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 }