mirror of
https://github.com/kavishdevar/librepods.git
synced 2026-02-24 18:03:35 +00:00
android: move navigation button to activity level
This commit is contained in:
@@ -38,11 +38,16 @@ import android.widget.Toast
|
|||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.core.RepeatMode
|
import androidx.compose.animation.core.RepeatMode
|
||||||
import androidx.compose.animation.core.animateFloat
|
import androidx.compose.animation.core.animateFloat
|
||||||
import androidx.compose.animation.core.infiniteRepeatable
|
import androidx.compose.animation.core.infiniteRepeatable
|
||||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
import androidx.compose.animation.core.rememberInfiniteTransition
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.scaleIn
|
||||||
|
import androidx.compose.animation.scaleOut
|
||||||
import androidx.compose.animation.slideInHorizontally
|
import androidx.compose.animation.slideInHorizontally
|
||||||
import androidx.compose.animation.slideOutHorizontally
|
import androidx.compose.animation.slideOutHorizontally
|
||||||
import androidx.compose.foundation.Canvas
|
import androidx.compose.foundation.Canvas
|
||||||
@@ -69,9 +74,11 @@ import androidx.compose.material3.Card
|
|||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@@ -104,8 +111,11 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
|||||||
import com.google.accompanist.permissions.MultiplePermissionsState
|
import com.google.accompanist.permissions.MultiplePermissionsState
|
||||||
import com.google.accompanist.permissions.isGranted
|
import com.google.accompanist.permissions.isGranted
|
||||||
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
import com.google.accompanist.permissions.rememberMultiplePermissionsState
|
||||||
|
import com.kyant.backdrop.backdrops.rememberLayerBackdrop
|
||||||
|
import com.kyant.backdrop.backdrops.layerBackdrop
|
||||||
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
|
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
|
||||||
import me.kavishdevar.librepods.constants.AirPodsNotifications
|
import me.kavishdevar.librepods.constants.AirPodsNotifications
|
||||||
|
import me.kavishdevar.librepods.composables.StyledIconButton
|
||||||
import me.kavishdevar.librepods.screens.AccessibilitySettingsScreen
|
import me.kavishdevar.librepods.screens.AccessibilitySettingsScreen
|
||||||
import me.kavishdevar.librepods.screens.AdaptiveStrengthScreen
|
import me.kavishdevar.librepods.screens.AdaptiveStrengthScreen
|
||||||
import me.kavishdevar.librepods.screens.AirPodsSettingsScreen
|
import me.kavishdevar.librepods.screens.AirPodsSettingsScreen
|
||||||
@@ -301,107 +311,127 @@ fun Main() {
|
|||||||
|
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
|
|
||||||
val sharedPreferences = context.getSharedPreferences("settings", MODE_PRIVATE)
|
|
||||||
val isAvailableChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
|
||||||
if (key == "CrossDeviceIsAvailable") {
|
|
||||||
Log.d("MainActivity", "CrossDeviceIsAvailable changed")
|
|
||||||
isRemotelyConnected.value = sharedPreferences.getBoolean("CrossDeviceIsAvailable", false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sharedPreferences.registerOnSharedPreferenceChangeListener(isAvailableChangeListener)
|
|
||||||
Log.d("MainActivity", "CrossDeviceIsAvailable: ${sharedPreferences.getBoolean("CrossDeviceIsAvailable", false)} | isAvailable: ${CrossDevice.isAvailable}")
|
|
||||||
isRemotelyConnected.value = sharedPreferences.getBoolean("CrossDeviceIsAvailable", false) || CrossDevice.isAvailable
|
|
||||||
Log.d("MainActivity", "isRemotelyConnected: ${isRemotelyConnected.value}")
|
|
||||||
Box (
|
Box (
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(0.dp)
|
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(if (isSystemInDarkTheme()) Color.Black else Color(0xFFF2F2F7))
|
){
|
||||||
) {
|
val backButtonBackdrop = rememberLayerBackdrop()
|
||||||
NavHost(
|
Box (
|
||||||
navController = navController,
|
modifier = Modifier
|
||||||
startDestination = if (hookAvailable) "settings" else "onboarding",
|
.fillMaxSize()
|
||||||
enterTransition = {
|
.background(if (isSystemInDarkTheme()) Color.Black else Color(0xFFF2F2F7))
|
||||||
slideInHorizontally(
|
.layerBackdrop(backButtonBackdrop)
|
||||||
initialOffsetX = { it },
|
|
||||||
animationSpec = tween(durationMillis = 300)
|
|
||||||
) // + fadeIn(animationSpec = tween(durationMillis = 300))
|
|
||||||
},
|
|
||||||
exitTransition = {
|
|
||||||
slideOutHorizontally(
|
|
||||||
targetOffsetX = { -it/4 },
|
|
||||||
animationSpec = tween(durationMillis = 300)
|
|
||||||
) // + fadeOut(animationSpec = tween(durationMillis = 150))
|
|
||||||
},
|
|
||||||
popEnterTransition = {
|
|
||||||
slideInHorizontally(
|
|
||||||
initialOffsetX = { -it/4 },
|
|
||||||
animationSpec = tween(durationMillis = 300)
|
|
||||||
) // + fadeIn(animationSpec = tween(durationMillis = 300))
|
|
||||||
},
|
|
||||||
popExitTransition = {
|
|
||||||
slideOutHorizontally(
|
|
||||||
targetOffsetX = { it },
|
|
||||||
animationSpec = tween(durationMillis = 300)
|
|
||||||
) // + fadeOut(animationSpec = tween(durationMillis = 150))
|
|
||||||
}
|
|
||||||
) {
|
) {
|
||||||
composable("settings") {
|
NavHost(
|
||||||
if (airPodsService.value != null) {
|
navController = navController,
|
||||||
AirPodsSettingsScreen(
|
startDestination = if (hookAvailable) "settings" else "onboarding",
|
||||||
dev = airPodsService.value?.device,
|
enterTransition = {
|
||||||
service = airPodsService.value!!,
|
slideInHorizontally(
|
||||||
|
initialOffsetX = { it },
|
||||||
|
animationSpec = tween(durationMillis = 300)
|
||||||
|
) // + fadeIn(animationSpec = tween(durationMillis = 300))
|
||||||
|
},
|
||||||
|
exitTransition = {
|
||||||
|
slideOutHorizontally(
|
||||||
|
targetOffsetX = { -it/4 },
|
||||||
|
animationSpec = tween(durationMillis = 300)
|
||||||
|
) // + fadeOut(animationSpec = tween(durationMillis = 150))
|
||||||
|
},
|
||||||
|
popEnterTransition = {
|
||||||
|
slideInHorizontally(
|
||||||
|
initialOffsetX = { -it/4 },
|
||||||
|
animationSpec = tween(durationMillis = 300)
|
||||||
|
) // + fadeIn(animationSpec = tween(durationMillis = 300))
|
||||||
|
},
|
||||||
|
popExitTransition = {
|
||||||
|
slideOutHorizontally(
|
||||||
|
targetOffsetX = { it },
|
||||||
|
animationSpec = tween(durationMillis = 300)
|
||||||
|
) // + fadeOut(animationSpec = tween(durationMillis = 150))
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
composable("settings") {
|
||||||
|
if (airPodsService.value != null) {
|
||||||
|
AirPodsSettingsScreen(
|
||||||
|
dev = airPodsService.value?.device,
|
||||||
|
service = airPodsService.value!!,
|
||||||
|
navController = navController,
|
||||||
|
isConnected = isConnected.value,
|
||||||
|
isRemotelyConnected = isRemotelyConnected.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
composable("debug") {
|
||||||
|
DebugScreen(navController = navController)
|
||||||
|
}
|
||||||
|
composable("long_press/{bud}") { navBackStackEntry ->
|
||||||
|
LongPress(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
isConnected = isConnected.value,
|
name = navBackStackEntry.arguments?.getString("bud")!!
|
||||||
isRemotelyConnected = isRemotelyConnected.value
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
composable("rename") {
|
||||||
|
RenameScreen(navController)
|
||||||
|
}
|
||||||
|
composable("app_settings") {
|
||||||
|
AppSettingsScreen(navController)
|
||||||
|
}
|
||||||
|
composable("troubleshooting") {
|
||||||
|
TroubleshootingScreen(navController)
|
||||||
|
}
|
||||||
|
composable("head_tracking") {
|
||||||
|
HeadTrackingScreen(navController)
|
||||||
|
}
|
||||||
|
composable("onboarding") {
|
||||||
|
Onboarding(navController, context)
|
||||||
|
}
|
||||||
|
composable("accessibility") {
|
||||||
|
AccessibilitySettingsScreen(navController)
|
||||||
|
}
|
||||||
|
composable("transparency_customization") {
|
||||||
|
TransparencySettingsScreen(navController)
|
||||||
|
}
|
||||||
|
composable("hearing_aid") {
|
||||||
|
HearingAidScreen(navController)
|
||||||
|
}
|
||||||
|
composable("hearing_aid_adjustments") {
|
||||||
|
HearingAidAdjustmentsScreen(navController)
|
||||||
|
}
|
||||||
|
composable("adaptive_strength") {
|
||||||
|
AdaptiveStrengthScreen(navController)
|
||||||
|
}
|
||||||
|
composable("camera_control") {
|
||||||
|
CameraControlScreen(navController)
|
||||||
|
}
|
||||||
|
composable("open_source_licenses") {
|
||||||
|
OpenSourceLicensesScreen(navController)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
composable("debug") {
|
}
|
||||||
DebugScreen(navController = navController)
|
|
||||||
|
val showBackButton = remember{ mutableStateOf(false) }
|
||||||
|
|
||||||
|
LaunchedEffect(navController) {
|
||||||
|
navController.addOnDestinationChangedListener { _, destination, _ ->
|
||||||
|
showBackButton.value = destination.route != "settings" && destination.route != "onboarding"
|
||||||
|
Log.d("MainActivity", "Navigated to ${destination.route}, showBackButton: ${showBackButton.value}")
|
||||||
}
|
}
|
||||||
composable("long_press/{bud}") { navBackStackEntry ->
|
}
|
||||||
LongPress(
|
|
||||||
navController = navController,
|
AnimatedVisibility(
|
||||||
name = navBackStackEntry.arguments?.getString("bud")!!
|
visible = showBackButton.value,
|
||||||
|
enter = fadeIn(animationSpec = tween()) + scaleIn(initialScale = 0f, animationSpec = tween()),
|
||||||
|
exit = fadeOut(animationSpec = tween()) + scaleOut(targetScale = 0.5f, animationSpec = tween(100)),
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.TopStart)
|
||||||
|
.padding(start = 8.dp, top = (context.resources.configuration.screenHeightDp.dp * 0.05f).value.dp)
|
||||||
|
) {
|
||||||
|
StyledIconButton(
|
||||||
|
onClick = { navController.popBackStack() },
|
||||||
|
icon = "",
|
||||||
|
darkMode = isSystemInDarkTheme(),
|
||||||
|
backdrop = backButtonBackdrop
|
||||||
)
|
)
|
||||||
}
|
|
||||||
composable("rename") {
|
|
||||||
RenameScreen(navController)
|
|
||||||
}
|
|
||||||
composable("app_settings") {
|
|
||||||
AppSettingsScreen(navController)
|
|
||||||
}
|
|
||||||
composable("troubleshooting") {
|
|
||||||
TroubleshootingScreen(navController)
|
|
||||||
}
|
|
||||||
composable("head_tracking") {
|
|
||||||
HeadTrackingScreen(navController)
|
|
||||||
}
|
|
||||||
composable("onboarding") {
|
|
||||||
Onboarding(navController, context)
|
|
||||||
}
|
|
||||||
composable("accessibility") {
|
|
||||||
AccessibilitySettingsScreen(navController)
|
|
||||||
}
|
|
||||||
composable("transparency_customization") {
|
|
||||||
TransparencySettingsScreen(navController)
|
|
||||||
}
|
|
||||||
composable("hearing_aid") {
|
|
||||||
HearingAidScreen(navController)
|
|
||||||
}
|
|
||||||
composable("hearing_aid_adjustments") {
|
|
||||||
HearingAidAdjustmentsScreen(navController)
|
|
||||||
}
|
|
||||||
composable("adaptive_strength") {
|
|
||||||
AdaptiveStrengthScreen(navController)
|
|
||||||
}
|
|
||||||
composable("camera_control") {
|
|
||||||
CameraControlScreen(navController)
|
|
||||||
}
|
|
||||||
composable("open_source_licenses") {
|
|
||||||
OpenSourceLicensesScreen(navController)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,8 +127,8 @@ half4 main(float2 coord) {
|
|||||||
highlight = { Highlight.Ambient.copy(alpha = if (isDarkTheme) 1f else 0f) },
|
highlight = { Highlight.Ambient.copy(alpha = if (isDarkTheme) 1f else 0f) },
|
||||||
shadow = {
|
shadow = {
|
||||||
Shadow(
|
Shadow(
|
||||||
radius = 48f.dp,
|
radius = 12f.dp,
|
||||||
color = Color.Black.copy(if (isDarkTheme) 0.08f else 0.4f)
|
color = Color.Black.copy(if (isDarkTheme) 0.08f else 0.2f)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
layerBlock = {
|
layerBlock = {
|
||||||
@@ -136,8 +136,7 @@ half4 main(float2 coord) {
|
|||||||
val height = size.height
|
val height = size.height
|
||||||
|
|
||||||
val progress = progressAnimation.value
|
val progress = progressAnimation.value
|
||||||
val maxScale = 0.1f
|
val scale = lerp(1f, 1.5f, progress)
|
||||||
val scale = lerp(1f, 1f + maxScale, progress)
|
|
||||||
|
|
||||||
val maxOffset = size.minDimension
|
val maxOffset = size.minDimension
|
||||||
val initialDerivative = 0.05f
|
val initialDerivative = 0.05f
|
||||||
@@ -220,7 +219,7 @@ half4 main(float2 coord) {
|
|||||||
},
|
},
|
||||||
effects = {
|
effects = {
|
||||||
refractionWithDispersion(6f.dp.toPx(), size.height / 2f)
|
refractionWithDispersion(6f.dp.toPx(), size.height / 2f)
|
||||||
blur(24f, TileMode.Decal)
|
// blur(24f, TileMode.Decal)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.pointerInput(animationScope) {
|
.pointerInput(animationScope) {
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.draw.shadow
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
@@ -48,6 +49,10 @@ import androidx.compose.ui.unit.Dp
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import com.kyant.backdrop.backdrops.LayerBackdrop
|
||||||
|
import com.kyant.backdrop.backdrops.layerBackdrop
|
||||||
|
import com.kyant.backdrop.backdrops.rememberLayerBackdrop
|
||||||
import dev.chrisbanes.haze.HazeProgressive
|
import dev.chrisbanes.haze.HazeProgressive
|
||||||
import dev.chrisbanes.haze.HazeState
|
import dev.chrisbanes.haze.HazeState
|
||||||
import dev.chrisbanes.haze.HazeTint
|
import dev.chrisbanes.haze.HazeTint
|
||||||
@@ -60,8 +65,7 @@ import me.kavishdevar.librepods.R
|
|||||||
@Composable
|
@Composable
|
||||||
fun StyledScaffold(
|
fun StyledScaffold(
|
||||||
title: String,
|
title: String,
|
||||||
navigationButton: @Composable () -> Unit = {},
|
actionButtons: List<@Composable (backdrop: LayerBackdrop) -> Unit> = emptyList(),
|
||||||
actionButtons: List<@Composable () -> Unit> = emptyList(),
|
|
||||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||||
content: @Composable (spacerValue: Dp, hazeState: HazeState) -> Unit
|
content: @Composable (spacerValue: Dp, hazeState: HazeState) -> Unit
|
||||||
) {
|
) {
|
||||||
@@ -72,6 +76,7 @@ fun StyledScaffold(
|
|||||||
containerColor = if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7),
|
containerColor = if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7),
|
||||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.then(if (!isDarkTheme) Modifier.shadow(elevation = 36.dp, shape = RoundedCornerShape(52.dp), ambientColor = Color.Black, spotColor = Color.Black) else Modifier)
|
||||||
.clip(RoundedCornerShape(52.dp))
|
.clip(RoundedCornerShape(52.dp))
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
val topPadding = paddingValues.calculateTopPadding()
|
val topPadding = paddingValues.calculateTopPadding()
|
||||||
@@ -84,23 +89,21 @@ fun StyledScaffold(
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(start = startPadding, end = endPadding, bottom = bottomPadding)
|
.padding(start = startPadding, end = endPadding, bottom = bottomPadding)
|
||||||
) {
|
) {
|
||||||
|
val backdrop = rememberLayerBackdrop()
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.zIndex(2f)
|
.zIndex(2f)
|
||||||
.height(64.dp + topPadding)
|
.height(64.dp + topPadding)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
.layerBackdrop(backdrop)
|
||||||
.hazeEffect(state = hazeState) {
|
.hazeEffect(state = hazeState) {
|
||||||
tints = listOf(HazeTint(color = if (isDarkTheme) Color.Black else Color.White))
|
tints = listOf(HazeTint(color = if (isDarkTheme) Color.Black else Color.White))
|
||||||
progressive = HazeProgressive.verticalGradient(startIntensity = 1f, endIntensity = 0f)
|
progressive = HazeProgressive.verticalGradient(startIntensity = 1f, endIntensity = 0f)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.fillMaxSize()) {
|
Column(modifier = Modifier.fillMaxSize()) {
|
||||||
Spacer(modifier = Modifier.height(topPadding))
|
Spacer(modifier = Modifier.height(topPadding + 12.dp))
|
||||||
Box(
|
Text(
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
navigationButton()
|
|
||||||
Text(
|
|
||||||
text = title,
|
text = title,
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontSize = 20.sp,
|
fontSize = 20.sp,
|
||||||
@@ -108,15 +111,19 @@ fun StyledScaffold(
|
|||||||
color = if (isDarkTheme) Color.White else Color.Black,
|
color = if (isDarkTheme) Color.White else Color.Black,
|
||||||
fontFamily = FontFamily(Font(R.font.sf_pro))
|
fontFamily = FontFamily(Font(R.font.sf_pro))
|
||||||
),
|
),
|
||||||
modifier = Modifier.align(Alignment.Center),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
textAlign = TextAlign.Center
|
textAlign = TextAlign.Center
|
||||||
)
|
)
|
||||||
Row(
|
}
|
||||||
modifier = Modifier.align(Alignment.CenterEnd)
|
}
|
||||||
) {
|
Row(
|
||||||
actionButtons.forEach { it() }
|
modifier = Modifier
|
||||||
}
|
.zIndex(3f)
|
||||||
}
|
.padding(top = topPadding, end = 8.dp)
|
||||||
|
.align(Alignment.TopEnd)
|
||||||
|
) {
|
||||||
|
actionButtons.forEach { actionButton ->
|
||||||
|
actionButton(backdrop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,16 +137,14 @@ fun StyledScaffold(
|
|||||||
@Composable
|
@Composable
|
||||||
fun StyledScaffold(
|
fun StyledScaffold(
|
||||||
title: String,
|
title: String,
|
||||||
navigationButton: @Composable () -> Unit = {},
|
actionButtons: List<@Composable (backdrop: LayerBackdrop) -> Unit> = emptyList(),
|
||||||
actionButtons: List<@Composable () -> Unit> = emptyList(),
|
|
||||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = title,
|
title = title,
|
||||||
navigationButton = navigationButton,
|
|
||||||
actionButtons = actionButtons,
|
actionButtons = actionButtons,
|
||||||
snackbarHostState = snackbarHostState
|
snackbarHostState = snackbarHostState,
|
||||||
) { _, _ ->
|
) { _, _ ->
|
||||||
content()
|
content()
|
||||||
}
|
}
|
||||||
@@ -149,16 +154,14 @@ fun StyledScaffold(
|
|||||||
@Composable
|
@Composable
|
||||||
fun StyledScaffold(
|
fun StyledScaffold(
|
||||||
title: String,
|
title: String,
|
||||||
navigationButton: @Composable () -> Unit = {},
|
actionButtons: List<@Composable (backdrop: LayerBackdrop) -> Unit> = emptyList(),
|
||||||
actionButtons: List<@Composable () -> Unit> = emptyList(),
|
|
||||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
|
||||||
content: @Composable (spacerValue: Dp) -> Unit
|
content: @Composable (spacerValue: Dp) -> Unit
|
||||||
) {
|
) {
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = title,
|
title = title,
|
||||||
navigationButton = navigationButton,
|
|
||||||
actionButtons = actionButtons,
|
actionButtons = actionButtons,
|
||||||
snackbarHostState = snackbarHostState
|
snackbarHostState = snackbarHostState,
|
||||||
) { spacerValue, _ ->
|
) { spacerValue, _ ->
|
||||||
content(spacerValue)
|
content(spacerValue)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,17 +106,27 @@ fun StyledSwitch(
|
|||||||
compositingStrategy = CompositingStrategy.Offscreen
|
compositingStrategy = CompositingStrategy.Offscreen
|
||||||
}
|
}
|
||||||
val animatedTrackColor = remember { Animatable(if (checked) onColor else offColor) }
|
val animatedTrackColor = remember { Animatable(if (checked) onColor else offColor) }
|
||||||
|
val totalDrag = remember { mutableFloatStateOf(0f) }
|
||||||
|
val tapThreshold = 10f
|
||||||
|
val isFirstComposition = remember { mutableStateOf(true) }
|
||||||
LaunchedEffect(checked) {
|
LaunchedEffect(checked) {
|
||||||
coroutineScope {
|
if (!isFirstComposition.value) {
|
||||||
launch {
|
coroutineScope {
|
||||||
val targetColor = if (checked) onColor else offColor
|
launch {
|
||||||
animatedTrackColor.animateTo(targetColor, colorAnimationSpec)
|
val targetColor = if (checked) onColor else offColor
|
||||||
}
|
animatedTrackColor.animateTo(targetColor, colorAnimationSpec)
|
||||||
launch {
|
}
|
||||||
val targetFrac = if (checked) 1f else 0f
|
launch {
|
||||||
animatedFraction.animateTo(targetFrac, progressAnimationSpec)
|
val targetFrac = if (checked) 1f else 0f
|
||||||
|
animatedFraction.animateTo(targetFrac, progressAnimationSpec)
|
||||||
|
}
|
||||||
|
launch {
|
||||||
|
progressAnimation.animateTo(1f, tween(100, easing = FastOutSlowInEasing))
|
||||||
|
progressAnimation.animateTo(0f, tween(100, easing = FastOutSlowInEasing))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
isFirstComposition.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
@@ -147,6 +157,7 @@ fun StyledSwitch(
|
|||||||
animationScope.launch {
|
animationScope.launch {
|
||||||
animatedFraction.snapTo(newFraction)
|
animatedFraction.snapTo(newFraction)
|
||||||
}
|
}
|
||||||
|
totalDrag.floatValue += kotlin.math.abs(delta)
|
||||||
val newChecked = newFraction >= 0.5f
|
val newChecked = newFraction >= 0.5f
|
||||||
if (newChecked != checked) {
|
if (newChecked != checked) {
|
||||||
onCheckedChange(newChecked)
|
onCheckedChange(newChecked)
|
||||||
@@ -156,17 +167,28 @@ fun StyledSwitch(
|
|||||||
Orientation.Horizontal,
|
Orientation.Horizontal,
|
||||||
startDragImmediately = true,
|
startDragImmediately = true,
|
||||||
onDragStarted = {
|
onDragStarted = {
|
||||||
|
totalDrag.floatValue = 0f
|
||||||
animationScope.launch {
|
animationScope.launch {
|
||||||
progressAnimation.animateTo(1f, progressAnimationSpec)
|
progressAnimation.animateTo(1f, progressAnimationSpec)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onDragStopped = {
|
onDragStopped = {
|
||||||
animationScope.launch {
|
animationScope.launch {
|
||||||
val snappedFraction = if (animatedFraction.value >= 0.5f) 1f else 0f
|
if (totalDrag.floatValue < tapThreshold) {
|
||||||
onCheckedChange(snappedFraction >= 0.5f)
|
val newChecked = !checked
|
||||||
coroutineScope {
|
onCheckedChange(newChecked)
|
||||||
launch { progressAnimation.animateTo(0f, progressAnimationSpec) }
|
val snappedFraction = if (newChecked) 1f else 0f
|
||||||
launch { animatedFraction.animateTo(snappedFraction, progressAnimationSpec) }
|
coroutineScope {
|
||||||
|
launch { progressAnimation.animateTo(0f, progressAnimationSpec) }
|
||||||
|
launch { animatedFraction.animateTo(snappedFraction, progressAnimationSpec) }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val snappedFraction = if (animatedFraction.value >= 0.5f) 1f else 0f
|
||||||
|
onCheckedChange(snappedFraction >= 0.5f)
|
||||||
|
coroutineScope {
|
||||||
|
launch { progressAnimation.animateTo(0f, progressAnimationSpec) }
|
||||||
|
launch { animatedFraction.animateTo(snappedFraction, progressAnimationSpec) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,15 +150,7 @@ fun AccessibilitySettingsScreen(navController: NavController) {
|
|||||||
val backdrop = rememberLayerBackdrop()
|
val backdrop = rememberLayerBackdrop()
|
||||||
|
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = stringResource(R.string.accessibility),
|
title = stringResource(R.string.accessibility)
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) { spacerHeight, hazeState ->
|
) { spacerHeight, hazeState ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -99,15 +99,7 @@ fun AdaptiveStrengthScreen(navController: NavController) {
|
|||||||
val backdrop = rememberLayerBackdrop()
|
val backdrop = rememberLayerBackdrop()
|
||||||
|
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = stringResource(R.string.customize_adaptive_audio),
|
title = stringResource(R.string.customize_adaptive_audio)
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
) { spacerHeight ->
|
) { spacerHeight ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -200,14 +200,16 @@ fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
|
|||||||
val backdrop = rememberLayerBackdrop()
|
val backdrop = rememberLayerBackdrop()
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = deviceName.text,
|
title = deviceName.text,
|
||||||
actionButtons = listOf {
|
actionButtons = listOf(
|
||||||
StyledIconButton(
|
{scaffoldBackdrop ->
|
||||||
onClick = { navController.navigate("app_settings") },
|
StyledIconButton(
|
||||||
icon = "",
|
onClick = { navController.navigate("app_settings") },
|
||||||
darkMode = darkMode,
|
icon = "",
|
||||||
backdrop = backdrop
|
darkMode = darkMode,
|
||||||
)
|
backdrop = scaffoldBackdrop
|
||||||
},
|
)
|
||||||
|
}
|
||||||
|
),
|
||||||
snackbarHostState = snackbarHostState
|
snackbarHostState = snackbarHostState
|
||||||
) { spacerHeight, hazeState ->
|
) { spacerHeight, hazeState ->
|
||||||
if (isLocallyConnected || isRemotelyConnected) {
|
if (isLocallyConnected || isRemotelyConnected) {
|
||||||
|
|||||||
@@ -193,15 +193,7 @@ fun AppSettingsScreen(navController: NavController) {
|
|||||||
val backdrop = rememberLayerBackdrop()
|
val backdrop = rememberLayerBackdrop()
|
||||||
|
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = stringResource(R.string.app_settings),
|
title = stringResource(R.string.app_settings)
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
) { spacerHeight, hazeState ->
|
) { spacerHeight, hazeState ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -130,15 +130,7 @@ fun CameraControlScreen(navController: NavController) {
|
|||||||
val backdrop = rememberLayerBackdrop()
|
val backdrop = rememberLayerBackdrop()
|
||||||
|
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = stringResource(R.string.camera_control),
|
title = stringResource(R.string.camera_control)
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
) { spacerHeight ->
|
) { spacerHeight ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -327,16 +327,8 @@ fun DebugScreen(navController: NavController) {
|
|||||||
val backdrop = rememberLayerBackdrop()
|
val backdrop = rememberLayerBackdrop()
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = "Debug",
|
title = "Debug",
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
},
|
|
||||||
actionButtons = listOf(
|
actionButtons = listOf(
|
||||||
{
|
{scaffoldBackdrop ->
|
||||||
StyledIconButton(
|
StyledIconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
airPodsService?.clearLogs()
|
airPodsService?.clearLogs()
|
||||||
@@ -344,7 +336,7 @@ fun DebugScreen(navController: NavController) {
|
|||||||
},
|
},
|
||||||
icon = "",
|
icon = "",
|
||||||
darkMode = isDarkTheme,
|
darkMode = isDarkTheme,
|
||||||
backdrop = backdrop
|
backdrop = scaffoldBackdrop
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -121,18 +121,10 @@ fun HeadTrackingScreen(navController: NavController) {
|
|||||||
|
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
val backdrop = rememberLayerBackdrop()
|
val backdrop = rememberLayerBackdrop()
|
||||||
StyledScaffold (
|
StyledScaffold(
|
||||||
title = stringResource(R.string.head_tracking),
|
title = stringResource(R.string.head_tracking),
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
},
|
|
||||||
actionButtons = listOf(
|
actionButtons = listOf(
|
||||||
{
|
{ scaffoldBackdrop ->
|
||||||
var isActive by remember { mutableStateOf(ServiceManager.getService()?.isHeadTrackingActive == true) }
|
var isActive by remember { mutableStateOf(ServiceManager.getService()?.isHeadTrackingActive == true) }
|
||||||
StyledIconButton(
|
StyledIconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
@@ -146,7 +138,7 @@ fun HeadTrackingScreen(navController: NavController) {
|
|||||||
},
|
},
|
||||||
icon = if (isActive) "" else "",
|
icon = if (isActive) "" else "",
|
||||||
darkMode = isDarkTheme,
|
darkMode = isDarkTheme,
|
||||||
backdrop = backdrop
|
backdrop = scaffoldBackdrop
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -81,15 +81,7 @@ fun HearingAidAdjustmentsScreen(@Suppress("unused") navController: NavController
|
|||||||
val aacpManager = remember { ServiceManager.getService()?.aacpManager }
|
val aacpManager = remember { ServiceManager.getService()?.aacpManager }
|
||||||
val backdrop = rememberLayerBackdrop()
|
val backdrop = rememberLayerBackdrop()
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = stringResource(R.string.adjustments),
|
title = stringResource(R.string.adjustments)
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
) { spacerHeight ->
|
) { spacerHeight ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -101,15 +101,6 @@ fun HearingAidScreen(navController: NavController) {
|
|||||||
|
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = stringResource(R.string.hearing_aid),
|
title = stringResource(R.string.hearing_aid),
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
},
|
|
||||||
actionButtons = emptyList(),
|
|
||||||
snackbarHostState = snackbarHostState,
|
snackbarHostState = snackbarHostState,
|
||||||
) { spacerHeight ->
|
) { spacerHeight ->
|
||||||
Column(
|
Column(
|
||||||
|
|||||||
@@ -157,14 +157,14 @@ fun Onboarding(navController: NavController, activityContext: Context) {
|
|||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = "Setting Up",
|
title = "Setting Up",
|
||||||
actionButtons = listOf(
|
actionButtons = listOf(
|
||||||
{
|
{scaffoldBackdrop ->
|
||||||
StyledIconButton(
|
StyledIconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
showSkipDialog = true
|
showSkipDialog = true
|
||||||
},
|
},
|
||||||
icon = "",
|
icon = "",
|
||||||
darkMode = isDarkTheme,
|
darkMode = isDarkTheme,
|
||||||
backdrop = backdrop
|
backdrop = scaffoldBackdrop
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -66,15 +66,7 @@ fun OpenSourceLicensesScreen(navController: NavController) {
|
|||||||
val backdrop = rememberLayerBackdrop()
|
val backdrop = rememberLayerBackdrop()
|
||||||
|
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = stringResource(R.string.open_source_licenses),
|
title = stringResource(R.string.open_source_licenses)
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
) { spacerHeight ->
|
) { spacerHeight ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -122,15 +122,7 @@ fun LongPress(navController: NavController, name: String) {
|
|||||||
var longPressAction by remember { mutableStateOf(StemAction.valueOf(longPressActionPref ?: StemAction.CYCLE_NOISE_CONTROL_MODES.name)) }
|
var longPressAction by remember { mutableStateOf(StemAction.valueOf(longPressActionPref ?: StemAction.CYCLE_NOISE_CONTROL_MODES.name)) }
|
||||||
val backdrop = rememberLayerBackdrop()
|
val backdrop = rememberLayerBackdrop()
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = name,
|
title = name
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
) { spacerHeight ->
|
) { spacerHeight ->
|
||||||
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
|
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
|
||||||
Column (
|
Column (
|
||||||
|
|||||||
@@ -87,14 +87,6 @@ fun RenameScreen(navController: NavController) {
|
|||||||
|
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = stringResource(R.string.name),
|
title = stringResource(R.string.name),
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) { spacerHeight ->
|
) { spacerHeight ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -100,15 +100,7 @@ fun TransparencySettingsScreen(navController: NavController) {
|
|||||||
val backdrop = rememberLayerBackdrop()
|
val backdrop = rememberLayerBackdrop()
|
||||||
|
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = stringResource(R.string.customize_transparency_mode),
|
title = stringResource(R.string.customize_transparency_mode)
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
){ spacerHeight, hazeState ->
|
){ spacerHeight, hazeState ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -216,15 +216,7 @@ fun TroubleshootingScreen(navController: NavController) {
|
|||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
StyledScaffold(
|
StyledScaffold(
|
||||||
title = stringResource(R.string.troubleshooting),
|
title = stringResource(R.string.troubleshooting)
|
||||||
navigationButton = {
|
|
||||||
StyledIconButton(
|
|
||||||
onClick = { navController.popBackStack() },
|
|
||||||
icon = "",
|
|
||||||
darkMode = isDarkTheme,
|
|
||||||
backdrop = backdrop
|
|
||||||
)
|
|
||||||
}
|
|
||||||
){ spacerHeight, hazeState ->
|
){ spacerHeight, hazeState ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
Reference in New Issue
Block a user