Skip to content
11 changes: 11 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-feature android:name="android.hardware.camera.flashlight" android:required="false" />

Expand Down Expand Up @@ -563,6 +564,16 @@
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
<service
android:name=".services.tiles.DeveloperOptionsTileService"
android:exported="true"
android:icon="@drawable/rounded_mobile_code_24"
android:label="@string/tile_developer_options"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>

<receiver
android:name=".services.receivers.FlashlightActionReceiver"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
Expand Down Expand Up @@ -162,6 +163,9 @@ class FeatureSettingsActivity : FragmentActivity() {
val pinnedFeatureKeys by viewModel.pinnedFeatureKeys

EssentialsTheme(pitchBlackTheme = isPitchBlackThemeEnabled) {
androidx.compose.runtime.CompositionLocalProvider(
com.sameerasw.essentials.ui.state.LocalMenuStateManager provides remember { com.sameerasw.essentials.ui.state.MenuStateManager() }
) {
val view = LocalView.current
val prefs = context.getSharedPreferences("essentials_prefs", MODE_PRIVATE)

Expand Down Expand Up @@ -204,6 +208,11 @@ class FeatureSettingsActivity : FragmentActivity() {
}
}

// Help Sheet State
var showHelpSheet by remember { mutableStateOf(false) }
var selectedHelpFeature by remember { mutableStateOf<com.sameerasw.essentials.domain.model.Feature?>(null) }


// Show permission sheet if feature has missing permissions
LaunchedEffect(
featureId,
Expand Down Expand Up @@ -266,6 +275,16 @@ class FeatureSettingsActivity : FragmentActivity() {
}
}

if (showHelpSheet && selectedHelpFeature != null) {
com.sameerasw.essentials.ui.components.sheets.FeatureHelpBottomSheet(
onDismissRequest = {
showHelpSheet = false
selectedHelpFeature = null
},
feature = selectedHelpFeature!!
)
}

val scrollBehavior =
TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState())
Scaffold(
Expand All @@ -285,7 +304,50 @@ class FeatureSettingsActivity : FragmentActivity() {
onBackClick = { finish() },
scrollBehavior = scrollBehavior,
subtitle = if (featureObj != null) stringResource(featureObj.description) else "",
isBeta = featureObj?.isBeta ?: false
isBeta = featureObj?.isBeta ?: false,
actions = {
if (featureObj != null && featureObj.aboutDescription != null) {
var showMenu by remember { mutableStateOf(false) }
androidx.compose.material3.IconButton(
onClick = {
HapticUtil.performVirtualKeyHaptic(view)
showMenu = true
},
colors = androidx.compose.material3.IconButtonDefaults.iconButtonColors(
containerColor = MaterialTheme.colorScheme.surfaceBright
),
modifier = Modifier.size(48.dp)
) {
androidx.compose.material3.Icon(
painter = painterResource(id = R.drawable.rounded_more_vert_24),
contentDescription = stringResource(R.string.content_desc_more_options),
modifier = Modifier.size(32.dp)
)

com.sameerasw.essentials.ui.components.menus.SegmentedDropdownMenu(
expanded = showMenu,
onDismissRequest = { showMenu = false }
) {
com.sameerasw.essentials.ui.components.menus.SegmentedDropdownMenuItem(
text = {
Text(stringResource(R.string.action_what_is_this))
},
onClick = {
showMenu = false
selectedHelpFeature = featureObj
showHelpSheet = true
},
leadingIcon = {
Icon(
painter = painterResource(id = R.drawable.rounded_help_24),
contentDescription = null
)
}
)
}
}
}
}
)
},
floatingActionButton = {
Expand All @@ -308,7 +370,7 @@ class FeatureSettingsActivity : FragmentActivity() {
}
}
) { innerPadding ->
val hasScroll = featureId != "Sound mode tile"
val hasScroll = featureId != "Sound mode tile" && featureId != "Quick settings tiles"
Column(
modifier = Modifier
.padding(innerPadding)
Expand Down Expand Up @@ -387,7 +449,13 @@ class FeatureSettingsActivity : FragmentActivity() {
)
},
isPinned = pinnedFeatureKeys.contains(child.id),
onPinToggle = { viewModel.togglePinFeature(child.id) }
onPinToggle = { viewModel.togglePinFeature(child.id) },
onHelpClick = if (child.aboutDescription != null) {
{
selectedHelpFeature = child
showHelpSheet = true
}
} else null
)
}
}
Expand Down Expand Up @@ -548,6 +616,7 @@ class FeatureSettingsActivity : FragmentActivity() {
}
}
}
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/com/sameerasw/essentials/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ class MainActivity : FragmentActivity() {
setContent {
val isPitchBlackThemeEnabled by viewModel.isPitchBlackThemeEnabled
EssentialsTheme(pitchBlackTheme = isPitchBlackThemeEnabled) {
androidx.compose.runtime.CompositionLocalProvider(
com.sameerasw.essentials.ui.state.LocalMenuStateManager provides remember { com.sameerasw.essentials.ui.state.MenuStateManager() }
) {
val context = LocalContext.current
val view = LocalView.current
val versionName = try {
Expand Down Expand Up @@ -636,6 +639,7 @@ class MainActivity : FragmentActivity() {
LaunchedEffect(Unit) {
isAppReady = true
}
}
}
}
}
Expand Down
36 changes: 35 additions & 1 deletion app/src/main/java/com/sameerasw/essentials/SettingsActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ fun SettingsContent(viewModel: MainViewModel, modifier: Modifier = Modifier) {
val isBackgroundLocationPermissionGranted by viewModel.isBackgroundLocationPermissionGranted
val isDeviceAdminEnabled by viewModel.isDeviceAdminEnabled
val isCalendarPermissionGranted by viewModel.isCalendarPermissionGranted
val isUsageStatsPermissionGranted by viewModel.isUsageStatsPermissionGranted
val context = LocalContext.current
val isAppHapticsEnabled = remember { mutableStateOf(HapticUtil.loadAppHapticsEnabled(context)) }
var isPermissionsExpanded by remember { mutableStateOf(false) }
Expand Down Expand Up @@ -458,9 +459,31 @@ fun SettingsContent(viewModel: MainViewModel, modifier: Modifier = Modifier) {
},
)

PermissionCard(
iconRes = R.drawable.rounded_security_24,
title = stringResource(R.string.perm_write_settings_title),
dependentFeatures = PermissionRegistry.getFeatures("WRITE_SETTINGS"),
actionLabel = if (isWriteSettingsEnabled) "Granted" else "Grant Permission",
isGranted = isWriteSettingsEnabled,
onActionClick = {
PermissionUtils.openWriteSettings(context)
},
)

PermissionCard(
iconRes = R.drawable.rounded_volume_up_24,
title = stringResource(R.string.perm_notif_policy_title),
dependentFeatures = PermissionRegistry.getFeatures("NOTIFICATION_POLICY"),
actionLabel = if (isNotificationPolicyAccessGranted) "Granted" else "Grant Permission",
isGranted = isNotificationPolicyAccessGranted,
onActionClick = {
PermissionUtils.openNotificationPolicySettings(context)
},
)

PermissionCard(
iconRes = R.drawable.rounded_open_in_browser_24,
title = "Default Browser",
title = stringResource(R.string.perm_default_browser_title),
dependentFeatures = PermissionRegistry.getFeatures("DEFAULT_BROWSER"),
actionLabel = if (isDefaultBrowserSet) "Granted" else "Set as Default",
isGranted = isDefaultBrowserSet,
Expand Down Expand Up @@ -498,6 +521,17 @@ fun SettingsContent(viewModel: MainViewModel, modifier: Modifier = Modifier) {
},
)

PermissionCard(
iconRes = R.drawable.rounded_data_usage_24,
title = stringResource(R.string.perm_usage_stats_title),
dependentFeatures = PermissionRegistry.getFeatures("USAGE_STATS"),
actionLabel = if (isUsageStatsPermissionGranted) "Granted" else "Grant Permission",
isGranted = isUsageStatsPermissionGranted,
onActionClick = {
PermissionUtils.openUsageStatsSettings(context)
},
)

PermissionCard(
iconRes = R.drawable.rounded_location_on_24,
title = "Location Access",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class SettingsRepository(private val context: Context) {
const val KEY_FREEZE_LOCK_DELAY_INDEX = "freeze_lock_delay_index"
const val KEY_FREEZE_AUTO_EXCLUDED_APPS = "freeze_auto_excluded_apps"
const val KEY_FREEZE_SELECTED_APPS = "freeze_selected_apps"
const val KEY_FREEZE_DONT_FREEZE_ACTIVE_APPS = "freeze_dont_freeze_active_apps"

const val KEY_DEVELOPER_MODE_ENABLED = "developer_mode_enabled"
const val KEY_HAPTIC_FEEDBACK_TYPE = "haptic_feedback_type"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ abstract class Feature(
val parentFeatureId: String? = null,
val isVisibleInMain: Boolean = true,
@StringRes val authTitle: Int = 0,
@StringRes val authSubtitle: Int = 0
@StringRes val authSubtitle: Int = 0,
@StringRes val aboutDescription: Int? = null
) {
val requiresAuth: Boolean = category == com.sameerasw.essentials.R.string.cat_protection

Expand Down
Loading