PermissionsScreen.kt (7103B) - raw


      1 package me.rhunk.snapenhance.ui.setup.screens.impl
      2 
      3 import android.Manifest
      4 import android.annotation.SuppressLint
      5 import android.app.Activity
      6 import android.content.Context
      7 import android.content.Intent
      8 import android.content.pm.PackageManager
      9 import android.net.Uri
     10 import android.os.Build
     11 import android.os.PowerManager
     12 import android.provider.Settings
     13 import androidx.compose.foundation.layout.*
     14 import androidx.compose.material.icons.Icons
     15 import androidx.compose.material.icons.filled.Check
     16 import androidx.compose.material3.Button
     17 import androidx.compose.material3.Icon
     18 import androidx.compose.material3.OutlinedCard
     19 import androidx.compose.material3.Text
     20 import androidx.compose.runtime.*
     21 import androidx.compose.ui.Alignment
     22 import androidx.compose.ui.Modifier
     23 import androidx.compose.ui.unit.dp
     24 import androidx.lifecycle.Lifecycle
     25 import kotlinx.coroutines.delay
     26 import kotlinx.coroutines.launch
     27 import me.rhunk.snapenhance.ui.setup.screens.SetupScreen
     28 import me.rhunk.snapenhance.ui.util.ActivityLauncherHelper
     29 import me.rhunk.snapenhance.ui.util.OnLifecycleEvent
     30 
     31 data class PermissionData(
     32     val translationKey: String,
     33     val isPermissionGranted: () -> Boolean,
     34     val requestPermission: (PermissionData) -> Unit,
     35 )
     36 
     37 class PermissionsScreen : SetupScreen() {
     38     private lateinit var activityLauncherHelper: ActivityLauncherHelper
     39 
     40     override fun init() {
     41         activityLauncherHelper = ActivityLauncherHelper(context.activity!!)
     42     }
     43 
     44     @Composable
     45     private fun RequestButton(onClick: () -> Unit) {
     46         Button(onClick = onClick) {
     47             Text(text = context.translation["setup.permissions.request_button"])
     48         }
     49     }
     50 
     51     @Composable
     52     private fun GrantedIcon() {
     53         Icon(
     54             imageVector = Icons.Filled.Check,
     55             contentDescription = null,
     56             modifier = Modifier
     57                 .size(24.dp)
     58                 .padding(5.dp)
     59         )
     60     }
     61 
     62     @SuppressLint("BatteryLife")
     63     @Composable
     64     override fun Content() {
     65         val coroutineScope = rememberCoroutineScope()
     66         val grantedPermissions = remember {
     67             mutableStateMapOf<String, Boolean>()
     68         }
     69         val permissions = remember {
     70             listOf(
     71                 PermissionData(
     72                     translationKey = "notification_access",
     73                     isPermissionGranted = {
     74                         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
     75                             context.androidContext.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
     76                         } else {
     77                             true
     78                         }
     79                     },
     80                     requestPermission = { perm ->
     81                         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
     82                             activityLauncherHelper.requestPermission(Manifest.permission.POST_NOTIFICATIONS) { resultCode, _ ->
     83                                 coroutineScope.launch {
     84                                     grantedPermissions[perm.translationKey] = resultCode == Activity.RESULT_OK
     85                                 }
     86                             }
     87                         }
     88                     }
     89                 ),
     90                 PermissionData(
     91                     translationKey = "battery_optimization",
     92                     isPermissionGranted = {
     93                         val powerManager =
     94                             context.androidContext.getSystemService(Context.POWER_SERVICE) as PowerManager
     95                         powerManager.isIgnoringBatteryOptimizations(context.androidContext.packageName)
     96                     },
     97                     requestPermission = { perm ->
     98                         activityLauncherHelper.launch(Intent().apply {
     99                             action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
    100                             data = Uri.parse("package:${context.androidContext.packageName}")
    101                         }) { resultCode, _ ->
    102                             coroutineScope.launch {
    103                                 grantedPermissions[perm.translationKey] = resultCode == 0
    104                             }
    105                         }
    106                     }
    107                 ),
    108                 PermissionData(
    109                     translationKey = "display_over_other_apps",
    110                     isPermissionGranted = {
    111                         Settings.canDrawOverlays(context.androidContext)
    112                     },
    113                     requestPermission = { perm ->
    114                         activityLauncherHelper.launch(Intent().apply {
    115                             action = Settings.ACTION_MANAGE_OVERLAY_PERMISSION
    116                             data = Uri.parse("package:${context.androidContext.packageName}")
    117                         }) { resultCode, _ ->
    118                             coroutineScope.launch {
    119                                 grantedPermissions[perm.translationKey] = resultCode == 0
    120                             }
    121                         }
    122                     }
    123                 )
    124             )
    125         }
    126 
    127         fun updateState() {
    128             permissions.forEach { perm ->
    129                 grantedPermissions[perm.translationKey] = perm.isPermissionGranted()
    130             }
    131             if (permissions.all { perm -> grantedPermissions[perm.translationKey] == true }) {
    132                 goNext()
    133             }
    134         }
    135 
    136         OnLifecycleEvent { _, event ->
    137             if (event != Lifecycle.Event.ON_RESUME) return@OnLifecycleEvent
    138             coroutineScope.launch {
    139                 updateState()
    140                 delay(1000)
    141                 updateState()
    142             }
    143         }
    144 
    145         LaunchedEffect(Unit) {
    146             updateState()
    147         }
    148 
    149         DialogText(text = context.translation["setup.permissions.dialog"])
    150 
    151         OutlinedCard(
    152             modifier = Modifier
    153                 .fillMaxWidth(),
    154         ) {
    155             Column(
    156                 verticalArrangement = Arrangement.spacedBy(16.dp),
    157                 modifier = Modifier
    158                     .padding(all = 16.dp),
    159             ) {
    160                 permissions.forEach { perm ->
    161                     Row(
    162                         verticalAlignment = Alignment.CenterVertically,
    163                     ) {
    164                         DialogText(
    165                             text = context.translation["setup.permissions.${perm.translationKey}"],
    166                             modifier = Modifier.weight(1f)
    167                         )
    168                         if (grantedPermissions[perm.translationKey] == true) {
    169                             GrantedIcon()
    170                         } else {
    171                             RequestButton {
    172                                 if (perm.isPermissionGranted()) {
    173                                     grantedPermissions[perm.translationKey] = true
    174                                 } else {
    175                                     perm.requestPermission(perm)
    176                                 }
    177                             }
    178                         }
    179                     }
    180                 }
    181             }
    182         }
    183     }
    184 }