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'
|
||||
minSdk = 23
|
||||
targetSdk = 32
|
||||
versionCode = 43
|
||||
versionName = "0.4.3"
|
||||
versionCode = 903
|
||||
versionName = "0.9.0"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
||||
javaCompileOptions {
|
||||
@ -58,7 +58,7 @@ android {
|
||||
minifyEnabled = false
|
||||
shrinkResources = false
|
||||
applicationIdSuffix = ".debug"
|
||||
versionNameSuffix = "-alpha2"
|
||||
versionNameSuffix = "-alpha3"
|
||||
resValue "string", "application_name", "Neo Store-Debug"
|
||||
manifestPlaceholders = [
|
||||
appIcon : "@mipmap/ic_launcher_debug",
|
||||
@ -69,7 +69,7 @@ android {
|
||||
minifyEnabled = false
|
||||
shrinkResources = false
|
||||
applicationIdSuffix = ".neo"
|
||||
versionNameSuffix = "-alpha2"
|
||||
versionNameSuffix = "-alpha3"
|
||||
resValue "string", "application_name", "Neo Store-alpha"
|
||||
manifestPlaceholders = [
|
||||
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_DELETE_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
tools:ignore="QueryAllPackagesPermission" />
|
||||
<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_INSTALLED = "installed"
|
||||
const val TABLE_INSTALLED_NAME = "memory_installed"
|
||||
const val TABLE_LOCK = "lock"
|
||||
const val TABLE_LOCK_NAME = "memory_lock"
|
||||
const val TABLE_IGNORED = "lock"
|
||||
const val TABLE_IGNORED_NAME = "memory_lock"
|
||||
const val TABLE_PRODUCT = "product"
|
||||
const val TABLE_PRODUCT_NAME = "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_DONATES = "donates"
|
||||
const val ROW_SCREENSHOTS = "screenshots"
|
||||
const val ROW_VERSION = "version"
|
||||
const val ROW_SIGNATURE = "signature"
|
||||
const val ROW_ID = "_id"
|
||||
const val ROW_ENABLED = "enabled"
|
||||
|
@ -37,7 +37,8 @@ object Preferences {
|
||||
Key.Theme,
|
||||
Key.DefaultTab,
|
||||
Key.UpdateNotify,
|
||||
Key.UpdateUnstable
|
||||
Key.UpdateUnstable,
|
||||
Key.IgnoreIgnoreBatteryOptimization
|
||||
).map { Pair(it.name, it) }.toMap()
|
||||
|
||||
fun init(context: Context) {
|
||||
@ -178,6 +179,9 @@ object Preferences {
|
||||
|
||||
object UpdateNotify : Key<Boolean>("update_notify", Value.BooleanValue(true))
|
||||
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> {
|
||||
|
@ -3,7 +3,7 @@ package com.looker.droidify.content
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
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 kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -27,13 +27,13 @@ object ProductPreferences {
|
||||
db.lockDao.insert(*preferences.all.keys
|
||||
.mapNotNull { pName ->
|
||||
this@ProductPreferences[pName].databaseVersionCode?.let {
|
||||
Lock(pName, it)
|
||||
Ignored(pName, it)
|
||||
}
|
||||
}
|
||||
.toTypedArray()
|
||||
)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ interface ProductDao : BaseDao<Product> {
|
||||
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_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_VERSION_CODE > COALESCE($TABLE_INSTALLED.$ROW_VERSION_CODE, 0xffffffff) AND
|
||||
$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"""
|
||||
|
||||
// Merge the matching locks
|
||||
builder += """LEFT JOIN $TABLE_LOCK_NAME AS $TABLE_LOCK
|
||||
ON $TABLE_PRODUCT.$ROW_PACKAGE_NAME = $TABLE_LOCK.$ROW_PACKAGE_NAME"""
|
||||
builder += """LEFT JOIN $TABLE_IGNORED_NAME AS $TABLE_IGNORED
|
||||
ON $TABLE_PRODUCT.$ROW_PACKAGE_NAME = $TABLE_IGNORED.$ROW_PACKAGE_NAME"""
|
||||
|
||||
// Merge the matching installed
|
||||
if (!installed && !updates) builder += "LEFT"
|
||||
@ -291,7 +291,7 @@ interface InstalledDao : BaseDao<Installed> {
|
||||
}
|
||||
|
||||
@Dao
|
||||
interface LockDao : BaseDao<Lock> {
|
||||
interface LockDao : BaseDao<Ignored> {
|
||||
@Query("DELETE FROM memory_lock WHERE packageName = :packageName")
|
||||
fun delete(packageName: String)
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import kotlinx.coroutines.launch
|
||||
Category::class,
|
||||
CategoryTemp::class,
|
||||
Installed::class,
|
||||
Lock::class
|
||||
Ignored::class
|
||||
], version = 6
|
||||
)
|
||||
@TypeConverters(Converters::class)
|
||||
|
@ -2,10 +2,11 @@ package com.looker.droidify.database.entity
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.looker.droidify.TABLE_LOCK_NAME
|
||||
import com.looker.droidify.TABLE_IGNORED_NAME
|
||||
|
||||
@Entity(tableName = TABLE_LOCK_NAME)
|
||||
data class Lock(
|
||||
// TODO complete renaming to Ignored
|
||||
@Entity(tableName = TABLE_IGNORED_NAME)
|
||||
data class Ignored(
|
||||
@PrimaryKey
|
||||
var packageName: String = "",
|
||||
var versionCode: Long = 0L
|
@ -37,6 +37,7 @@ import java.io.File
|
||||
import java.security.MessageDigest
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
// TODO maybe replace by using WorkManager instead?
|
||||
class DownloadService : ConnectionService<DownloadService.Binder>() {
|
||||
companion object {
|
||||
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.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.PowerManager
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
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.utility.extension.android.Android
|
||||
import com.looker.droidify.utility.extension.text.nullIfEmpty
|
||||
import com.looker.droidify.utility.showBatteryOptimizationDialog
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
@ -52,6 +54,7 @@ class MainActivityX : AppCompatActivity() {
|
||||
lateinit var appBarConfiguration: AppBarConfiguration
|
||||
private lateinit var navController: NavController
|
||||
private val viewModel: MainActivityViewModelX by viewModels()
|
||||
private lateinit var powerManager: PowerManager
|
||||
val menuSetup = MutableLiveData<Boolean>()
|
||||
|
||||
val syncConnection = Connection(SyncService::class.java, onBind = { _, _ ->
|
||||
@ -95,6 +98,7 @@ class MainActivityX : AppCompatActivity() {
|
||||
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||
binding.bottomNavigation.selectedItemId = currentTab
|
||||
|
||||
powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
if (savedInstanceState == null && (intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) {
|
||||
handleIntent(intent)
|
||||
}
|
||||
@ -117,6 +121,8 @@ class MainActivityX : AppCompatActivity() {
|
||||
super.onResume()
|
||||
if (currentTheme != Preferences[Preferences.Key.Theme].getResId(resources.configuration))
|
||||
recreate()
|
||||
if (!powerManager.isIgnoringBatteryOptimizations(this.packageName) && !Preferences[Preferences.Key.IgnoreIgnoreBatteryOptimization])
|
||||
showBatteryOptimizationDialog()
|
||||
}
|
||||
|
||||
override fun onSupportNavigateUp(): Boolean {
|
||||
|
@ -30,11 +30,12 @@ import com.looker.droidify.ui.compose.components.RepositoryItem
|
||||
fun ProductsVerticalRecycler(
|
||||
productsList: List<Product>?,
|
||||
repositories: Map<Long, Repository>,
|
||||
modifier: Modifier = Modifier.fillMaxSize(),
|
||||
onUserClick: (ProductItem) -> Unit = {},
|
||||
onFavouriteClick: (ProductItem) -> Unit = {},
|
||||
onInstallClick: (ProductItem) -> Unit = {}
|
||||
) {
|
||||
VerticalItemList(list = productsList) {
|
||||
VerticalItemList(list = productsList, modifier = modifier) {
|
||||
it.toItem().let { item ->
|
||||
ProductsListItem(
|
||||
item,
|
||||
@ -84,7 +85,7 @@ fun RepositoriesRecycler(
|
||||
|
||||
@Composable
|
||||
fun <T> VerticalItemList(
|
||||
modifier: Modifier = Modifier,
|
||||
modifier: Modifier = Modifier.fillMaxSize(),
|
||||
backgroundColor: Color = MaterialTheme.colorScheme.background,
|
||||
list: List<T>?,
|
||||
itemKey: ((T) -> Any)? = null,
|
||||
@ -92,7 +93,6 @@ fun <T> VerticalItemList(
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.background(backgroundColor),
|
||||
contentAlignment = if (list.isNullOrEmpty()) Alignment.Center else Alignment.TopStart
|
||||
) {
|
||||
|
@ -28,12 +28,13 @@ fun ProductCard(
|
||||
onUserClick: (ProductItem) -> Unit = {}
|
||||
) {
|
||||
|
||||
val imageData by remember(item, repo) {
|
||||
val product by remember(item) { mutableStateOf(item) }
|
||||
val imageData by remember(product, repo) {
|
||||
mutableStateOf(
|
||||
CoilDownloader.createIconUri(
|
||||
item.packageName,
|
||||
item.icon,
|
||||
item.metadataIcon,
|
||||
product.packageName,
|
||||
product.icon,
|
||||
product.metadataIcon,
|
||||
repo?.address,
|
||||
repo?.authentication
|
||||
).toString()
|
||||
@ -46,7 +47,7 @@ fun ProductCard(
|
||||
.requiredSize(80.dp, 116.dp)
|
||||
.clip(shape = RoundedCornerShape(8.dp))
|
||||
.background(color = MaterialTheme.colorScheme.surface)
|
||||
.clickable(onClick = { onUserClick(item) }),
|
||||
.clickable(onClick = { onUserClick(product) }),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
@ -57,7 +58,7 @@ fun ProductCard(
|
||||
|
||||
Text(
|
||||
modifier = Modifier.padding(4.dp, 2.dp),
|
||||
text = item.name,
|
||||
text = product.name,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
@ -65,7 +66,7 @@ fun ProductCard(
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(4.dp, 1.dp),
|
||||
text = item.version,
|
||||
text = product.version,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
|
@ -32,12 +32,13 @@ fun ProductsListItem(
|
||||
onFavouriteClick: (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(
|
||||
CoilDownloader.createIconUri(
|
||||
item.packageName,
|
||||
item.icon,
|
||||
item.metadataIcon,
|
||||
product.packageName,
|
||||
product.icon,
|
||||
product.metadataIcon,
|
||||
repo?.address,
|
||||
repo?.authentication
|
||||
).toString()
|
||||
@ -46,10 +47,10 @@ fun ProductsListItem(
|
||||
|
||||
ExpandableCard(
|
||||
modifier = Modifier.padding(horizontal = 8.dp, vertical = 8.dp),
|
||||
onClick = { onUserClick(item) },
|
||||
onClick = { onUserClick(product) },
|
||||
expandedContent = {
|
||||
ExpandedItemContent(
|
||||
item = item,
|
||||
item = product,
|
||||
onFavourite = onFavouriteClick,
|
||||
onInstallClicked = onInstallClick
|
||||
)
|
||||
@ -74,7 +75,7 @@ fun ProductsListItem(
|
||||
.fillMaxHeight(0.4f),
|
||||
) {
|
||||
Text(
|
||||
text = item.name,
|
||||
text = product.name,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.weight(1f),
|
||||
@ -84,8 +85,8 @@ fun ProductsListItem(
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
Text(
|
||||
text = item.version,
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
text = product.version,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
@ -95,7 +96,7 @@ fun ProductsListItem(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.fillMaxWidth(),
|
||||
text = item.summary,
|
||||
text = product.summary,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 2,
|
||||
|
@ -1,16 +1,14 @@
|
||||
package com.looker.droidify.ui.compose.utils
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Chip
|
||||
import androidx.compose.material.ChipColors
|
||||
import androidx.compose.material.ChipDefaults
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.unit.dp
|
||||
@ -29,7 +27,8 @@ fun ChipRow(
|
||||
) {
|
||||
LazyRow(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
contentPadding = PaddingValues(horizontal = 8.dp)
|
||||
) {
|
||||
items(list) {
|
||||
Chip(
|
||||
@ -40,7 +39,47 @@ fun ChipRow(
|
||||
Text(
|
||||
text = it,
|
||||
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() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setupAdapters()
|
||||
setupLayout()
|
||||
}
|
||||
|
||||
abstract fun setupAdapters()
|
||||
abstract fun setupLayout()
|
||||
}
|
@ -5,18 +5,26 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.core.view.children
|
||||
import com.google.android.material.chip.Chip
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
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.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.databinding.FragmentExploreXBinding
|
||||
import com.looker.droidify.entity.Section
|
||||
import com.looker.droidify.ui.compose.ProductsVerticalRecycler
|
||||
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.widget.FocusSearchView
|
||||
|
||||
@ -40,67 +48,15 @@ class ExploreFragment : MainNavFragmentX() {
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun setupAdapters() {
|
||||
}
|
||||
|
||||
override fun setupLayout() {
|
||||
viewModel.repositories.observe(viewLifecycleOwner) {
|
||||
repositories = it.associateBy { repo -> repo.id }
|
||||
}
|
||||
viewModel.primaryProducts.observe(viewLifecycleOwner) {
|
||||
binding.primaryComposeRecycler.setContent {
|
||||
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))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
redrawPage(it, viewModel.categories.value ?: emptyList())
|
||||
}
|
||||
viewModel.categories.observe(viewLifecycleOwner) {
|
||||
binding.categories.apply {
|
||||
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())
|
||||
)
|
||||
}
|
||||
redrawPage(viewModel.primaryProducts.value, it)
|
||||
}
|
||||
mainActivityX.menuSetup.observe(viewLifecycleOwner) {
|
||||
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
|
||||
}
|
||||
|
||||
override fun setupAdapters() {
|
||||
}
|
||||
|
||||
override fun setupLayout() {
|
||||
viewModel.repositories.observe(viewLifecycleOwner) {
|
||||
repositories = it.associateBy { repo -> repo.id }
|
||||
|
@ -39,9 +39,6 @@ class LatestFragment : MainNavFragmentX() {
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun setupAdapters() {
|
||||
}
|
||||
|
||||
override fun setupLayout() {
|
||||
viewModel.repositories.observe(viewLifecycleOwner) {
|
||||
repositories = it.associateBy { repo -> repo.id }
|
||||
|
@ -43,12 +43,9 @@ class PrefsRepositoriesFragment : BaseNavFragment() {
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun setupAdapters() {
|
||||
override fun setupLayout() {
|
||||
syncConnection.bind(requireContext())
|
||||
binding.addRepository.setOnClickListener { viewModel.addRepository() }
|
||||
}
|
||||
|
||||
override fun setupLayout() {
|
||||
viewModel.repositories.observe(requireActivity()) {
|
||||
binding.reposRecycler.setContent {
|
||||
AppTheme(
|
||||
|
@ -3,11 +3,19 @@ package com.looker.droidify.utility
|
||||
import android.app.ActivityManager
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
|
||||
import android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.Signature
|
||||
import android.content.res.Configuration
|
||||
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.PREFS_LANGUAGE_DEFAULT
|
||||
import com.looker.droidify.R
|
||||
@ -194,3 +202,27 @@ val isBlackTheme: Boolean
|
||||
is Preferences.Theme.AmoledSystem -> true
|
||||
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
|
||||
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<data>
|
||||
|
||||
@ -26,33 +25,10 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/primaryComposeRecycler"
|
||||
android:layout_width="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>
|
||||
android:layout_height="match_parent" />
|
||||
</com.google.android.material.circularreveal.CircularRevealFrameLayout>
|
||||
</layout>
|
||||
|
||||
|
@ -189,4 +189,9 @@
|
||||
<string name="default_tab">Default Tab</string>
|
||||
<string name="pending">Pending</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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user