RemoteOverlay.kt (4500B) - raw
1 package me.rhunk.snapenhance.ui.overlay 2 3 import android.app.Dialog 4 import android.content.Intent 5 import android.graphics.drawable.ColorDrawable 6 import android.net.Uri 7 import android.provider.Settings 8 import android.view.WindowManager 9 import androidx.compose.foundation.layout.Arrangement 10 import androidx.compose.foundation.layout.Column 11 import androidx.compose.foundation.layout.fillMaxSize 12 import androidx.compose.foundation.layout.padding 13 import androidx.compose.material3.MaterialTheme 14 import androidx.compose.material3.Scaffold 15 import androidx.compose.runtime.Composable 16 import androidx.compose.runtime.LaunchedEffect 17 import androidx.compose.runtime.remember 18 import androidx.compose.ui.Alignment 19 import androidx.compose.ui.Modifier 20 import androidx.compose.ui.draw.clip 21 import androidx.compose.ui.graphics.Color 22 import androidx.compose.ui.unit.dp 23 import androidx.navigation.compose.rememberNavController 24 import com.arthenica.ffmpegkit.Packages.getPackageName 25 import me.rhunk.snapenhance.R 26 import me.rhunk.snapenhance.RemoteSideContext 27 import me.rhunk.snapenhance.common.ui.createComposeView 28 import me.rhunk.snapenhance.ui.manager.Navigation 29 import me.rhunk.snapenhance.ui.manager.Routes 30 31 32 class RemoteOverlay( 33 private val context: RemoteSideContext 34 ) { 35 private lateinit var dialog: Dialog 36 private var dismissCallback: (() -> Boolean)? = null 37 38 private fun checkForPermissions(): Boolean { 39 if (!Settings.canDrawOverlays(context.androidContext)) { 40 val myIntent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION) 41 myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 42 myIntent.setData(Uri.parse("package:" + getPackageName())) 43 context.androidContext.startActivity(myIntent) 44 return false 45 } 46 return true 47 } 48 49 @Composable 50 private fun OverlayContent(startRoute: (Routes) -> Routes.Route) { 51 val navHostController = rememberNavController() 52 53 LaunchedEffect(Unit) { 54 dismissCallback = { navHostController.popBackStack() } 55 } 56 57 val navigation = remember { Navigation(context, navHostController) } 58 59 Scaffold( 60 containerColor = MaterialTheme.colorScheme.background, 61 topBar = { navigation.TopBar() } 62 ) { innerPadding -> 63 navigation.Content( 64 innerPadding, 65 startDestination = remember { startRoute(navigation.routes).routeInfo.id } 66 ) 67 } 68 } 69 70 fun close() { 71 if (!::dialog.isInitialized || !dialog.isShowing) return 72 dismissCallback = null 73 context.androidContext.mainExecutor.execute { 74 dialog.dismiss() 75 } 76 } 77 78 fun show(route: (Routes) -> Routes.Route) { 79 if (!checkForPermissions()) { 80 return 81 } 82 83 if (::dialog.isInitialized && dialog.isShowing) { 84 return 85 } 86 87 context.androidContext.mainExecutor.execute { 88 dialog = object: Dialog(context.androidContext, R.style.FullscreenOverlayDialog) { 89 override fun dismiss() { 90 dismissCallback?.also { 91 if (it()) return 92 } 93 super.dismiss() 94 this@RemoteOverlay.context.config.writeConfig() 95 } 96 } 97 dialog.window?.apply { 98 setBackgroundDrawable(ColorDrawable(Color.Transparent.value.toInt())) 99 setLayout( 100 WindowManager.LayoutParams.MATCH_PARENT, 101 WindowManager.LayoutParams.MATCH_PARENT, 102 ) 103 clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) 104 setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY) 105 } 106 107 dialog.setContentView( 108 createComposeView(context.androidContext) { 109 Column( 110 modifier = Modifier 111 .fillMaxSize() 112 .padding(start = 12.dp, end = 12.dp, top = 10.dp, bottom = 20.dp) 113 .clip(shape = MaterialTheme.shapes.large), 114 horizontalAlignment = Alignment.CenterHorizontally, 115 verticalArrangement = Arrangement.Center 116 ) { 117 OverlayContent(route) 118 } 119 } 120 ) 121 122 dialog.setCancelable(true) 123 dialog.show() 124 } 125 } 126 }