11package com.sameerasw.essentials
22
3+ import android.content.ClipData
4+ import android.content.ClipboardManager
5+ import android.content.Context
6+ import android.content.Intent
7+ import android.net.Uri
38import android.os.Bundle
49import android.os.Vibrator
10+ import android.provider.Settings
511import androidx.activity.ComponentActivity
612import androidx.activity.compose.setContent
713import androidx.activity.enableEdgeToEdge
@@ -31,9 +37,12 @@ import androidx.lifecycle.viewmodel.compose.viewModel
3137import com.sameerasw.essentials.ui.composables.configs.StatusBarIconSettingsUI
3238import com.sameerasw.essentials.ui.composables.configs.CaffeinateSettingsUI
3339import com.sameerasw.essentials.ui.composables.configs.ScreenOffWidgetSettingsUI
40+ import com.sameerasw.essentials.ui.composables.configs.EdgeLightingSettingsUI
3441import com.sameerasw.essentials.viewmodels.CaffeinateViewModel
3542import com.sameerasw.essentials.viewmodels.MainViewModel
3643import com.sameerasw.essentials.viewmodels.StatusBarIconViewModel
44+ import com.sameerasw.essentials.ui.components.sheets.PermissionItem
45+ import com.sameerasw.essentials.ui.components.sheets.PermissionsBottomSheet
3746
3847@OptIn(ExperimentalMaterial3Api ::class )
3948class FeatureSettingsActivity : ComponentActivity () {
@@ -45,7 +54,8 @@ class FeatureSettingsActivity : ComponentActivity() {
4554 val featureDescriptions = mapOf (
4655 " Screen off widget" to " Invisible widget to turn the screen off" ,
4756 " Statusbar icons" to " Control the visibility of statusbar icons" ,
48- " Caffeinate" to " Keep the screen awake"
57+ " Caffeinate" to " Keep the screen awake" ,
58+ " Edge lighting" to " Preview edge lighting effects on new notifications"
4959 )
5060 val description = featureDescriptions[feature] ? : " "
5161 setContent {
@@ -76,6 +86,109 @@ class FeatureSettingsActivity : ComponentActivity() {
7686 )
7787 }
7888
89+ // Permission sheet state
90+ var showPermissionSheet by remember { mutableStateOf(false ) }
91+ val isAccessibilityEnabled by viewModel.isAccessibilityEnabled
92+ val isWriteSecureSettingsEnabled by viewModel.isWriteSecureSettingsEnabled
93+ val isOverlayPermissionGranted by viewModel.isOverlayPermissionGranted
94+ val isEdgeLightingAccessibilityEnabled by viewModel.isEdgeLightingAccessibilityEnabled
95+ val isNotificationListenerEnabled by viewModel.isNotificationListenerEnabled
96+
97+ // Show permission sheet if feature has missing permissions
98+ LaunchedEffect (feature, isAccessibilityEnabled, isWriteSecureSettingsEnabled, isOverlayPermissionGranted, isEdgeLightingAccessibilityEnabled, isNotificationListenerEnabled) {
99+ val hasMissingPermissions = when (feature) {
100+ " Screen off widget" -> ! isAccessibilityEnabled
101+ " Statusbar icons" -> ! isWriteSecureSettingsEnabled
102+ " Edge lighting" -> ! isOverlayPermissionGranted || ! isEdgeLightingAccessibilityEnabled || ! isNotificationListenerEnabled
103+ else -> false
104+ }
105+ showPermissionSheet = hasMissingPermissions
106+ }
107+
108+ if (showPermissionSheet) {
109+ val permissionItems = when (feature) {
110+ " Screen off widget" -> listOf (
111+ PermissionItem (
112+ iconRes = R .drawable.rounded_settings_accessibility_24,
113+ title = " Accessibility" ,
114+ description = " Required to perform screen off actions via widget" ,
115+ dependentFeatures = PermissionRegistry .getFeatures(" ACCESSIBILITY" ),
116+ actionLabel = " Grant Permission" ,
117+ action = {
118+ context.startActivity(Intent (Settings .ACTION_ACCESSIBILITY_SETTINGS ))
119+ },
120+ isGranted = isAccessibilityEnabled
121+ )
122+ )
123+ " Statusbar icons" -> listOf (
124+ PermissionItem (
125+ iconRes = R .drawable.rounded_security_24,
126+ title = " Write Secure Settings" ,
127+ description = " Required to change status bar icon visibility" ,
128+ dependentFeatures = PermissionRegistry .getFeatures(" WRITE_SECURE_SETTINGS" ),
129+ actionLabel = " Copy ADB" ,
130+ action = {
131+ val adbCommand = " adb shell pm grant com.sameerasw.essentials android.permission.WRITE_SECURE_SETTINGS"
132+ val clipboard = context.getSystemService(Context .CLIPBOARD_SERVICE ) as ClipboardManager
133+ val clip = ClipData .newPlainText(" adb_command" , adbCommand)
134+ clipboard.setPrimaryClip(clip)
135+ },
136+ secondaryActionLabel = " Check" ,
137+ secondaryAction = {
138+ viewModel.isWriteSecureSettingsEnabled.value = viewModel.canWriteSecureSettings(context)
139+ },
140+ isGranted = isWriteSecureSettingsEnabled
141+ )
142+ )
143+ " Edge lighting" -> listOf (
144+ PermissionItem (
145+ iconRes = R .drawable.rounded_magnify_fullscreen_24,
146+ title = " Overlay Permission" ,
147+ description = " Required to display the edge lighting overlay on the screen" ,
148+ dependentFeatures = PermissionRegistry .getFeatures(" DRAW_OVERLAYS" ),
149+ actionLabel = " Grant Permission" ,
150+ action = {
151+ val intent = Intent (Settings .ACTION_MANAGE_OVERLAY_PERMISSION , Uri .parse(" package:${context.packageName} " ))
152+ intent.flags = Intent .FLAG_ACTIVITY_NEW_TASK
153+ context.startActivity(intent)
154+ },
155+ isGranted = isOverlayPermissionGranted
156+ ),
157+ PermissionItem (
158+ iconRes = R .drawable.rounded_settings_accessibility_24,
159+ title = " Accessibility Service" ,
160+ description = " Required to trigger edge lighting on new notifications" ,
161+ dependentFeatures = PermissionRegistry .getFeatures(" ACCESSIBILITY" ),
162+ actionLabel = " Enable in Settings" ,
163+ action = {
164+ val intent = Intent (Settings .ACTION_ACCESSIBILITY_SETTINGS )
165+ intent.flags = Intent .FLAG_ACTIVITY_NEW_TASK
166+ context.startActivity(intent)
167+ },
168+ isGranted = isEdgeLightingAccessibilityEnabled
169+ ),
170+ PermissionItem (
171+ iconRes = R .drawable.rounded_notifications_unread_24,
172+ title = " Notification Listener" ,
173+ description = " Required to detect new notifications" ,
174+ dependentFeatures = PermissionRegistry .getFeatures(" NOTIFICATION_LISTENER" ),
175+ actionLabel = if (isNotificationListenerEnabled) " Permission granted" else " Grant listener" ,
176+ action = { viewModel.requestNotificationListenerPermission(context) },
177+ isGranted = isNotificationListenerEnabled
178+ )
179+ )
180+ else -> emptyList()
181+ }
182+
183+ if (permissionItems.isNotEmpty()) {
184+ PermissionsBottomSheet (
185+ onDismissRequest = { showPermissionSheet = false },
186+ featureTitle = feature,
187+ permissions = permissionItems
188+ )
189+ }
190+ }
191+
79192 val scrollBehavior = TopAppBarDefaults .enterAlwaysScrollBehavior(rememberTopAppBarState())
80193 Scaffold (
81194 modifier = Modifier .nestedScroll(scrollBehavior.nestedScrollConnection),
@@ -128,6 +241,9 @@ class FeatureSettingsActivity : ComponentActivity() {
128241 modifier = Modifier .padding(top = 16 .dp)
129242 )
130243 }
244+ " Edge lighting" -> {
245+ EdgeLightingSettingsUI (viewModel = viewModel, modifier = Modifier .padding(top = 16 .dp))
246+ }
131247 else -> {
132248 ScreenOffWidgetSettingsUI (
133249 viewModel = viewModel,
@@ -144,4 +260,4 @@ class FeatureSettingsActivity : ComponentActivity() {
144260 }
145261 }
146262 }
147- }
263+ }
0 commit comments