Skip to content
Merged
27 changes: 27 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,14 @@
android:taskAffinity=""
android:theme="@style/Theme.Essentials.Translucent" />

<activity
android:name=".ui.activities.PrivateDnsSettingsActivity"
android:exported="true"
android:excludeFromRecents="true"
android:noHistory="true"
android:taskAffinity=""
android:theme="@style/Theme.Essentials.Translucent" />

<activity
android:name=".ui.activities.WatermarkActivity"
android:exported="true"
Expand Down Expand Up @@ -314,6 +322,14 @@
<property android:name="android.app.property.FOREGROUND_SERVICE_TYPE_SPECIAL_USE_DESCRIPTION"
android:value="Caffeinate Service" />
</service>
<service
android:name=".services.BatteryNotificationService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="specialUse">
<property android:name="android.app.property.FOREGROUND_SERVICE_TYPE_SPECIAL_USE_DESCRIPTION"
android:value="Battery Notification Service" />
</service>
<service
android:name=".services.tiles.SoundModeTileService"
android:exported="true"
Expand Down Expand Up @@ -585,6 +601,17 @@
</intent-filter>
</receiver>

<service
android:name=".services.tiles.BatteryNotificationTileService"
android:exported="true"
android:icon="@drawable/rounded_battery_charging_60_24"
android:label="@string/feat_battery_notification_title"
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.SecurityDeviceAdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN"
Expand Down
165 changes: 158 additions & 7 deletions app/src/main/java/com/sameerasw/essentials/AppUpdatesActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,23 @@ import android.os.Build
import android.os.Bundle
import android.widget.Toast
import androidx.activity.SystemBarStyle
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.Button
import androidx.compose.material3.CircularWavyProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
Expand All @@ -22,8 +30,10 @@ import androidx.compose.material3.LoadingIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ProgressIndicatorDefaults
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -47,6 +57,9 @@ import com.sameerasw.essentials.ui.theme.EssentialsTheme
import com.sameerasw.essentials.utils.HapticUtil
import com.sameerasw.essentials.viewmodels.AppUpdatesViewModel
import com.sameerasw.essentials.viewmodels.MainViewModel
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

@OptIn(ExperimentalMaterial3Api::class)
class AppUpdatesActivity : FragmentActivity() {
Expand Down Expand Up @@ -88,6 +101,61 @@ class AppUpdatesActivity : FragmentActivity() {
var showAddRepoSheet by remember { mutableStateOf(false) }
val errorMessage by updatesViewModel.errorMessage

val exportLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.CreateDocument("application/json")
) { uri ->
uri?.let {
try {
context.contentResolver.openOutputStream(it)?.use { outputStream ->
updatesViewModel.exportTrackedRepos(context, outputStream)
Toast.makeText(
context,
context.getString(R.string.msg_export_success),
Toast.LENGTH_SHORT
).show()
}
} catch (e: Exception) {
Toast.makeText(
context,
context.getString(R.string.msg_export_failed),
Toast.LENGTH_SHORT
).show()
e.printStackTrace()
}
}
}

val importLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.OpenDocument()
) { uri ->
uri?.let {
try {
context.contentResolver.openInputStream(it)?.use { inputStream ->
if (updatesViewModel.importTrackedRepos(context, inputStream)) {
Toast.makeText(
context,
context.getString(R.string.msg_import_success),
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
context,
context.getString(R.string.msg_import_failed),
Toast.LENGTH_SHORT
).show()
}
}
} catch (e: Exception) {
Toast.makeText(
context,
context.getString(R.string.msg_import_failed),
Toast.LENGTH_SHORT
).show()
e.printStackTrace()
}
}
}

LaunchedEffect(errorMessage) {
if (errorMessage != null && !showAddRepoSheet) {
Toast.makeText(context, errorMessage, Toast.LENGTH_LONG).show()
Expand Down Expand Up @@ -229,24 +297,33 @@ class AppUpdatesActivity : FragmentActivity() {
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
androidx.compose.material3.Icon(
painter = painterResource(id = R.drawable.rounded_apps_24),
contentDescription = null,
modifier = Modifier.size(64.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f)
)
androidx.compose.material3.Text(
text = stringResource(R.string.msg_no_repos_tracked),
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant
)

Spacer(modifier = Modifier.height(32.dp))

androidx.compose.material3.Text(
text = stringResource(R.string.label_apps),
style = MaterialTheme.typography.titleMedium,
modifier = Modifier.padding(bottom = 12.dp),
color = MaterialTheme.colorScheme.onSurfaceVariant
)

ImportExportButtons(
view = view,
exportLauncher = exportLauncher,
importLauncher = importLauncher
)
}
} else {
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = androidx.compose.foundation.layout.PaddingValues(
top = innerPadding.calculateTopPadding() + 16.dp,
bottom = innerPadding.calculateBottomPadding() + 80.dp,
bottom = innerPadding.calculateBottomPadding() + 100.dp,
start = 16.dp,
end = 16.dp
),
Expand Down Expand Up @@ -407,10 +484,84 @@ class AppUpdatesActivity : FragmentActivity() {
}
}
}

