mirror of
https://github.com/Aviortheking/Neo-Store.git
synced 2025-04-23 03:12:15 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
5543c78987
@ -17,8 +17,8 @@ android {
|
|||||||
applicationId = 'com.looker.droidify'
|
applicationId = 'com.looker.droidify'
|
||||||
minSdk = 23
|
minSdk = 23
|
||||||
targetSdk = 32
|
targetSdk = 32
|
||||||
versionCode = 43
|
versionCode = 903
|
||||||
versionName = "0.4.3"
|
versionName = "0.9.0"
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
|
|
||||||
javaCompileOptions {
|
javaCompileOptions {
|
||||||
@ -58,7 +58,7 @@ android {
|
|||||||
minifyEnabled = false
|
minifyEnabled = false
|
||||||
shrinkResources = false
|
shrinkResources = false
|
||||||
applicationIdSuffix = ".debug"
|
applicationIdSuffix = ".debug"
|
||||||
versionNameSuffix = "-alpha2"
|
versionNameSuffix = "-alpha3"
|
||||||
resValue "string", "application_name", "Neo Store-Debug"
|
resValue "string", "application_name", "Neo Store-Debug"
|
||||||
manifestPlaceholders = [
|
manifestPlaceholders = [
|
||||||
appIcon : "@mipmap/ic_launcher_debug",
|
appIcon : "@mipmap/ic_launcher_debug",
|
||||||
@ -69,7 +69,7 @@ android {
|
|||||||
minifyEnabled = false
|
minifyEnabled = false
|
||||||
shrinkResources = false
|
shrinkResources = false
|
||||||
applicationIdSuffix = ".neo"
|
applicationIdSuffix = ".neo"
|
||||||
versionNameSuffix = "-alpha2"
|
versionNameSuffix = "-alpha3"
|
||||||
resValue "string", "application_name", "Neo Store-alpha"
|
resValue "string", "application_name", "Neo Store-alpha"
|
||||||
manifestPlaceholders = [
|
manifestPlaceholders = [
|
||||||
appIcon : "@mipmap/ic_launcher_debug",
|
appIcon : "@mipmap/ic_launcher_debug",
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||||
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
|
||||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
|
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||||
|
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||||
tools:ignore="QueryAllPackagesPermission" />
|
tools:ignore="QueryAllPackagesPermission" />
|
||||||
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" />
|
<uses-permission android:name="android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION" />
|
||||||
|
|
||||||
|
@ -15,8 +15,8 @@ const val TABLE_CATEGORY_NAME = "category"
|
|||||||
const val TABLE_CATEGORY_TEMP_NAME = "temporary_category"
|
const val TABLE_CATEGORY_TEMP_NAME = "temporary_category"
|
||||||
const val TABLE_INSTALLED = "installed"
|
const val TABLE_INSTALLED = "installed"
|
||||||
const val TABLE_INSTALLED_NAME = "memory_installed"
|
const val TABLE_INSTALLED_NAME = "memory_installed"
|
||||||
const val TABLE_LOCK = "lock"
|
const val TABLE_IGNORED = "lock"
|
||||||
const val TABLE_LOCK_NAME = "memory_lock"
|
const val TABLE_IGNORED_NAME = "memory_lock"
|
||||||
const val TABLE_PRODUCT = "product"
|
const val TABLE_PRODUCT = "product"
|
||||||
const val TABLE_PRODUCT_NAME = "product"
|
const val TABLE_PRODUCT_NAME = "product"
|
||||||
const val TABLE_PRODUCT_TEMP_NAME = "temporary_product"
|
const val TABLE_PRODUCT_TEMP_NAME = "temporary_product"
|
||||||
@ -43,7 +43,6 @@ const val ROW_ANTIFEATURES = "antiFeatures"
|
|||||||
const val ROW_LICENSES = "licenses"
|
const val ROW_LICENSES = "licenses"
|
||||||
const val ROW_DONATES = "donates"
|
const val ROW_DONATES = "donates"
|
||||||
const val ROW_SCREENSHOTS = "screenshots"
|
const val ROW_SCREENSHOTS = "screenshots"
|
||||||
const val ROW_VERSION = "version"
|
|
||||||
const val ROW_SIGNATURE = "signature"
|
const val ROW_SIGNATURE = "signature"
|
||||||
const val ROW_ID = "_id"
|
const val ROW_ID = "_id"
|
||||||
const val ROW_ENABLED = "enabled"
|
const val ROW_ENABLED = "enabled"
|
||||||
|
@ -37,7 +37,8 @@ object Preferences {
|
|||||||
Key.Theme,
|
Key.Theme,
|
||||||
Key.DefaultTab,
|
Key.DefaultTab,
|
||||||
Key.UpdateNotify,
|
Key.UpdateNotify,
|
||||||
Key.UpdateUnstable
|
Key.UpdateUnstable,
|
||||||
|
Key.IgnoreIgnoreBatteryOptimization
|
||||||
).map { Pair(it.name, it) }.toMap()
|
).map { Pair(it.name, it) }.toMap()
|
||||||
|
|
||||||
fun init(context: Context) {
|
fun init(context: Context) {
|
||||||
@ -178,6 +179,9 @@ object Preferences {
|
|||||||
|
|
||||||
object UpdateNotify : Key<Boolean>("update_notify", Value.BooleanValue(true))
|
object UpdateNotify : Key<Boolean>("update_notify", Value.BooleanValue(true))
|
||||||
object UpdateUnstable : Key<Boolean>("update_unstable", Value.BooleanValue(false))
|
object UpdateUnstable : Key<Boolean>("update_unstable", Value.BooleanValue(false))
|
||||||
|
|
||||||
|
object IgnoreIgnoreBatteryOptimization :
|
||||||
|
Key<Boolean>("ignore_ignore_battery_optimization", Value.BooleanValue(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class AutoSync(override val valueString: String) : Enumeration<AutoSync> {
|
sealed class AutoSync(override val valueString: String) : Enumeration<AutoSync> {
|
||||||
|
@ -3,7 +3,7 @@ package com.looker.droidify.content
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import com.looker.droidify.database.DatabaseX
|
import com.looker.droidify.database.DatabaseX
|
||||||
import com.looker.droidify.database.entity.Lock
|
import com.looker.droidify.database.entity.Ignored
|
||||||
import com.looker.droidify.entity.ProductPreference
|
import com.looker.droidify.entity.ProductPreference
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -27,13 +27,13 @@ object ProductPreferences {
|
|||||||
db.lockDao.insert(*preferences.all.keys
|
db.lockDao.insert(*preferences.all.keys
|
||||||
.mapNotNull { pName ->
|
.mapNotNull { pName ->
|
||||||
this@ProductPreferences[pName].databaseVersionCode?.let {
|
this@ProductPreferences[pName].databaseVersionCode?.let {
|
||||||
Lock(pName, it)
|
Ignored(pName, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.toTypedArray()
|
.toTypedArray()
|
||||||
)
|
)
|
||||||
subject.collect { (packageName, versionCode) ->
|
subject.collect { (packageName, versionCode) ->
|
||||||
if (versionCode != null) db.lockDao.insert(Lock(packageName, versionCode))
|
if (versionCode != null) db.lockDao.insert(Ignored(packageName, versionCode))
|
||||||
else db.lockDao.delete(packageName)
|
else db.lockDao.delete(packageName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ interface ProductDao : BaseDao<Product> {
|
|||||||
builder += """SELECT $TABLE_PRODUCT.rowid AS $ROW_ID, $TABLE_PRODUCT.$ROW_REPOSITORY_ID,
|
builder += """SELECT $TABLE_PRODUCT.rowid AS $ROW_ID, $TABLE_PRODUCT.$ROW_REPOSITORY_ID,
|
||||||
$TABLE_PRODUCT.$ROW_PACKAGE_NAME, $TABLE_PRODUCT.$ROW_LABEL,
|
$TABLE_PRODUCT.$ROW_PACKAGE_NAME, $TABLE_PRODUCT.$ROW_LABEL,
|
||||||
$TABLE_PRODUCT.$ROW_SUMMARY, $TABLE_PRODUCT.$ROW_DESCRIPTION,
|
$TABLE_PRODUCT.$ROW_SUMMARY, $TABLE_PRODUCT.$ROW_DESCRIPTION,
|
||||||
(COALESCE($TABLE_LOCK.$ROW_VERSION_CODE, -1) NOT IN (0, $TABLE_PRODUCT.$ROW_VERSION_CODE) AND
|
(COALESCE($TABLE_IGNORED.$ROW_VERSION_CODE, -1) NOT IN (0, $TABLE_PRODUCT.$ROW_VERSION_CODE) AND
|
||||||
$TABLE_PRODUCT.$ROW_COMPATIBLE != 0 AND
|
$TABLE_PRODUCT.$ROW_COMPATIBLE != 0 AND
|
||||||
$TABLE_PRODUCT.$ROW_VERSION_CODE > COALESCE($TABLE_INSTALLED.$ROW_VERSION_CODE, 0xffffffff) AND
|
$TABLE_PRODUCT.$ROW_VERSION_CODE > COALESCE($TABLE_INSTALLED.$ROW_VERSION_CODE, 0xffffffff) AND
|
||||||
$signatureMatches) AS $ROW_CAN_UPDATE, $TABLE_PRODUCT.$ROW_ICON,
|
$signatureMatches) AS $ROW_CAN_UPDATE, $TABLE_PRODUCT.$ROW_ICON,
|
||||||
@ -173,8 +173,8 @@ interface ProductDao : BaseDao<Product> {
|
|||||||
ON $TABLE_PRODUCT.$ROW_REPOSITORY_ID = $TABLE_REPOSITORY.$ROW_ID"""
|
ON $TABLE_PRODUCT.$ROW_REPOSITORY_ID = $TABLE_REPOSITORY.$ROW_ID"""
|
||||||
|
|
||||||
// Merge the matching locks
|
// Merge the matching locks
|
||||||
builder += """LEFT JOIN $TABLE_LOCK_NAME AS $TABLE_LOCK
|
builder += """LEFT JOIN $TABLE_IGNORED_NAME AS $TABLE_IGNORED
|
||||||
ON $TABLE_PRODUCT.$ROW_PACKAGE_NAME = $TABLE_LOCK.$ROW_PACKAGE_NAME"""
|
ON $TABLE_PRODUCT.$ROW_PACKAGE_NAME = $TABLE_IGNORED.$ROW_PACKAGE_NAME"""
|
||||||
|
|
||||||
// Merge the matching installed
|
// Merge the matching installed
|
||||||
if (!installed && !updates) builder += "LEFT"
|
if (!installed && !updates) builder += "LEFT"
|
||||||
@ -291,7 +291,7 @@ interface InstalledDao : BaseDao<Installed> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
interface LockDao : BaseDao<Lock> {
|
interface LockDao : BaseDao<Ignored> {
|
||||||
@Query("DELETE FROM memory_lock WHERE packageName = :packageName")
|
@Query("DELETE FROM memory_lock WHERE packageName = :packageName")
|
||||||
fun delete(packageName: String)
|
fun delete(packageName: String)
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ import kotlinx.coroutines.launch
|
|||||||
Category::class,
|
Category::class,
|
||||||
CategoryTemp::class,
|
CategoryTemp::class,
|
||||||
Installed::class,
|
Installed::class,
|
||||||
Lock::class
|
Ignored::class
|
||||||
], version = 6
|
], version = 6
|
||||||
)
|
)
|
||||||
@TypeConverters(Converters::class)
|
@TypeConverters(Converters::class)
|
||||||
|
@ -2,10 +2,11 @@ package com.looker.droidify.database.entity
|
|||||||
|
|
||||||
import androidx.room.Entity
|
import androidx.room.Entity
|
||||||
import androidx.room.PrimaryKey
|
import androidx.room.PrimaryKey
|
||||||
import com.looker.droidify.TABLE_LOCK_NAME
|
import com.looker.droidify.TABLE_IGNORED_NAME
|
||||||
|
|
||||||
@Entity(tableName = TABLE_LOCK_NAME)
|
// TODO complete renaming to Ignored
|
||||||
data class Lock(
|
@Entity(tableName = TABLE_IGNORED_NAME)
|
||||||
|
data class Ignored(
|
||||||
@PrimaryKey
|
@PrimaryKey
|
||||||
var packageName: String = "",
|
var packageName: String = "",
|
||||||
var versionCode: Long = 0L
|
var versionCode: Long = 0L
|
@ -37,6 +37,7 @@ import java.io.File
|
|||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
// TODO maybe replace by using WorkManager instead?
|
||||||
class DownloadService : ConnectionService<DownloadService.Binder>() {
|
class DownloadService : ConnectionService<DownloadService.Binder>() {
|
||||||
companion object {
|
companion object {
|
||||||
private const val ACTION_CANCEL = "${BuildConfig.APPLICATION_ID}.intent.action.CANCEL"
|
private const val ACTION_CANCEL = "${BuildConfig.APPLICATION_ID}.intent.action.CANCEL"
|
||||||
|
@ -3,6 +3,7 @@ package com.looker.droidify.ui.activities
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.PowerManager
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
@ -31,6 +32,7 @@ import com.looker.droidify.ui.fragments.Source
|
|||||||
import com.looker.droidify.ui.viewmodels.MainActivityViewModelX
|
import com.looker.droidify.ui.viewmodels.MainActivityViewModelX
|
||||||
import com.looker.droidify.utility.extension.android.Android
|
import com.looker.droidify.utility.extension.android.Android
|
||||||
import com.looker.droidify.utility.extension.text.nullIfEmpty
|
import com.looker.droidify.utility.extension.text.nullIfEmpty
|
||||||
|
import com.looker.droidify.utility.showBatteryOptimizationDialog
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
@ -52,6 +54,7 @@ class MainActivityX : AppCompatActivity() {
|
|||||||
lateinit var appBarConfiguration: AppBarConfiguration
|
lateinit var appBarConfiguration: AppBarConfiguration
|
||||||
private lateinit var navController: NavController
|
private lateinit var navController: NavController
|
||||||
private val viewModel: MainActivityViewModelX by viewModels()
|
private val viewModel: MainActivityViewModelX by viewModels()
|
||||||
|
private lateinit var powerManager: PowerManager
|
||||||
val menuSetup = MutableLiveData<Boolean>()
|
val menuSetup = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
val syncConnection = Connection(SyncService::class.java, onBind = { _, _ ->
|
val syncConnection = Connection(SyncService::class.java, onBind = { _, _ ->
|
||||||
@ -95,6 +98,7 @@ class MainActivityX : AppCompatActivity() {
|
|||||||
setupActionBarWithNavController(navController, appBarConfiguration)
|
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||||
binding.bottomNavigation.selectedItemId = currentTab
|
binding.bottomNavigation.selectedItemId = currentTab
|
||||||
|
|
||||||
|
powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
if (savedInstanceState == null && (intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
|
if (savedInstanceState == null && (intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
|
||||||
handleIntent(intent)
|
handleIntent(intent)
|
||||||
}
|
}
|
||||||
@ -117,6 +121,8 @@ class MainActivityX : AppCompatActivity() {
|
|||||||
super.onResume()
|
super.onResume()
|
||||||
if (currentTheme != Preferences[Preferences.Key.Theme].getResId(resources.configuration))
|
if (currentTheme != Preferences[Preferences.Key.Theme].getResId(resources.configuration))
|
||||||
recreate()
|
recreate()
|
||||||
|
if (!powerManager.isIgnoringBatteryOptimizations(this.packageName) && !Preferences[Preferences.Key.IgnoreIgnoreBatteryOptimization])
|
||||||
|
showBatteryOptimizationDialog()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSupportNavigateUp(): Boolean {
|
override fun onSupportNavigateUp(): Boolean {
|
||||||
|
@ -30,11 +30,12 @@ import com.looker.droidify.ui.compose.components.RepositoryItem
|
|||||||
fun ProductsVerticalRecycler(
|
fun ProductsVerticalRecycler(
|
||||||
productsList: List<Product>?,
|
productsList: List<Product>?,
|
||||||
repositories: Map<Long, Repository>,
|
repositories: Map<Long, Repository>,
|
||||||
|
modifier: Modifier = Modifier.fillMaxSize(),
|
||||||
onUserClick: (ProductItem) -> Unit = {},
|
onUserClick: (ProductItem) -> Unit = {},
|
||||||
onFavouriteClick: (ProductItem) -> Unit = {},
|
onFavouriteClick: (ProductItem) -> Unit = {},
|
||||||
onInstallClick: (ProductItem) -> Unit = {}
|
onInstallClick: (ProductItem) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
VerticalItemList(list = productsList) {
|
VerticalItemList(list = productsList, modifier = modifier) {
|
||||||
it.toItem().let { item ->
|
it.toItem().let { item ->
|
||||||
ProductsListItem(
|
ProductsListItem(
|
||||||
item,
|
item,
|
||||||
@ -84,7 +85,7 @@ fun RepositoriesRecycler(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun <T> VerticalItemList(
|
fun <T> VerticalItemList(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier.fillMaxSize(),
|
||||||
backgroundColor: Color = MaterialTheme.colorScheme.background,
|
backgroundColor: Color = MaterialTheme.colorScheme.background,
|
||||||
list: List<T>?,
|
list: List<T>?,
|
||||||
itemKey: ((T) -> Any)? = null,
|
itemKey: ((T) -> Any)? = null,
|
||||||
@ -92,7 +93,6 @@ fun <T> VerticalItemList(
|
|||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxSize()
|
|
||||||
.background(backgroundColor),
|
.background(backgroundColor),
|
||||||
contentAlignment = if (list.isNullOrEmpty()) Alignment.Center else Alignment.TopStart
|
contentAlignment = if (list.isNullOrEmpty()) Alignment.Center else Alignment.TopStart
|
||||||
) {
|
) {
|
||||||
|
@ -28,12 +28,13 @@ fun ProductCard(
|
|||||||
onUserClick: (ProductItem) -> Unit = {}
|
onUserClick: (ProductItem) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val imageData by remember(item, repo) {
|
val product by remember(item) { mutableStateOf(item) }
|
||||||
|
val imageData by remember(product, repo) {
|
||||||
mutableStateOf(
|
mutableStateOf(
|
||||||
CoilDownloader.createIconUri(
|
CoilDownloader.createIconUri(
|
||||||
item.packageName,
|
product.packageName,
|
||||||
item.icon,
|
product.icon,
|
||||||
item.metadataIcon,
|
product.metadataIcon,
|
||||||
repo?.address,
|
repo?.address,
|
||||||
repo?.authentication
|
repo?.authentication
|
||||||
).toString()
|
).toString()
|
||||||
@ -46,7 +47,7 @@ fun ProductCard(
|
|||||||
.requiredSize(80.dp, 116.dp)
|
.requiredSize(80.dp, 116.dp)
|
||||||
.clip(shape = RoundedCornerShape(8.dp))
|
.clip(shape = RoundedCornerShape(8.dp))
|
||||||
.background(color = MaterialTheme.colorScheme.surface)
|
.background(color = MaterialTheme.colorScheme.surface)
|
||||||
.clickable(onClick = { onUserClick(item) }),
|
.clickable(onClick = { onUserClick(product) }),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
@ -57,7 +58,7 @@ fun ProductCard(
|
|||||||
|
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.padding(4.dp, 2.dp),
|
modifier = Modifier.padding(4.dp, 2.dp),
|
||||||
text = item.name,
|
text = product.name,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
@ -65,7 +66,7 @@ fun ProductCard(
|
|||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.padding(4.dp, 1.dp),
|
modifier = Modifier.padding(4.dp, 1.dp),
|
||||||
text = item.version,
|
text = product.version,
|
||||||
style = MaterialTheme.typography.labelSmall,
|
style = MaterialTheme.typography.labelSmall,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
|
@ -32,12 +32,13 @@ fun ProductsListItem(
|
|||||||
onFavouriteClick: (ProductItem) -> Unit = {},
|
onFavouriteClick: (ProductItem) -> Unit = {},
|
||||||
onInstallClick: (ProductItem) -> Unit = {}
|
onInstallClick: (ProductItem) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
val imageData by remember(item, repo) {
|
val product by remember(item) { mutableStateOf(item) }
|
||||||
|
val imageData by remember(product, repo) {
|
||||||
mutableStateOf(
|
mutableStateOf(
|
||||||
CoilDownloader.createIconUri(
|
CoilDownloader.createIconUri(
|
||||||
item.packageName,
|
product.packageName,
|
||||||
item.icon,
|
product.icon,
|
||||||
item.metadataIcon,
|
product.metadataIcon,
|
||||||
repo?.address,
|
repo?.address,
|
||||||
repo?.authentication
|
repo?.authentication
|
||||||
).toString()
|
).toString()
|
||||||
@ -46,10 +47,10 @@ fun ProductsListItem(
|
|||||||
|
|
||||||
ExpandableCard(
|
ExpandableCard(
|
||||||
modifier = Modifier.padding(horizontal = 8.dp, vertical = 8.dp),
|
modifier = Modifier.padding(horizontal = 8.dp, vertical = 8.dp),
|
||||||
onClick = { onUserClick(item) },
|
onClick = { onUserClick(product) },
|
||||||
expandedContent = {
|
expandedContent = {
|
||||||
ExpandedItemContent(
|
ExpandedItemContent(
|
||||||
item = item,
|
item = product,
|
||||||
onFavourite = onFavouriteClick,
|
onFavourite = onFavouriteClick,
|
||||||
onInstallClicked = onInstallClick
|
onInstallClicked = onInstallClick
|
||||||
)
|
)
|
||||||
@ -74,7 +75,7 @@ fun ProductsListItem(
|
|||||||
.fillMaxHeight(0.4f),
|
.fillMaxHeight(0.4f),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = item.name,
|
text = product.name,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.CenterVertically)
|
.align(Alignment.CenterVertically)
|
||||||
.weight(1f),
|
.weight(1f),
|
||||||
@ -84,8 +85,8 @@ fun ProductsListItem(
|
|||||||
style = MaterialTheme.typography.titleMedium
|
style = MaterialTheme.typography.titleMedium
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = item.version,
|
|
||||||
modifier = Modifier.align(Alignment.CenterVertically),
|
modifier = Modifier.align(Alignment.CenterVertically),
|
||||||
|
text = product.version,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
@ -95,7 +96,7 @@ fun ProductsListItem(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
text = item.summary,
|
text = product.summary,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
maxLines = 2,
|
maxLines = 2,
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
package com.looker.droidify.ui.compose.utils
|
package com.looker.droidify.ui.compose.utils
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.Chip
|
import androidx.compose.material.*
|
||||||
import androidx.compose.material.ChipColors
|
|
||||||
import androidx.compose.material.ChipDefaults
|
|
||||||
import androidx.compose.material.ExperimentalMaterialApi
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Shape
|
import androidx.compose.ui.graphics.Shape
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@ -29,7 +27,8 @@ fun ChipRow(
|
|||||||
) {
|
) {
|
||||||
LazyRow(
|
LazyRow(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
contentPadding = PaddingValues(horizontal = 8.dp)
|
||||||
) {
|
) {
|
||||||
items(list) {
|
items(list) {
|
||||||
Chip(
|
Chip(
|
||||||
@ -40,7 +39,47 @@ fun ChipRow(
|
|||||||
Text(
|
Text(
|
||||||
text = it,
|
text = it,
|
||||||
style = MaterialTheme.typography.labelLarge,
|
style = MaterialTheme.typography.labelLarge,
|
||||||
color = MaterialTheme.colorScheme.primary.copy(alpha = ChipDefaults.ContentOpacity)
|
color = chipColors.contentColor(enabled = true).value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
|
@Composable
|
||||||
|
fun SelectableChipRow(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
list: List<String>,
|
||||||
|
chipColors: SelectableChipColors = ChipDefaults.filterChipColors(
|
||||||
|
backgroundColor = MaterialTheme.colorScheme.surface,
|
||||||
|
contentColor = MaterialTheme.colorScheme.onSurface,
|
||||||
|
selectedBackgroundColor = MaterialTheme.colorScheme.primary,
|
||||||
|
selectedContentColor = MaterialTheme.colorScheme.onPrimary
|
||||||
|
),
|
||||||
|
shapes: Shape = RoundedCornerShape(50),
|
||||||
|
onClick: (String) -> Unit
|
||||||
|
) {
|
||||||
|
var selected by remember { mutableStateOf(list[0]) }
|
||||||
|
|
||||||
|
LazyRow(
|
||||||
|
modifier = modifier,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
contentPadding = PaddingValues(horizontal = 8.dp)
|
||||||
|
) {
|
||||||
|
items(list) {
|
||||||
|
FilterChip(
|
||||||
|
shape = shapes,
|
||||||
|
colors = chipColors,
|
||||||
|
selected = it == selected,
|
||||||
|
onClick = {
|
||||||
|
onClick(it)
|
||||||
|
selected = it
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = it,
|
||||||
|
color = chipColors.contentColor(enabled = true, selected = it == selected).value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,8 @@ import androidx.fragment.app.Fragment
|
|||||||
abstract class BaseNavFragment : Fragment() {
|
abstract class BaseNavFragment : Fragment() {
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
setupAdapters()
|
|
||||||
setupLayout()
|
setupLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun setupAdapters()
|
|
||||||
abstract fun setupLayout()
|
abstract fun setupLayout()
|
||||||
}
|
}
|
@ -5,18 +5,26 @@ import android.view.LayoutInflater
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.material.Scaffold
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.core.view.children
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import com.google.android.material.chip.Chip
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.material.ExperimentalMaterialApi
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import com.looker.droidify.R
|
import com.looker.droidify.R
|
||||||
import com.looker.droidify.content.Preferences
|
import com.looker.droidify.content.Preferences
|
||||||
import com.looker.droidify.database.entity.Category
|
import com.looker.droidify.database.entity.Product
|
||||||
import com.looker.droidify.database.entity.Repository
|
import com.looker.droidify.database.entity.Repository
|
||||||
import com.looker.droidify.databinding.FragmentExploreXBinding
|
import com.looker.droidify.databinding.FragmentExploreXBinding
|
||||||
import com.looker.droidify.entity.Section
|
import com.looker.droidify.entity.Section
|
||||||
import com.looker.droidify.ui.compose.ProductsVerticalRecycler
|
import com.looker.droidify.ui.compose.ProductsVerticalRecycler
|
||||||
import com.looker.droidify.ui.compose.theme.AppTheme
|
import com.looker.droidify.ui.compose.theme.AppTheme
|
||||||
|
import com.looker.droidify.ui.compose.utils.SelectableChipRow
|
||||||
import com.looker.droidify.utility.isDarkTheme
|
import com.looker.droidify.utility.isDarkTheme
|
||||||
import com.looker.droidify.widget.FocusSearchView
|
import com.looker.droidify.widget.FocusSearchView
|
||||||
|
|
||||||
@ -40,67 +48,15 @@ class ExploreFragment : MainNavFragmentX() {
|
|||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupAdapters() {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupLayout() {
|
override fun setupLayout() {
|
||||||
viewModel.repositories.observe(viewLifecycleOwner) {
|
viewModel.repositories.observe(viewLifecycleOwner) {
|
||||||
repositories = it.associateBy { repo -> repo.id }
|
repositories = it.associateBy { repo -> repo.id }
|
||||||
}
|
}
|
||||||
viewModel.primaryProducts.observe(viewLifecycleOwner) {
|
viewModel.primaryProducts.observe(viewLifecycleOwner) {
|
||||||
binding.primaryComposeRecycler.setContent {
|
redrawPage(it, viewModel.categories.value ?: emptyList())
|
||||||
AppTheme(
|
|
||||||
darkTheme = when (Preferences[Preferences.Key.Theme]) {
|
|
||||||
is Preferences.Theme.System -> isSystemInDarkTheme()
|
|
||||||
is Preferences.Theme.AmoledSystem -> isSystemInDarkTheme()
|
|
||||||
else -> isDarkTheme
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
Scaffold { _ ->
|
|
||||||
ProductsVerticalRecycler(it, repositories,
|
|
||||||
onUserClick = { item ->
|
|
||||||
AppSheetX(item.packageName)
|
|
||||||
.showNow(parentFragmentManager, "Product ${item.packageName}")
|
|
||||||
},
|
|
||||||
onFavouriteClick = {},
|
|
||||||
onInstallClick = {
|
|
||||||
mainActivityX.syncConnection.binder?.installApps(listOf(it))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
viewModel.categories.observe(viewLifecycleOwner) {
|
viewModel.categories.observe(viewLifecycleOwner) {
|
||||||
binding.categories.apply {
|
redrawPage(viewModel.primaryProducts.value, it)
|
||||||
removeAllViews()
|
|
||||||
addView(Chip(requireContext(), null, R.attr.categoryChipStyle).apply {
|
|
||||||
setText(R.string.all_applications)
|
|
||||||
id = R.id.SHOW_ALL
|
|
||||||
})
|
|
||||||
it.sorted().forEach {
|
|
||||||
addView(Chip(requireContext(), null, R.attr.categoryChipStyle).apply {
|
|
||||||
text = it
|
|
||||||
})
|
|
||||||
}
|
|
||||||
val selectedSection = viewModel.sections.value
|
|
||||||
check(
|
|
||||||
children.filterNotNull()
|
|
||||||
.find { child ->
|
|
||||||
child is Chip && selectedSection is Category && child.text == selectedSection.label
|
|
||||||
}?.id ?: R.id.SHOW_ALL
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding.categories.setOnCheckedStateChangeListener { group, checkedIds ->
|
|
||||||
group.findViewById<Chip>(checkedIds[0]).let {
|
|
||||||
viewModel.setSection(
|
|
||||||
if (it.text.equals(getString(R.string.all_applications)))
|
|
||||||
Section.All
|
|
||||||
else
|
|
||||||
Section.Category(it.text.toString())
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mainActivityX.menuSetup.observe(viewLifecycleOwner) {
|
mainActivityX.menuSetup.observe(viewLifecycleOwner) {
|
||||||
if (it != null) {
|
if (it != null) {
|
||||||
@ -122,4 +78,53 @@ class ExploreFragment : MainNavFragmentX() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
|
||||||
|
private fun redrawPage(products: List<Product>?, categories: List<String> = emptyList()) {
|
||||||
|
binding.primaryComposeRecycler.setContent {
|
||||||
|
AppTheme(
|
||||||
|
darkTheme = when (Preferences[Preferences.Key.Theme]) {
|
||||||
|
is Preferences.Theme.System -> isSystemInDarkTheme()
|
||||||
|
is Preferences.Theme.AmoledSystem -> isSystemInDarkTheme()
|
||||||
|
else -> isDarkTheme
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Scaffold { _ ->
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.background(MaterialTheme.colorScheme.background)
|
||||||
|
.fillMaxSize()
|
||||||
|
) {
|
||||||
|
SelectableChipRow(
|
||||||
|
list = listOf(
|
||||||
|
stringResource(id = R.string.all_applications),
|
||||||
|
*categories.sorted().toTypedArray()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
viewModel.setSection(
|
||||||
|
when (it) {
|
||||||
|
getString(R.string.all_applications) -> Section.All
|
||||||
|
else -> Section.Category(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ProductsVerticalRecycler(products,
|
||||||
|
repositories,
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1f),
|
||||||
|
onUserClick = { item ->
|
||||||
|
AppSheetX(item.packageName)
|
||||||
|
.showNow(parentFragmentManager, "Product ${item.packageName}")
|
||||||
|
},
|
||||||
|
onFavouriteClick = {},
|
||||||
|
onInstallClick = {
|
||||||
|
mainActivityX.syncConnection.binder?.installApps(listOf(it))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,6 @@ class InstalledFragment : MainNavFragmentX() {
|
|||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupAdapters() {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupLayout() {
|
override fun setupLayout() {
|
||||||
viewModel.repositories.observe(viewLifecycleOwner) {
|
viewModel.repositories.observe(viewLifecycleOwner) {
|
||||||
repositories = it.associateBy { repo -> repo.id }
|
repositories = it.associateBy { repo -> repo.id }
|
||||||
|
@ -39,9 +39,6 @@ class LatestFragment : MainNavFragmentX() {
|
|||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupAdapters() {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupLayout() {
|
override fun setupLayout() {
|
||||||
viewModel.repositories.observe(viewLifecycleOwner) {
|
viewModel.repositories.observe(viewLifecycleOwner) {
|
||||||
repositories = it.associateBy { repo -> repo.id }
|
repositories = it.associateBy { repo -> repo.id }
|
||||||
|
@ -43,12 +43,9 @@ class PrefsRepositoriesFragment : BaseNavFragment() {
|
|||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupAdapters() {
|
override fun setupLayout() {
|
||||||
syncConnection.bind(requireContext())
|
syncConnection.bind(requireContext())
|
||||||
binding.addRepository.setOnClickListener { viewModel.addRepository() }
|
binding.addRepository.setOnClickListener { viewModel.addRepository() }
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupLayout() {
|
|
||||||
viewModel.repositories.observe(requireActivity()) {
|
viewModel.repositories.observe(requireActivity()) {
|
||||||
binding.reposRecycler.setContent {
|
binding.reposRecycler.setContent {
|
||||||
AppTheme(
|
AppTheme(
|
||||||
|
@ -3,11 +3,19 @@ package com.looker.droidify.utility
|
|||||||
import android.app.ActivityManager
|
import android.app.ActivityManager
|
||||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
|
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
|
||||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE
|
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.content.Intent
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import android.content.pm.Signature
|
import android.content.pm.Signature
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.PowerManager
|
||||||
|
import android.provider.Settings
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import com.looker.droidify.BuildConfig
|
import com.looker.droidify.BuildConfig
|
||||||
import com.looker.droidify.PREFS_LANGUAGE_DEFAULT
|
import com.looker.droidify.PREFS_LANGUAGE_DEFAULT
|
||||||
import com.looker.droidify.R
|
import com.looker.droidify.R
|
||||||
@ -194,3 +202,27 @@ val isBlackTheme: Boolean
|
|||||||
is Preferences.Theme.AmoledSystem -> true
|
is Preferences.Theme.AmoledSystem -> true
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Context.showBatteryOptimizationDialog() {
|
||||||
|
AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.ignore_battery_optimization_title)
|
||||||
|
.setMessage(R.string.ignore_battery_optimization_message)
|
||||||
|
.setPositiveButton(R.string.dialog_approve) { dialog: DialogInterface?, _: Int ->
|
||||||
|
val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
|
||||||
|
intent.data = Uri.parse("package:" + this.packageName)
|
||||||
|
try {
|
||||||
|
startActivity(intent)
|
||||||
|
} catch (e: ActivityNotFoundException) {
|
||||||
|
Toast.makeText(
|
||||||
|
this,
|
||||||
|
R.string.ignore_battery_optimization_not_supported,
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
Preferences[Preferences.Key.IgnoreIgnoreBatteryOptimization] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.setNeutralButton(R.string.dialog_refuse) { _: DialogInterface?, _: Int ->
|
||||||
|
Preferences[Preferences.Key.IgnoreIgnoreBatteryOptimization] = true
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
@ -15,8 +15,7 @@
|
|||||||
~ You should have received a copy of the GNU Affero General Public License
|
~ You should have received a copy of the GNU Affero General Public License
|
||||||
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
-->
|
-->
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
@ -26,33 +25,10 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.compose.ui.platform.ComposeView
|
||||||
|
android:id="@+id/primaryComposeRecycler"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent" />
|
||||||
android:nestedScrollingEnabled="true"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<HorizontalScrollView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:scrollbars="none">
|
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
|
||||||
android:id="@+id/categories"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:nestedScrollingEnabled="true"
|
|
||||||
android:paddingHorizontal="@dimen/shape_margin_medium"
|
|
||||||
app:selectionRequired="true"
|
|
||||||
app:singleSelection="true" />
|
|
||||||
</HorizontalScrollView>
|
|
||||||
|
|
||||||
<androidx.compose.ui.platform.ComposeView
|
|
||||||
android:id="@+id/primaryComposeRecycler"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_weight="1" />
|
|
||||||
</LinearLayout>
|
|
||||||
</com.google.android.material.circularreveal.CircularRevealFrameLayout>
|
</com.google.android.material.circularreveal.CircularRevealFrameLayout>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
||||||
|
@ -189,4 +189,9 @@
|
|||||||
<string name="default_tab">Default Tab</string>
|
<string name="default_tab">Default Tab</string>
|
||||||
<string name="pending">Pending</string>
|
<string name="pending">Pending</string>
|
||||||
<string name="installing">Installing</string>
|
<string name="installing">Installing</string>
|
||||||
|
<string name="ignore_battery_optimization_title">Ignore Battery Optimization</string>
|
||||||
|
<string name="ignore_battery_optimization_message">Starting Android 12 there\'s restrictions on running foreground services causing the app to crash on downloads. To prevent this, you should turn off the battery optimization</string>
|
||||||
|
<string name="ignore_battery_optimization_not_supported">The device doesn\'t support ignoring battery optimizations!</string>
|
||||||
|
<string name="dialog_refuse">Don\'t need it</string>
|
||||||
|
<string name="dialog_approve">Let\'s do it!</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user