@@ -38,11 +38,16 @@ import android.widget.Toast
3838import androidx.activity.ComponentActivity
3939import androidx.activity.compose.setContent
4040import androidx.activity.enableEdgeToEdge
41+ import androidx.compose.animation.AnimatedVisibility
4142import androidx.compose.animation.core.RepeatMode
4243import androidx.compose.animation.core.animateFloat
4344import androidx.compose.animation.core.infiniteRepeatable
4445import androidx.compose.animation.core.rememberInfiniteTransition
4546import androidx.compose.animation.core.tween
47+ import androidx.compose.animation.fadeIn
48+ import androidx.compose.animation.fadeOut
49+ import androidx.compose.animation.scaleIn
50+ import androidx.compose.animation.scaleOut
4651import androidx.compose.animation.slideInHorizontally
4752import androidx.compose.animation.slideOutHorizontally
4853import androidx.compose.foundation.Canvas
@@ -69,9 +74,11 @@ import androidx.compose.material3.Card
6974import androidx.compose.material3.CardDefaults
7075import androidx.compose.material3.ExperimentalMaterial3Api
7176import androidx.compose.material3.Icon
77+ import androidx.compose.material3.IconButton
7278import androidx.compose.material3.MaterialTheme
7379import androidx.compose.material3.Text
7480import androidx.compose.runtime.Composable
81+ import androidx.compose.runtime.derivedStateOf
7582import androidx.compose.runtime.LaunchedEffect
7683import androidx.compose.runtime.getValue
7784import androidx.compose.runtime.mutableStateOf
@@ -104,8 +111,11 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi
104111import com.google.accompanist.permissions.MultiplePermissionsState
105112import com.google.accompanist.permissions.isGranted
106113import com.google.accompanist.permissions.rememberMultiplePermissionsState
114+ import com.kyant.backdrop.backdrops.rememberLayerBackdrop
115+ import com.kyant.backdrop.backdrops.layerBackdrop
107116import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
108117import me.kavishdevar.librepods.constants.AirPodsNotifications
118+ import me.kavishdevar.librepods.composables.StyledIconButton
109119import me.kavishdevar.librepods.screens.AccessibilitySettingsScreen
110120import me.kavishdevar.librepods.screens.AdaptiveStrengthScreen
111121import me.kavishdevar.librepods.screens.AirPodsSettingsScreen
@@ -300,108 +310,128 @@ fun Main() {
300310 val context = LocalContext .current
301311
302312 val navController = rememberNavController()
303-
304- val sharedPreferences = context.getSharedPreferences(" settings" , MODE_PRIVATE )
305- val isAvailableChangeListener = SharedPreferences .OnSharedPreferenceChangeListener { _, key ->
306- if (key == " CrossDeviceIsAvailable" ) {
307- Log .d(" MainActivity" , " CrossDeviceIsAvailable changed" )
308- isRemotelyConnected.value = sharedPreferences.getBoolean(" CrossDeviceIsAvailable" , false )
309- }
310- }
311- sharedPreferences.registerOnSharedPreferenceChangeListener(isAvailableChangeListener)
312- Log .d(" MainActivity" , " CrossDeviceIsAvailable: ${sharedPreferences.getBoolean(" CrossDeviceIsAvailable" , false )} | isAvailable: ${CrossDevice .isAvailable} " )
313- isRemotelyConnected.value = sharedPreferences.getBoolean(" CrossDeviceIsAvailable" , false ) || CrossDevice .isAvailable
314- Log .d(" MainActivity" , " isRemotelyConnected: ${isRemotelyConnected.value} " )
313+
315314 Box (
316315 modifier = Modifier
317- .padding(0 .dp)
318316 .fillMaxSize()
319- .background(if (isSystemInDarkTheme()) Color .Black else Color (0xFFF2F2F7 ))
320- ) {
321- NavHost (
322- navController = navController,
323- startDestination = if (hookAvailable) " settings" else " onboarding" ,
324- enterTransition = {
325- slideInHorizontally(
326- initialOffsetX = { it },
327- animationSpec = tween(durationMillis = 300 )
328- ) // + fadeIn(animationSpec = tween(durationMillis = 300))
329- },
330- exitTransition = {
331- slideOutHorizontally(
332- targetOffsetX = { - it/ 4 },
333- animationSpec = tween(durationMillis = 300 )
334- ) // + fadeOut(animationSpec = tween(durationMillis = 150))
335- },
336- popEnterTransition = {
337- slideInHorizontally(
338- initialOffsetX = { - it/ 4 },
339- animationSpec = tween(durationMillis = 300 )
340- ) // + fadeIn(animationSpec = tween(durationMillis = 300))
341- },
342- popExitTransition = {
343- slideOutHorizontally(
344- targetOffsetX = { it },
345- animationSpec = tween(durationMillis = 300 )
346- ) // + fadeOut(animationSpec = tween(durationMillis = 150))
347- }
317+ ){
318+ val backButtonBackdrop = rememberLayerBackdrop()
319+ Box (
320+ modifier = Modifier
321+ .fillMaxSize()
322+ .background(if (isSystemInDarkTheme()) Color .Black else Color (0xFFF2F2F7 ))
323+ .layerBackdrop(backButtonBackdrop)
348324 ) {
349- composable(" settings" ) {
350- if (airPodsService.value != null ) {
351- AirPodsSettingsScreen (
352- dev = airPodsService.value?.device,
353- service = airPodsService.value!! ,
325+ NavHost (
326+ navController = navController,
327+ startDestination = if (hookAvailable) " settings" else " onboarding" ,
328+ enterTransition = {
329+ slideInHorizontally(
330+ initialOffsetX = { it },
331+ animationSpec = tween(durationMillis = 300 )
332+ ) // + fadeIn(animationSpec = tween(durationMillis = 300))
333+ },
334+ exitTransition = {
335+ slideOutHorizontally(
336+ targetOffsetX = { - it/ 4 },
337+ animationSpec = tween(durationMillis = 300 )
338+ ) // + fadeOut(animationSpec = tween(durationMillis = 150))
339+ },
340+ popEnterTransition = {
341+ slideInHorizontally(
342+ initialOffsetX = { - it/ 4 },
343+ animationSpec = tween(durationMillis = 300 )
344+ ) // + fadeIn(animationSpec = tween(durationMillis = 300))
345+ },
346+ popExitTransition = {
347+ slideOutHorizontally(
348+ targetOffsetX = { it },
349+ animationSpec = tween(durationMillis = 300 )
350+ ) // + fadeOut(animationSpec = tween(durationMillis = 150))
351+ }
352+ ) {
353+ composable(" settings" ) {
354+ if (airPodsService.value != null ) {
355+ AirPodsSettingsScreen (
356+ dev = airPodsService.value?.device,
357+ service = airPodsService.value!! ,
358+ navController = navController,
359+ isConnected = isConnected.value,
360+ isRemotelyConnected = isRemotelyConnected.value
361+ )
362+ }
363+ }
364+ composable(" debug" ) {
365+ DebugScreen (navController = navController)
366+ }
367+ composable(" long_press/{bud}" ) { navBackStackEntry ->
368+ LongPress (
354369 navController = navController,
355- isConnected = isConnected.value,
356- isRemotelyConnected = isRemotelyConnected.value
370+ name = navBackStackEntry.arguments?.getString(" bud" )!!
357371 )
358372 }
373+ composable(" rename" ) {
374+ RenameScreen (navController)
375+ }
376+ composable(" app_settings" ) {
377+ AppSettingsScreen (navController)
378+ }
379+ composable(" troubleshooting" ) {
380+ TroubleshootingScreen (navController)
381+ }
382+ composable(" head_tracking" ) {
383+ HeadTrackingScreen (navController)
384+ }
385+ composable(" onboarding" ) {
386+ Onboarding (navController, context)
387+ }
388+ composable(" accessibility" ) {
389+ AccessibilitySettingsScreen (navController)
390+ }
391+ composable(" transparency_customization" ) {
392+ TransparencySettingsScreen (navController)
393+ }
394+ composable(" hearing_aid" ) {
395+ HearingAidScreen (navController)
396+ }
397+ composable(" hearing_aid_adjustments" ) {
398+ HearingAidAdjustmentsScreen (navController)
399+ }
400+ composable(" adaptive_strength" ) {
401+ AdaptiveStrengthScreen (navController)
402+ }
403+ composable(" camera_control" ) {
404+ CameraControlScreen (navController)
405+ }
406+ composable(" open_source_licenses" ) {
407+ OpenSourceLicensesScreen (navController)
408+ }
359409 }
360- composable(" debug" ) {
361- DebugScreen (navController = navController)
410+ }
411+
412+ val showBackButton = remember{ mutableStateOf(false ) }
413+
414+ LaunchedEffect (navController) {
415+ navController.addOnDestinationChangedListener { _, destination, _ ->
416+ showBackButton.value = destination.route != " settings" && destination.route != " onboarding"
417+ Log .d(" MainActivity" , " Navigated to ${destination.route} , showBackButton: ${showBackButton.value} " )
362418 }
363- composable(" long_press/{bud}" ) { navBackStackEntry ->
364- LongPress (
365- navController = navController,
366- name = navBackStackEntry.arguments?.getString(" bud" )!!
419+ }
420+
421+ AnimatedVisibility (
422+ visible = showBackButton.value,
423+ enter = fadeIn(animationSpec = tween()) + scaleIn(initialScale = 0f , animationSpec = tween()),
424+ exit = fadeOut(animationSpec = tween()) + scaleOut(targetScale = 0.5f , animationSpec = tween(100 )),
425+ modifier = Modifier
426+ .align(Alignment .TopStart )
427+ .padding(start = 8 .dp, top = (context.resources.configuration.screenHeightDp.dp * 0.05f ).value.dp)
428+ ) {
429+ StyledIconButton (
430+ onClick = { navController.popBackStack() },
431+ icon = " " ,
432+ darkMode = isSystemInDarkTheme(),
433+ backdrop = backButtonBackdrop
367434 )
368- }
369- composable(" rename" ) {
370- RenameScreen (navController)
371- }
372- composable(" app_settings" ) {
373- AppSettingsScreen (navController)
374- }
375- composable(" troubleshooting" ) {
376- TroubleshootingScreen (navController)
377- }
378- composable(" head_tracking" ) {
379- HeadTrackingScreen (navController)
380- }
381- composable(" onboarding" ) {
382- Onboarding (navController, context)
383- }
384- composable(" accessibility" ) {
385- AccessibilitySettingsScreen (navController)
386- }
387- composable(" transparency_customization" ) {
388- TransparencySettingsScreen (navController)
389- }
390- composable(" hearing_aid" ) {
391- HearingAidScreen (navController)
392- }
393- composable(" hearing_aid_adjustments" ) {
394- HearingAidAdjustmentsScreen (navController)
395- }
396- composable(" adaptive_strength" ) {
397- AdaptiveStrengthScreen (navController)
398- }
399- composable(" camera_control" ) {
400- CameraControlScreen (navController)
401- }
402- composable(" open_source_licenses" ) {
403- OpenSourceLicensesScreen (navController)
404- }
405435 }
406436 }
407437
0 commit comments