mirror of
https://github.com/gkd-kit/gkd.git
synced 2024-11-16 03:32:38 +08:00
This commit is contained in:
parent
76b3049b36
commit
8892dd3da8
|
@ -74,6 +74,7 @@ import li.songe.gkd.util.ResolvedGroup
|
||||||
import li.songe.gkd.util.RuleSortOption
|
import li.songe.gkd.util.RuleSortOption
|
||||||
import li.songe.gkd.util.appInfoCacheFlow
|
import li.songe.gkd.util.appInfoCacheFlow
|
||||||
import li.songe.gkd.util.launchTry
|
import li.songe.gkd.util.launchTry
|
||||||
|
import li.songe.gkd.util.storeFlow
|
||||||
import li.songe.gkd.util.throttle
|
import li.songe.gkd.util.throttle
|
||||||
|
|
||||||
@Destination<RootGraph>(style = ProfileTransitions::class)
|
@Destination<RootGraph>(style = ProfileTransitions::class)
|
||||||
|
@ -148,12 +149,12 @@ fun AppConfigPage(appId: String) {
|
||||||
RadioButton(
|
RadioButton(
|
||||||
selected = ruleSortType == s,
|
selected = ruleSortType == s,
|
||||||
onClick = {
|
onClick = {
|
||||||
vm.ruleSortTypeFlow.update { s }
|
storeFlow.update { it.copy(appRuleSortType = s.value) }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
vm.ruleSortTypeFlow.update { s }
|
storeFlow.update { it.copy(appRuleSortType = s.value) }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -164,7 +165,8 @@ fun AppConfigPage(appId: String) {
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
onClick = throttle {
|
onClick = throttle {
|
||||||
navController.toDestinationsNavigator().navigate(AppItemPageDestination(LOCAL_SUBS_ID, appId))
|
navController.toDestinationsNavigator()
|
||||||
|
.navigate(AppItemPageDestination(LOCAL_SUBS_ID, appId))
|
||||||
},
|
},
|
||||||
content = {
|
content = {
|
||||||
Icon(
|
Icon(
|
||||||
|
@ -295,7 +297,6 @@ private fun AppGroupCard(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onCheckedChange: ((Boolean) -> Unit)?,
|
onCheckedChange: ((Boolean) -> Unit)?,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current as MainActivity
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable(onClick = onClick)
|
.clickable(onClick = onClick)
|
||||||
|
@ -349,20 +350,26 @@ private fun AppGroupCard(
|
||||||
if (checked != null) {
|
if (checked != null) {
|
||||||
Switch(checked = checked, onCheckedChange = onCheckedChange)
|
Switch(checked = checked, onCheckedChange = onCheckedChange)
|
||||||
} else {
|
} else {
|
||||||
Switch(
|
InnerDisableSwitch()
|
||||||
checked = false,
|
|
||||||
enabled = false,
|
|
||||||
onCheckedChange = null,
|
|
||||||
modifier = Modifier.clickable(
|
|
||||||
interactionSource = remember { MutableInteractionSource() },
|
|
||||||
indication = null,
|
|
||||||
) {
|
|
||||||
context.mainVm.dialogFlow.updateDialogOptions(
|
|
||||||
title = "内置禁用",
|
|
||||||
text = "此规则组已经在其 apps 字段中配置对当前应用的禁用, 因此无法手动开启规则组\n\n提示: 这种情况一般在此全局规则无法适配/跳过适配/单独适配当前应用时出现",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun InnerDisableSwitch() {
|
||||||
|
val context = LocalContext.current as MainActivity
|
||||||
|
Switch(
|
||||||
|
checked = false,
|
||||||
|
enabled = false,
|
||||||
|
onCheckedChange = null,
|
||||||
|
modifier = Modifier.clickable(
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
indication = null,
|
||||||
|
) {
|
||||||
|
context.mainVm.dialogFlow.updateDialogOptions(
|
||||||
|
title = "内置禁用",
|
||||||
|
text = "此规则组已经在其 apps 字段中配置对当前应用的禁用, 因此无法手动开启规则组\n\n提示: 这种情况一般在此全局规则无法适配/跳过适配/单独适配当前应用时出现",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.ramcosta.composedestinations.generated.destinations.AppConfigPageDestination
|
import com.ramcosta.composedestinations.generated.destinations.AppConfigPageDestination
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
|
@ -16,11 +15,14 @@ import li.songe.gkd.util.ResolvedAppGroup
|
||||||
import li.songe.gkd.util.ResolvedGlobalGroup
|
import li.songe.gkd.util.ResolvedGlobalGroup
|
||||||
import li.songe.gkd.util.RuleSortOption
|
import li.songe.gkd.util.RuleSortOption
|
||||||
import li.songe.gkd.util.collator
|
import li.songe.gkd.util.collator
|
||||||
|
import li.songe.gkd.util.findOption
|
||||||
import li.songe.gkd.util.getGroupRawEnable
|
import li.songe.gkd.util.getGroupRawEnable
|
||||||
|
import li.songe.gkd.util.map
|
||||||
|
import li.songe.gkd.util.storeFlow
|
||||||
import li.songe.gkd.util.subsIdToRawFlow
|
import li.songe.gkd.util.subsIdToRawFlow
|
||||||
import li.songe.gkd.util.subsItemsFlow
|
import li.songe.gkd.util.subsItemsFlow
|
||||||
|
|
||||||
class AppConfigVm (stateHandle: SavedStateHandle) : ViewModel() {
|
class AppConfigVm(stateHandle: SavedStateHandle) : ViewModel() {
|
||||||
private val args = AppConfigPageDestination.argsFrom(stateHandle)
|
private val args = AppConfigPageDestination.argsFrom(stateHandle)
|
||||||
|
|
||||||
private val latestGlobalLogsFlow = DbSet.clickLogDao.queryAppLatest(
|
private val latestGlobalLogsFlow = DbSet.clickLogDao.queryAppLatest(
|
||||||
|
@ -33,7 +35,8 @@ class AppConfigVm (stateHandle: SavedStateHandle) : ViewModel() {
|
||||||
SubsConfig.AppGroupType
|
SubsConfig.AppGroupType
|
||||||
)
|
)
|
||||||
|
|
||||||
val ruleSortTypeFlow = MutableStateFlow<RuleSortOption>(RuleSortOption.Default)
|
val ruleSortTypeFlow =
|
||||||
|
storeFlow.map(viewModelScope) { RuleSortOption.allSubObject.findOption(it.appRuleSortType) }
|
||||||
|
|
||||||
private val subsFlow = combine(subsIdToRawFlow, subsItemsFlow) { subsIdToRaw, subsItems ->
|
private val subsFlow = combine(subsIdToRawFlow, subsItemsFlow) { subsIdToRaw, subsItems ->
|
||||||
subsItems.mapNotNull { if (it.enable && subsIdToRaw[it.id] != null) it to subsIdToRaw[it.id]!! else null }
|
subsItems.mapNotNull { if (it.enable && subsIdToRaw[it.id] != null) it to subsIdToRaw[it.id]!! else null }
|
||||||
|
|
|
@ -259,7 +259,7 @@ fun AuthA11yPage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val commandText by lazy { "adb pm grant ${META.appId} android.permission.WRITE_SECURE_SETTINGS" }
|
private val commandText by lazy { "adb shell pm grant ${META.appId} android.permission.WRITE_SECURE_SETTINGS" }
|
||||||
|
|
||||||
private suspend fun MainActivity.grantPermissionByShizuku() {
|
private suspend fun MainActivity.grantPermissionByShizuku() {
|
||||||
if (shizukuOkState.stateFlow.value) {
|
if (shizukuOkState.stateFlow.value) {
|
||||||
|
|
|
@ -61,6 +61,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
||||||
import com.ramcosta.composedestinations.annotation.Destination
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
import com.ramcosta.composedestinations.annotation.RootGraph
|
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
import li.songe.gkd.data.AppInfo
|
import li.songe.gkd.data.AppInfo
|
||||||
import li.songe.gkd.data.ExcludeData
|
import li.songe.gkd.data.ExcludeData
|
||||||
import li.songe.gkd.data.RawSubscription
|
import li.songe.gkd.data.RawSubscription
|
||||||
|
@ -79,6 +80,8 @@ import li.songe.gkd.util.LocalNavController
|
||||||
import li.songe.gkd.util.ProfileTransitions
|
import li.songe.gkd.util.ProfileTransitions
|
||||||
import li.songe.gkd.util.SortTypeOption
|
import li.songe.gkd.util.SortTypeOption
|
||||||
import li.songe.gkd.util.launchTry
|
import li.songe.gkd.util.launchTry
|
||||||
|
import li.songe.gkd.util.mapHashCode
|
||||||
|
import li.songe.gkd.util.storeFlow
|
||||||
import li.songe.gkd.util.toast
|
import li.songe.gkd.util.toast
|
||||||
|
|
||||||
@Destination<RootGraph>(style = ProfileTransitions::class)
|
@Destination<RootGraph>(style = ProfileTransitions::class)
|
||||||
|
@ -109,9 +112,16 @@ fun GlobalRuleExcludePage(subsItemId: Long, groupKey: Int) {
|
||||||
})
|
})
|
||||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
LaunchedEffect(key1 = showAppInfos, block = {
|
var isFirstVisit by remember { mutableStateOf(true) }
|
||||||
listState.animateScrollToItem(0)
|
LaunchedEffect(
|
||||||
})
|
key1 = showAppInfos.mapHashCode { it.id },
|
||||||
|
) {
|
||||||
|
if (isFirstVisit) {
|
||||||
|
isFirstVisit = false
|
||||||
|
} else {
|
||||||
|
listState.scrollToItem(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
var expanded by remember { mutableStateOf(false) }
|
var expanded by remember { mutableStateOf(false) }
|
||||||
Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = {
|
Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = {
|
||||||
TopAppBar(scrollBehavior = scrollBehavior, navigationIcon = {
|
TopAppBar(scrollBehavior = scrollBehavior, navigationIcon = {
|
||||||
|
@ -190,12 +200,12 @@ fun GlobalRuleExcludePage(subsItemId: Long, groupKey: Int) {
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
RadioButton(selected = sortType == sortOption,
|
RadioButton(selected = sortType == sortOption,
|
||||||
onClick = {
|
onClick = {
|
||||||
vm.sortTypeFlow.value = sortOption
|
storeFlow.update { it.copy(subsExcludeSortType = sortOption.value) }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
vm.sortTypeFlow.value = sortOption
|
storeFlow.update { it.copy(subsExcludeSortType = sortOption.value) }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -213,11 +223,11 @@ fun GlobalRuleExcludePage(subsItemId: Long, groupKey: Int) {
|
||||||
Checkbox(
|
Checkbox(
|
||||||
checked = showSystemApp,
|
checked = showSystemApp,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
vm.showSystemAppFlow.value = !vm.showSystemAppFlow.value
|
storeFlow.update { it.copy(subsExcludeShowSystemApp = !it.subsExcludeShowSystemApp) }
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
vm.showSystemAppFlow.value = !vm.showSystemAppFlow.value
|
storeFlow.update { it.copy(subsExcludeShowSystemApp = !it.subsExcludeShowSystemApp) }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
DropdownMenuItem(
|
DropdownMenuItem(
|
||||||
|
@ -228,12 +238,11 @@ fun GlobalRuleExcludePage(subsItemId: Long, groupKey: Int) {
|
||||||
Checkbox(
|
Checkbox(
|
||||||
checked = showHiddenApp,
|
checked = showHiddenApp,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
vm.showHiddenAppFlow.value =
|
storeFlow.update { it.copy(subsExcludeShowHiddenApp = !it.subsExcludeShowHiddenApp) }
|
||||||
!vm.showHiddenAppFlow.value
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
vm.showHiddenAppFlow.value = !vm.showHiddenAppFlow.value
|
storeFlow.update { it.copy(subsExcludeShowHiddenApp = !it.subsExcludeShowHiddenApp) }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -334,11 +343,7 @@ fun GlobalRuleExcludePage(subsItemId: Long, groupKey: Int) {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Switch(
|
InnerDisableSwitch()
|
||||||
enabled = false,
|
|
||||||
checked = false,
|
|
||||||
onCheckedChange = {},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,13 @@ import kotlinx.coroutines.flow.stateIn
|
||||||
import li.songe.gkd.data.ExcludeData
|
import li.songe.gkd.data.ExcludeData
|
||||||
import li.songe.gkd.db.DbSet
|
import li.songe.gkd.db.DbSet
|
||||||
import li.songe.gkd.util.SortTypeOption
|
import li.songe.gkd.util.SortTypeOption
|
||||||
|
import li.songe.gkd.util.findOption
|
||||||
import li.songe.gkd.util.map
|
import li.songe.gkd.util.map
|
||||||
import li.songe.gkd.util.orderedAppInfosFlow
|
import li.songe.gkd.util.orderedAppInfosFlow
|
||||||
|
import li.songe.gkd.util.storeFlow
|
||||||
import li.songe.gkd.util.subsIdToRawFlow
|
import li.songe.gkd.util.subsIdToRawFlow
|
||||||
|
|
||||||
class GlobalRuleExcludeVm (stateHandle: SavedStateHandle) : ViewModel() {
|
class GlobalRuleExcludeVm(stateHandle: SavedStateHandle) : ViewModel() {
|
||||||
private val args = GlobalRuleExcludePageDestination.argsFrom(stateHandle)
|
private val args = GlobalRuleExcludePageDestination.argsFrom(stateHandle)
|
||||||
|
|
||||||
val rawSubsFlow = subsIdToRawFlow.map(viewModelScope) { it[args.subsItemId] }
|
val rawSubsFlow = subsIdToRawFlow.map(viewModelScope) { it[args.subsItemId] }
|
||||||
|
@ -40,9 +42,11 @@ class GlobalRuleExcludeVm (stateHandle: SavedStateHandle) : ViewModel() {
|
||||||
DbSet.clickLogDao.queryLatestUniqueAppIds(args.subsItemId, args.groupKey).map { appIds ->
|
DbSet.clickLogDao.queryLatestUniqueAppIds(args.subsItemId, args.groupKey).map { appIds ->
|
||||||
appIds.mapIndexed { index, appId -> appId to index }.toMap()
|
appIds.mapIndexed { index, appId -> appId to index }.toMap()
|
||||||
}
|
}
|
||||||
val sortTypeFlow = MutableStateFlow<SortTypeOption>(SortTypeOption.SortByName)
|
val sortTypeFlow = storeFlow.map(viewModelScope) {
|
||||||
val showSystemAppFlow = MutableStateFlow(true)
|
SortTypeOption.allSubObject.findOption(it.subsExcludeSortType)
|
||||||
val showHiddenAppFlow = MutableStateFlow(false)
|
}
|
||||||
|
val showSystemAppFlow = storeFlow.map(viewModelScope) { it.subsExcludeShowSystemApp }
|
||||||
|
val showHiddenAppFlow = storeFlow.map(viewModelScope) { it.subsExcludeShowHiddenApp }
|
||||||
val showAppInfosFlow =
|
val showAppInfosFlow =
|
||||||
combine(orderedAppInfosFlow.combine(showHiddenAppFlow) { appInfos, showHiddenApp ->
|
combine(orderedAppInfosFlow.combine(showHiddenAppFlow) { appInfos, showHiddenApp ->
|
||||||
if (showHiddenApp) {
|
if (showHiddenApp) {
|
||||||
|
|
|
@ -51,6 +51,7 @@ import com.ramcosta.composedestinations.annotation.Destination
|
||||||
import com.ramcosta.composedestinations.annotation.RootGraph
|
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||||
import com.ramcosta.composedestinations.generated.destinations.AppItemPageDestination
|
import com.ramcosta.composedestinations.generated.destinations.AppItemPageDestination
|
||||||
import com.ramcosta.composedestinations.utils.toDestinationsNavigator
|
import com.ramcosta.composedestinations.utils.toDestinationsNavigator
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
import li.songe.gkd.MainActivity
|
import li.songe.gkd.MainActivity
|
||||||
import li.songe.gkd.data.RawSubscription
|
import li.songe.gkd.data.RawSubscription
|
||||||
import li.songe.gkd.data.SubsConfig
|
import li.songe.gkd.data.SubsConfig
|
||||||
|
@ -70,6 +71,8 @@ import li.songe.gkd.util.appInfoCacheFlow
|
||||||
import li.songe.gkd.util.json
|
import li.songe.gkd.util.json
|
||||||
import li.songe.gkd.util.launchAsFn
|
import li.songe.gkd.util.launchAsFn
|
||||||
import li.songe.gkd.util.launchTry
|
import li.songe.gkd.util.launchTry
|
||||||
|
import li.songe.gkd.util.mapHashCode
|
||||||
|
import li.songe.gkd.util.storeFlow
|
||||||
import li.songe.gkd.util.throttle
|
import li.songe.gkd.util.throttle
|
||||||
import li.songe.gkd.util.toast
|
import li.songe.gkd.util.toast
|
||||||
import li.songe.gkd.util.updateSubscription
|
import li.songe.gkd.util.updateSubscription
|
||||||
|
@ -117,16 +120,14 @@ fun SubsPage(
|
||||||
val showUninstallApp by vm.showUninstallAppFlow.collectAsState()
|
val showUninstallApp by vm.showUninstallAppFlow.collectAsState()
|
||||||
val sortType by vm.sortTypeFlow.collectAsState()
|
val sortType by vm.sortTypeFlow.collectAsState()
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
var isFirstVisit by remember { mutableStateOf(false) }
|
var isFirstVisit by remember { mutableStateOf(true) }
|
||||||
LaunchedEffect(
|
LaunchedEffect(
|
||||||
appAndConfigs.size,
|
key1 = appAndConfigs.mapHashCode { it.t0.id }
|
||||||
sortType.value,
|
|
||||||
appAndConfigs.fold(0) { acc, t -> 31 * acc + t.t0.id.hashCode() }
|
|
||||||
) {
|
) {
|
||||||
if (isFirstVisit) {
|
if (isFirstVisit) {
|
||||||
listState.scrollToItem(0)
|
isFirstVisit = false
|
||||||
} else {
|
} else {
|
||||||
isFirstVisit = true
|
listState.scrollToItem(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,11 +198,11 @@ fun SubsPage(
|
||||||
RadioButton(
|
RadioButton(
|
||||||
selected = sortType == sortOption,
|
selected = sortType == sortOption,
|
||||||
onClick = {
|
onClick = {
|
||||||
vm.sortTypeFlow.value = sortOption
|
storeFlow.update { s -> s.copy(subsAppSortType = sortOption.value) }
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
vm.sortTypeFlow.value = sortOption
|
storeFlow.update { s -> s.copy(subsAppSortType = sortOption.value) }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -217,11 +218,11 @@ fun SubsPage(
|
||||||
},
|
},
|
||||||
trailingIcon = {
|
trailingIcon = {
|
||||||
Checkbox(checked = showUninstallApp, onCheckedChange = {
|
Checkbox(checked = showUninstallApp, onCheckedChange = {
|
||||||
vm.showUninstallAppFlow.value = it
|
storeFlow.update { s -> s.copy(subsAppShowUninstallApp = it) }
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
vm.showUninstallAppFlow.value = !showUninstallApp
|
storeFlow.update { s -> s.copy(subsAppShowUninstallApp = !showUninstallApp) }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -252,7 +253,8 @@ fun SubsPage(
|
||||||
subsConfig = subsConfig,
|
subsConfig = subsConfig,
|
||||||
enableSize = enableSize,
|
enableSize = enableSize,
|
||||||
onClick = throttle {
|
onClick = throttle {
|
||||||
navController.toDestinationsNavigator().navigate(AppItemPageDestination(subsItemId, appRaw.id))
|
navController.toDestinationsNavigator()
|
||||||
|
.navigate(AppItemPageDestination(subsItemId, appRaw.id))
|
||||||
},
|
},
|
||||||
onValueChange = throttle(fn = vm.viewModelScope.launchAsFn { enable ->
|
onValueChange = throttle(fn = vm.viewModelScope.launchAsFn { enable ->
|
||||||
val newItem = subsConfig?.copy(
|
val newItem = subsConfig?.copy(
|
||||||
|
@ -284,11 +286,13 @@ fun SubsPage(
|
||||||
item {
|
item {
|
||||||
Spacer(modifier = Modifier.height(EmptyHeight))
|
Spacer(modifier = Modifier.height(EmptyHeight))
|
||||||
if (appAndConfigs.isEmpty()) {
|
if (appAndConfigs.isEmpty()) {
|
||||||
EmptyText(text = if (searchStr.isNotEmpty()) {
|
EmptyText(
|
||||||
if (showUninstallApp) "暂无搜索结果" else "暂无搜索结果,请尝试修改筛选条件"
|
text = if (searchStr.isNotEmpty()) {
|
||||||
} else {
|
if (showUninstallApp) "暂无搜索结果" else "暂无搜索结果,请尝试修改筛选条件"
|
||||||
"暂无规则"
|
} else {
|
||||||
})
|
"暂无规则"
|
||||||
|
}
|
||||||
|
)
|
||||||
} else if (editable) {
|
} else if (editable) {
|
||||||
Spacer(modifier = Modifier.height(EmptyHeight))
|
Spacer(modifier = Modifier.height(EmptyHeight))
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,14 @@ import li.songe.gkd.db.DbSet
|
||||||
import li.songe.gkd.util.SortTypeOption
|
import li.songe.gkd.util.SortTypeOption
|
||||||
import li.songe.gkd.util.appInfoCacheFlow
|
import li.songe.gkd.util.appInfoCacheFlow
|
||||||
import li.songe.gkd.util.collator
|
import li.songe.gkd.util.collator
|
||||||
|
import li.songe.gkd.util.findOption
|
||||||
import li.songe.gkd.util.getGroupRawEnable
|
import li.songe.gkd.util.getGroupRawEnable
|
||||||
import li.songe.gkd.util.map
|
import li.songe.gkd.util.map
|
||||||
|
import li.songe.gkd.util.storeFlow
|
||||||
import li.songe.gkd.util.subsIdToRawFlow
|
import li.songe.gkd.util.subsIdToRawFlow
|
||||||
import li.songe.gkd.util.subsItemsFlow
|
import li.songe.gkd.util.subsItemsFlow
|
||||||
|
|
||||||
class SubsVm (stateHandle: SavedStateHandle) : ViewModel() {
|
class SubsVm(stateHandle: SavedStateHandle) : ViewModel() {
|
||||||
private val args = SubsPageDestination.argsFrom(stateHandle)
|
private val args = SubsPageDestination.argsFrom(stateHandle)
|
||||||
|
|
||||||
val subsItemFlow =
|
val subsItemFlow =
|
||||||
|
@ -43,9 +45,9 @@ class SubsVm (stateHandle: SavedStateHandle) : ViewModel() {
|
||||||
DbSet.clickLogDao.queryLatestUniqueAppIds(args.subsItemId).map { appIds ->
|
DbSet.clickLogDao.queryLatestUniqueAppIds(args.subsItemId).map { appIds ->
|
||||||
appIds.mapIndexed { index, appId -> appId to index }.toMap()
|
appIds.mapIndexed { index, appId -> appId to index }.toMap()
|
||||||
}
|
}
|
||||||
val sortTypeFlow = MutableStateFlow<SortTypeOption>(SortTypeOption.SortByName)
|
val sortTypeFlow = storeFlow.map(viewModelScope) { SortTypeOption.allSubObject.findOption(it.subsAppSortType) }
|
||||||
|
|
||||||
val showUninstallAppFlow = MutableStateFlow(false)
|
val showUninstallAppFlow = storeFlow.map(viewModelScope) { it.subsAppShowUninstallApp }
|
||||||
private val sortAppsFlow =
|
private val sortAppsFlow =
|
||||||
combine(combine((subsRawFlow.combine(appInfoCacheFlow) { subs, appInfoCache ->
|
combine(combine((subsRawFlow.combine(appInfoCacheFlow) { subs, appInfoCache ->
|
||||||
(subs?.apps ?: emptyList()).sortedWith { a, b ->
|
(subs?.apps ?: emptyList()).sortedWith { a, b ->
|
||||||
|
|
|
@ -69,6 +69,7 @@ import li.songe.gkd.ui.style.appItemPadding
|
||||||
import li.songe.gkd.ui.style.menuPadding
|
import li.songe.gkd.ui.style.menuPadding
|
||||||
import li.songe.gkd.util.LocalNavController
|
import li.songe.gkd.util.LocalNavController
|
||||||
import li.songe.gkd.util.SortTypeOption
|
import li.songe.gkd.util.SortTypeOption
|
||||||
|
import li.songe.gkd.util.mapHashCode
|
||||||
import li.songe.gkd.util.ruleSummaryFlow
|
import li.songe.gkd.util.ruleSummaryFlow
|
||||||
import li.songe.gkd.util.storeFlow
|
import li.songe.gkd.util.storeFlow
|
||||||
import li.songe.gkd.util.throttle
|
import li.songe.gkd.util.throttle
|
||||||
|
@ -112,14 +113,16 @@ fun useAppListPage(): ScaffoldExt {
|
||||||
})
|
})
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
var isFirstVisit by remember { mutableStateOf(false) }
|
var isFirstVisit by remember { mutableStateOf(true) }
|
||||||
LaunchedEffect(key1 = orderedAppInfos, block = {
|
LaunchedEffect(
|
||||||
|
key1 = orderedAppInfos.mapHashCode { it.id }
|
||||||
|
) {
|
||||||
if (isFirstVisit) {
|
if (isFirstVisit) {
|
||||||
listState.scrollToItem(0)
|
isFirstVisit = false
|
||||||
} else {
|
} else {
|
||||||
isFirstVisit = true
|
listState.scrollToItem(0)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||||
return ScaffoldExt(
|
return ScaffoldExt(
|
||||||
navItem = appListNav,
|
navItem = appListNav,
|
||||||
|
@ -265,7 +268,9 @@ fun useAppListPage(): ScaffoldExt {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable(onClick = throttle {
|
.clickable(onClick = throttle {
|
||||||
navController.toDestinationsNavigator().navigate(AppConfigPageDestination(appInfo.id))
|
navController
|
||||||
|
.toDestinationsNavigator()
|
||||||
|
.navigate(AppConfigPageDestination(appInfo.id))
|
||||||
})
|
})
|
||||||
.height(IntrinsicSize.Min)
|
.height(IntrinsicSize.Min)
|
||||||
.appItemPadding(),
|
.appItemPadding(),
|
||||||
|
|
5
app/src/main/kotlin/li/songe/gkd/util/Others.kt
Normal file
5
app/src/main/kotlin/li/songe/gkd/util/Others.kt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
package li.songe.gkd.util
|
||||||
|
|
||||||
|
inline fun <T, R> Iterable<T>.mapHashCode(transform: (T) -> R): Int {
|
||||||
|
return fold(0) { acc, t -> 31 * acc + transform(t).hashCode() }
|
||||||
|
}
|
|
@ -74,15 +74,21 @@ data class Store(
|
||||||
val enableDarkTheme: Boolean? = null,
|
val enableDarkTheme: Boolean? = null,
|
||||||
val enableDynamicColor: Boolean = true,
|
val enableDynamicColor: Boolean = true,
|
||||||
val enableAbFloatWindow: Boolean = true,
|
val enableAbFloatWindow: Boolean = true,
|
||||||
val sortType: Int = SortTypeOption.SortByName.value,
|
|
||||||
val showSystemApp: Boolean = true,
|
|
||||||
val showHiddenApp: Boolean = false,
|
|
||||||
val showSaveSnapshotToast: Boolean = true,
|
val showSaveSnapshotToast: Boolean = true,
|
||||||
val useSystemToast: Boolean = false,
|
val useSystemToast: Boolean = false,
|
||||||
val useCustomNotifText: Boolean = false,
|
val useCustomNotifText: Boolean = false,
|
||||||
val customNotifText: String = "\${i}全局/\${k}应用/\${u}规则组/\${n}触发",
|
val customNotifText: String = "\${i}全局/\${k}应用/\${u}规则组/\${n}触发",
|
||||||
val enableActivityLog: Boolean = false,
|
val enableActivityLog: Boolean = false,
|
||||||
val updateChannel: Int = if (META.versionName.contains("beta")) UpdateChannelOption.Beta.value else UpdateChannelOption.Stable.value,
|
val updateChannel: Int = if (META.versionName.contains("beta")) UpdateChannelOption.Beta.value else UpdateChannelOption.Stable.value,
|
||||||
|
val sortType: Int = SortTypeOption.SortByName.value,
|
||||||
|
val showSystemApp: Boolean = true,
|
||||||
|
val showHiddenApp: Boolean = false,
|
||||||
|
val appRuleSortType: Int = RuleSortOption.Default.value,
|
||||||
|
val subsAppSortType: Int = SortTypeOption.SortByName.value,
|
||||||
|
val subsAppShowUninstallApp: Boolean = false,
|
||||||
|
val subsExcludeSortType: Int = SortTypeOption.SortByName.value,
|
||||||
|
val subsExcludeShowSystemApp: Boolean = true,
|
||||||
|
val subsExcludeShowHiddenApp: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
val storeFlow by lazy {
|
val storeFlow by lazy {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user