package com.suno.android.feature_tweaks.staff import android.app.Application import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import com.suno.android.common_core_utils.ApplicationCoroutineScope import com.suno.android.common_core_utils.SunoLogger import com.suno.android.common_core_utils.helpers.AppLifecycleManager import com.suno.android.common_core_utils.helpers.SunoAppLifecycleEvent import com.suno.android.feature_tweaks.staff.ui.TweaksScreen import com.suno.android.feature_tweaks.staff.util.ShakeDetector import com.suno.android.framework.shakereport.ShakeReportManager import com.suno.feature_tweaks.TweaksEntryPoint import com.suno.feature_tweaks.TweaksNavDestination import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import javax.inject.Inject class StaffTweaksEntryPoint @Inject constructor( loggerFactory: SunoLogger.Factory, @ApplicationCoroutineScope private val applicationScope: CoroutineScope, private val appLifecycleManager: AppLifecycleManager, private val shakeDetector: ShakeDetector, private val shakeReportManager: ShakeReportManager, ) : TweaksEntryPoint { private val logger = loggerFactory.create(this@StaffTweaksEntryPoint) override val showTweaks: Boolean = true override fun tweaksDestination( navGraphBuilder: NavGraphBuilder, ) { navGraphBuilder.composable( route = TweaksNavDestination::class, ) { TweaksScreen() } } @OptIn(ExperimentalMaterial3Api::class) @Composable override fun TweaksBottomSheet() { val showTweaks by isTweaksBottomSheetOpen.collectAsStateWithLifecycle() if (showTweaks) { val sheetState = rememberModalBottomSheetState() LaunchedEffect(sheetState) { sheetState.show() } suspend fun closeTweaksSheet() { sheetState.hide() isTweaksBottomSheetOpen.value = false } val coroutineScope = rememberCoroutineScope() ModalBottomSheet( sheetState = sheetState, onDismissRequest = { coroutineScope.launch { closeTweaksSheet() } }, ) { TweaksScreen( onReportBugStarted = { closeTweaksSheet() }, ) } } } private val isTweaksBottomSheetOpen = MutableStateFlow(false) override fun init( application: Application, ) { // Initialize ShakeReportManager shakeReportManager.init(application) shakeReportManager.subscribeFlow().launchIn(applicationScope) // Start/stop shake detection based on app lifecycle appLifecycleManager.appProcessEventFlow() .onEach { sunoAppLifecycleEvent -> when (sunoAppLifecycleEvent) { is SunoAppLifecycleEvent.OnAppFirstLaunch, is SunoAppLifecycleEvent.OnAppForegrounded, -> { shakeDetector.start { isTweaksBottomSheetOpen.value = true } } SunoAppLifecycleEvent.OnAppBackgrounded -> { shakeDetector.stop() } else -> { // No action needed for other lifecycle events } } } .catch { exception -> logger.e(exception) } .launchIn(applicationScope) } }