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 }