// Apps Section
item {
androidx.compose.material3.Text(
text = stringResource(R.string.label_apps),
style = MaterialTheme.typography.titleMedium,
modifier = Modifier.padding(start = 16.dp, bottom = 8.dp),
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.height(8.dp))
ImportExportButtons(
view = view,
exportLauncher = exportLauncher,
importLauncher = importLauncher
)
}
}
}
}
}
}
}
}

@Composable
private fun ImportExportButtons(
view: android.view.View,
exportLauncher: androidx.activity.result.ActivityResultLauncher<String>,
importLauncher: androidx.activity.result.ActivityResultLauncher<Array<String>>
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 4.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
Button(
onClick = {
HapticUtil.performUIHaptic(view)
val timeStamp = SimpleDateFormat(
"yyyyMMdd_HHmmss",
Locale.getDefault()
).format(Date())
exportLauncher.launch("essentials_updates_$timeStamp.json")
},
modifier = Modifier.weight(1f),
colors = androidx.compose.material3.ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant,
contentColor = MaterialTheme.colorScheme.onSurfaceVariant
)
) {
androidx.compose.material3.Icon(
painter = painterResource(id = R.drawable.rounded_arrow_warm_up_24),
contentDescription = null,
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(stringResource(R.string.action_export))
}

Button(
onClick = {
HapticUtil.performUIHaptic(view)
importLauncher.launch(arrayOf("application/json"))
},
modifier = Modifier.weight(1f),
colors = androidx.compose.material3.ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant,
contentColor = MaterialTheme.colorScheme.onSurfaceVariant
)
) {
androidx.compose.material3.Icon(
painter = painterResource(id = R.drawable.rounded_arrow_cool_down_24),
contentDescription = null,
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text(stringResource(R.string.action_import))
}
}
}
7 changes: 7 additions & 0 deletions app/src/main/java/com/sameerasw/essentials/EssentialsApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ class EssentialsApp : Application() {
override fun onCreate() {
super.onCreate()
context = applicationContext

try {
resources?.configuration
} catch (e: Exception) {

}

ShizukuUtils.initialize()
com.sameerasw.essentials.utils.LogManager.init(this)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import com.sameerasw.essentials.ui.components.sheets.PermissionsBottomSheet
import com.sameerasw.essentials.ui.composables.configs.AmbientMusicGlanceSettingsUI
import com.sameerasw.essentials.ui.composables.configs.AppLockSettingsUI
import com.sameerasw.essentials.ui.composables.configs.BatteriesSettingsUI
import com.sameerasw.essentials.ui.composables.configs.BatteryNotificationSettingsUI
import com.sameerasw.essentials.ui.composables.configs.ButtonRemapSettingsUI
import com.sameerasw.essentials.ui.composables.configs.CaffeinateSettingsUI
import com.sameerasw.essentials.ui.composables.configs.DynamicNightLightSettingsUI
Expand All @@ -63,6 +64,7 @@ import com.sameerasw.essentials.ui.composables.configs.ScreenOffWidgetSettingsUI
import com.sameerasw.essentials.ui.composables.configs.SnoozeNotificationsSettingsUI
import com.sameerasw.essentials.ui.composables.configs.SoundModeTileSettingsUI
import com.sameerasw.essentials.ui.composables.configs.StatusBarIconSettingsUI
import com.sameerasw.essentials.ui.composables.configs.TextAnimationsSettingsUI
import com.sameerasw.essentials.ui.composables.configs.WatchSettingsUI
import com.sameerasw.essentials.ui.theme.EssentialsTheme
import com.sameerasw.essentials.utils.BiometricSecurityHelper
Expand Down Expand Up @@ -241,6 +243,8 @@ class FeatureSettingsActivity : FragmentActivity() {
)

"Caffeinate" -> !viewModel.isPostNotificationsEnabled.value
"Battery notification" -> !viewModel.isPostNotificationsEnabled.value || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !viewModel.isBluetoothPermissionGranted.value)
"Text and animations" -> !viewModel.isWriteSettingsEnabled.value || !isWriteSecureSettingsEnabled
else -> false
}
if (hasMissingPermissions) {
Expand Down Expand Up @@ -429,6 +433,8 @@ class FeatureSettingsActivity : FragmentActivity() {
)

"Caffeinate" -> !viewModel.isPostNotificationsEnabled.value
"Battery notification" -> !viewModel.isPostNotificationsEnabled.value || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !viewModel.isBluetoothPermissionGranted.value)
"Text and animations" -> !viewModel.isWriteSettingsEnabled.value || !isWriteSecureSettingsEnabled
else -> false
}

Expand Down Expand Up @@ -603,6 +609,14 @@ class FeatureSettingsActivity : FragmentActivity() {
)
}

"Battery notification" -> {
BatteryNotificationSettingsUI(
viewModel = viewModel,
modifier = Modifier.padding(top = 16.dp),
highlightKey = highlightSetting
)
}

"Ambient music glance" -> {
AmbientMusicGlanceSettingsUI(
viewModel = viewModel,
Expand Down Expand Up @@ -634,6 +648,14 @@ class FeatureSettingsActivity : FragmentActivity() {
highlightSetting = highlightSetting
)
}

"Text and animations" -> {
TextAnimationsSettingsUI(
viewModel = viewModel,
modifier = Modifier.padding(top = 16.dp),
highlightSetting = highlightSetting
)
}
}
}
}
Expand Down
Loading