mirror of
https://github.com/gkd-kit/gkd.git
synced 2024-11-15 19:22:26 +08:00
perf: some changes
This commit is contained in:
parent
d683296a7b
commit
3d10cfe45a
|
@ -182,8 +182,12 @@ dependencies {
|
|||
|
||||
implementation(libs.androidx.room.runtime)
|
||||
implementation(libs.androidx.room.ktx)
|
||||
implementation(libs.androidx.room.paging)
|
||||
ksp(libs.androidx.room.compiler)
|
||||
|
||||
implementation(libs.androidx.paging.runtime)
|
||||
implementation(libs.androidx.paging.compose)
|
||||
|
||||
implementation(libs.ktor.server.core)
|
||||
implementation(libs.ktor.server.cio)
|
||||
implementation(libs.ktor.server.content.negotiation)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package li.songe.gkd.data
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Delete
|
||||
|
@ -49,6 +50,9 @@ data class ClickLog(
|
|||
@Query("SELECT * FROM click_log ORDER BY id DESC LIMIT 1000")
|
||||
fun query(): Flow<List<ClickLog>>
|
||||
|
||||
@Query("SELECT * FROM click_log ORDER BY id DESC ")
|
||||
fun pagingSource(): PagingSource<Int, ClickLog>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM click_log")
|
||||
fun count(): Flow<Int>
|
||||
|
||||
|
|
|
@ -295,53 +295,51 @@ fun AppItemPage(
|
|||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column {
|
||||
Text(text = "编辑禁用", modifier = Modifier
|
||||
Text(text = "编辑禁用", modifier = Modifier
|
||||
.clickable {
|
||||
setExcludeGroupRaw(menuGroupRaw)
|
||||
setMenuGroupRaw(null)
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth())
|
||||
if (editable) {
|
||||
Text(text = "编辑规则组", modifier = Modifier
|
||||
.clickable {
|
||||
setExcludeGroupRaw(menuGroupRaw)
|
||||
setEditGroupRaw(menuGroupRaw)
|
||||
setMenuGroupRaw(null)
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth())
|
||||
if (editable) {
|
||||
Text(text = "编辑规则组", modifier = Modifier
|
||||
.clickable {
|
||||
setEditGroupRaw(menuGroupRaw)
|
||||
Text(text = "删除规则组", modifier = Modifier
|
||||
.clickable {
|
||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||
subsRaw ?: return@launchTry
|
||||
val newSubsRaw = subsRaw.copy(
|
||||
apps = subsRaw.apps
|
||||
.toMutableList()
|
||||
.apply {
|
||||
set(
|
||||
indexOfFirst { a -> a.id == appRawVal.id },
|
||||
appRawVal.copy(
|
||||
groups = appRawVal.groups
|
||||
.filter { g -> g.key != menuGroupRaw.key }
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
updateSubscription(newSubsRaw)
|
||||
DbSet.subsItemDao.update(subsItemVal.copy(mtime = System.currentTimeMillis()))
|
||||
DbSet.subsConfigDao.delete(
|
||||
subsItemVal.id, appRawVal.id, menuGroupRaw.key
|
||||
)
|
||||
toast("删除成功")
|
||||
setMenuGroupRaw(null)
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth())
|
||||
Text(text = "删除规则组", modifier = Modifier
|
||||
.clickable {
|
||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||
subsRaw ?: return@launchTry
|
||||
val newSubsRaw = subsRaw.copy(
|
||||
apps = subsRaw.apps
|
||||
.toMutableList()
|
||||
.apply {
|
||||
set(
|
||||
indexOfFirst { a -> a.id == appRawVal.id },
|
||||
appRawVal.copy(
|
||||
groups = appRawVal.groups
|
||||
.filter { g -> g.key != menuGroupRaw.key }
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
updateSubscription(newSubsRaw)
|
||||
DbSet.subsItemDao.update(subsItemVal.copy(mtime = System.currentTimeMillis()))
|
||||
DbSet.subsConfigDao.delete(
|
||||
subsItemVal.id, appRawVal.id, menuGroupRaw.key
|
||||
)
|
||||
toast("删除成功")
|
||||
setMenuGroupRaw(null)
|
||||
}
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth(),
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth(),
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -181,37 +181,35 @@ fun CategoryPage(subsItemId: Long) {
|
|||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column {
|
||||
enableGroupRadioOptions.forEach { option ->
|
||||
val onClick: () -> Unit = {
|
||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||
DbSet.categoryConfigDao.insert(
|
||||
(categoryConfig ?: CategoryConfig(
|
||||
enable = option.second,
|
||||
subsItemId = subsItemId,
|
||||
categoryKey = category.key
|
||||
)).copy(enable = option.second)
|
||||
)
|
||||
}
|
||||
enableGroupRadioOptions.forEach { option ->
|
||||
val onClick: () -> Unit = {
|
||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||
DbSet.categoryConfigDao.insert(
|
||||
(categoryConfig ?: CategoryConfig(
|
||||
enable = option.second,
|
||||
subsItemId = subsItemId,
|
||||
categoryKey = category.key
|
||||
)).copy(enable = option.second)
|
||||
)
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.selectable(
|
||||
selected = (option.second == enable),
|
||||
onClick = onClick
|
||||
)
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
RadioButton(
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.selectable(
|
||||
selected = (option.second == enable),
|
||||
onClick = onClick
|
||||
)
|
||||
Text(
|
||||
text = option.first, modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
RadioButton(
|
||||
selected = (option.second == enable),
|
||||
onClick = onClick
|
||||
)
|
||||
Text(
|
||||
text = option.first, modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -328,36 +326,34 @@ fun CategoryPage(subsItemId: Long) {
|
|||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column {
|
||||
Text(text = "编辑", modifier = Modifier
|
||||
.clickable {
|
||||
setEditNameCategory(menuCategory)
|
||||
Text(text = "编辑", modifier = Modifier
|
||||
.clickable {
|
||||
setEditNameCategory(menuCategory)
|
||||
setMenuCategory(null)
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth())
|
||||
Text(text = "删除", modifier = Modifier
|
||||
.clickable {
|
||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||
subsItem?.apply {
|
||||
updateSubscription(subsRawVal.copy(
|
||||
categories = subsRawVal.categories.filter { c -> c.key != menuCategory.key }
|
||||
))
|
||||
DbSet.subsItemDao.update(copy(mtime = System.currentTimeMillis()))
|
||||
}
|
||||
DbSet.categoryConfigDao.deleteByCategoryKey(
|
||||
subsItemId,
|
||||
menuCategory.key
|
||||
)
|
||||
toast("删除成功")
|
||||
setMenuCategory(null)
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth())
|
||||
Text(text = "删除", modifier = Modifier
|
||||
.clickable {
|
||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||
subsItem?.apply {
|
||||
updateSubscription(subsRawVal.copy(
|
||||
categories = subsRawVal.categories.filter { c -> c.key != menuCategory.key }
|
||||
))
|
||||
DbSet.subsItemDao.update(copy(mtime = System.currentTimeMillis()))
|
||||
}
|
||||
DbSet.categoryConfigDao.deleteByCategoryKey(
|
||||
subsItemId,
|
||||
menuCategory.key
|
||||
)
|
||||
toast("删除成功")
|
||||
setMenuCategory(null)
|
||||
}
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth(),
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth(),
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.height
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
|
@ -33,15 +32,18 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import androidx.paging.compose.itemKey
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.annotation.RootNavGraph
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -75,8 +77,9 @@ fun ClickLogPage() {
|
|||
val navController = LocalNavController.current
|
||||
|
||||
val vm = hiltViewModel<ClickLogVm>()
|
||||
val clickDataList by vm.clickDataListFlow.collectAsState()
|
||||
// val clickDataList by vm.clickDataListFlow.collectAsState()
|
||||
val clickLogCount by vm.clickLogCountFlow.collectAsState()
|
||||
val clickDataItems = vm.pagingDataFlow.collectAsLazyPagingItems()
|
||||
val appInfoCache by appInfoCacheFlow.collectAsState()
|
||||
val subsIdToRaw by subsIdToRawFlow.collectAsState()
|
||||
|
||||
|
@ -105,6 +108,10 @@ fun ClickLogPage() {
|
|||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = clickDataItems.itemSnapshotList.items, block = {
|
||||
LogUtils.d(clickDataItems.itemSnapshotList.items.size)
|
||||
})
|
||||
|
||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||
Scaffold(modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = {
|
||||
TopAppBar(
|
||||
|
@ -121,7 +128,7 @@ fun ClickLogPage() {
|
|||
},
|
||||
title = { Text(text = "触发记录" + if (clickLogCount <= 0) "" else ("-$clickLogCount")) },
|
||||
actions = {
|
||||
if (clickDataList.isNotEmpty()) {
|
||||
if (clickLogCount > 0) {
|
||||
IconButton(onClick = { showDeleteDlg = true }) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Delete,
|
||||
|
@ -131,71 +138,70 @@ fun ClickLogPage() {
|
|||
}
|
||||
})
|
||||
}, content = { contentPadding ->
|
||||
if (clickDataList.isNotEmpty()) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
) {
|
||||
items(clickDataList, { it.t0.id }) { (clickLog, group, rule) ->
|
||||
Column(modifier = Modifier
|
||||
.clickable {
|
||||
previewClickLog = clickLog
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(10.dp)) {
|
||||
Row {
|
||||
Text(
|
||||
text = clickLog.id.format("MM-dd HH:mm:ss"),
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text(
|
||||
text = appInfoCache[clickLog.appId]?.name ?: clickLog.appId ?: ""
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
val showActivityId = if (clickLog.activityId != null) {
|
||||
if (clickLog.appId != null && clickLog.activityId.startsWith(
|
||||
clickLog.appId
|
||||
)
|
||||
) {
|
||||
clickLog.activityId.substring(clickLog.appId.length)
|
||||
} else {
|
||||
clickLog.activityId
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (showActivityId != null) {
|
||||
Text(
|
||||
text = showActivityId,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
if (group?.name != null) {
|
||||
Text(text = group.name)
|
||||
}
|
||||
if (rule?.name != null) {
|
||||
Text(text = rule.name ?: "")
|
||||
} else if ((group?.rules?.size ?: 0) > 1) {
|
||||
Text(text = (if (clickLog.ruleKey != null) "key=${clickLog.ruleKey}, " else "") + "index=${clickLog.ruleIndex}")
|
||||
}
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
) {
|
||||
items(
|
||||
count = clickDataItems.itemCount,
|
||||
key = clickDataItems.itemKey { c -> c.t0.id }
|
||||
) { i ->
|
||||
val (clickLog, group, rule) = clickDataItems[i] ?: return@items
|
||||
Column(modifier = Modifier
|
||||
.clickable {
|
||||
previewClickLog = clickLog
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(10.dp)) {
|
||||
Row {
|
||||
Text(
|
||||
text = clickLog.id.format("MM-dd HH:mm:ss"),
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text(
|
||||
text = appInfoCache[clickLog.appId]?.name ?: clickLog.appId ?: ""
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
val showActivityId = if (clickLog.activityId != null) {
|
||||
if (clickLog.appId != null && clickLog.activityId.startsWith(
|
||||
clickLog.appId
|
||||
)
|
||||
) {
|
||||
clickLog.activityId.substring(clickLog.appId.length)
|
||||
} else {
|
||||
clickLog.activityId
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (showActivityId != null) {
|
||||
Text(
|
||||
text = showActivityId,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
if (group?.name != null) {
|
||||
Text(text = group.name)
|
||||
}
|
||||
if (rule?.name != null) {
|
||||
Text(text = rule.name ?: "")
|
||||
} else if ((group?.rules?.size ?: 0) > 1) {
|
||||
Text(text = (if (clickLog.ruleKey != null) "key=${clickLog.ruleKey}, " else "") + "index=${clickLog.ruleIndex}")
|
||||
}
|
||||
HorizontalDivider()
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
HorizontalDivider()
|
||||
}
|
||||
} else {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(contentPadding)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(40.dp))
|
||||
Text(text = "暂无记录")
|
||||
if (clickLogCount == 0) {
|
||||
Text(
|
||||
text = "暂无记录",
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -214,124 +220,121 @@ fun ClickLogPage() {
|
|||
}
|
||||
val appInfo = appInfoCache[clickLog.appId]
|
||||
|
||||
Column {
|
||||
Text(text = "查看规则组", modifier = Modifier
|
||||
.clickable {
|
||||
clickLog.appId ?: return@clickable
|
||||
if (clickLog.groupType == SubsConfig.AppGroupType) {
|
||||
navController.navigate(
|
||||
AppItemPageDestination(
|
||||
clickLog.subsId, clickLog.appId, clickLog.groupKey
|
||||
)
|
||||
Text(text = "查看规则组", modifier = Modifier
|
||||
.clickable {
|
||||
clickLog.appId ?: return@clickable
|
||||
if (clickLog.groupType == SubsConfig.AppGroupType) {
|
||||
navController.navigate(
|
||||
AppItemPageDestination(
|
||||
clickLog.subsId, clickLog.appId, clickLog.groupKey
|
||||
)
|
||||
} else if (clickLog.groupType == SubsConfig.GlobalGroupType) {
|
||||
navController.navigate(
|
||||
GlobalRulePageDestination(
|
||||
clickLog.subsId, clickLog.groupKey
|
||||
)
|
||||
)
|
||||
}
|
||||
previewClickLog = null
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
if (clickLog.groupType == SubsConfig.GlobalGroupType && clickLog.appId != null) {
|
||||
val group =
|
||||
subsIdToRaw[clickLog.subsId]?.globalGroups?.find { g -> g.key == clickLog.groupKey }
|
||||
val appChecked = if (group != null) {
|
||||
getChecked(
|
||||
oldExclude,
|
||||
group,
|
||||
clickLog.appId,
|
||||
appInfo
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (appChecked != null) {
|
||||
Text(
|
||||
text = if (appChecked) "在此应用禁用" else "移除在此应用的禁用",
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
onClick = vm.viewModelScope.launchAsFn(
|
||||
Dispatchers.IO
|
||||
) {
|
||||
val subsConfig = previewConfig ?: SubsConfig(
|
||||
type = SubsConfig.GlobalGroupType,
|
||||
subsItemId = clickLog.subsId,
|
||||
groupKey = clickLog.groupKey,
|
||||
)
|
||||
val newSubsConfig = subsConfig.copy(
|
||||
exclude = oldExclude
|
||||
.copy(
|
||||
appIds = oldExclude.appIds
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
set(clickLog.appId, appChecked)
|
||||
})
|
||||
.stringify()
|
||||
)
|
||||
DbSet.subsConfigDao.insert(newSubsConfig)
|
||||
toast("更新禁用")
|
||||
})
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
} else if (clickLog.groupType == SubsConfig.GlobalGroupType) {
|
||||
navController.navigate(
|
||||
GlobalRulePageDestination(
|
||||
clickLog.subsId, clickLog.groupKey
|
||||
)
|
||||
)
|
||||
}
|
||||
previewClickLog = null
|
||||
}
|
||||
if (clickLog.appId != null && clickLog.activityId != null) {
|
||||
val disabled =
|
||||
oldExclude.activityIds.contains(clickLog.appId to clickLog.activityId)
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
if (clickLog.groupType == SubsConfig.GlobalGroupType && clickLog.appId != null) {
|
||||
val group =
|
||||
subsIdToRaw[clickLog.subsId]?.globalGroups?.find { g -> g.key == clickLog.groupKey }
|
||||
val appChecked = if (group != null) {
|
||||
getChecked(
|
||||
oldExclude,
|
||||
group,
|
||||
clickLog.appId,
|
||||
appInfo
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
if (appChecked != null) {
|
||||
Text(
|
||||
text = if (disabled) "移除在此页面的禁用" else "在此页面禁用",
|
||||
text = if (appChecked) "在此应用禁用" else "移除在此应用的禁用",
|
||||
modifier = Modifier
|
||||
.clickable(onClick = vm.viewModelScope.launchAsFn(Dispatchers.IO) {
|
||||
val subsConfig =
|
||||
if (clickLog.groupType == SubsConfig.AppGroupType) {
|
||||
previewConfig ?: SubsConfig(
|
||||
type = SubsConfig.AppGroupType,
|
||||
subsItemId = clickLog.subsId,
|
||||
appId = clickLog.appId,
|
||||
groupKey = clickLog.groupKey,
|
||||
)
|
||||
} else {
|
||||
previewConfig ?: SubsConfig(
|
||||
type = SubsConfig.GlobalGroupType,
|
||||
subsItemId = clickLog.subsId,
|
||||
groupKey = clickLog.groupKey,
|
||||
)
|
||||
}
|
||||
val newSubsConfig = subsConfig.copy(
|
||||
exclude = oldExclude
|
||||
.switch(
|
||||
clickLog.appId,
|
||||
clickLog.activityId
|
||||
)
|
||||
.stringify()
|
||||
)
|
||||
DbSet.subsConfigDao.insert(newSubsConfig)
|
||||
toast("更新禁用")
|
||||
})
|
||||
.clickable(
|
||||
onClick = vm.viewModelScope.launchAsFn(
|
||||
Dispatchers.IO
|
||||
) {
|
||||
val subsConfig = previewConfig ?: SubsConfig(
|
||||
type = SubsConfig.GlobalGroupType,
|
||||
subsItemId = clickLog.subsId,
|
||||
groupKey = clickLog.groupKey,
|
||||
)
|
||||
val newSubsConfig = subsConfig.copy(
|
||||
exclude = oldExclude
|
||||
.copy(
|
||||
appIds = oldExclude.appIds
|
||||
.toMutableMap()
|
||||
.apply {
|
||||
set(clickLog.appId, appChecked)
|
||||
})
|
||||
.stringify()
|
||||
)
|
||||
DbSet.subsConfigDao.insert(newSubsConfig)
|
||||
toast("更新禁用")
|
||||
})
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
if (clickLog.appId != null && clickLog.activityId != null) {
|
||||
val disabled =
|
||||
oldExclude.activityIds.contains(clickLog.appId to clickLog.activityId)
|
||||
Text(
|
||||
text = "删除记录",
|
||||
text = if (disabled) "移除在此页面的禁用" else "在此页面禁用",
|
||||
modifier = Modifier
|
||||
.clickable(onClick = scope.launchAsFn {
|
||||
previewClickLog = null
|
||||
DbSet.clickLogDao.delete(clickLog)
|
||||
toast("删除成功")
|
||||
.clickable(onClick = vm.viewModelScope.launchAsFn(Dispatchers.IO) {
|
||||
val subsConfig =
|
||||
if (clickLog.groupType == SubsConfig.AppGroupType) {
|
||||
previewConfig ?: SubsConfig(
|
||||
type = SubsConfig.AppGroupType,
|
||||
subsItemId = clickLog.subsId,
|
||||
appId = clickLog.appId,
|
||||
groupKey = clickLog.groupKey,
|
||||
)
|
||||
} else {
|
||||
previewConfig ?: SubsConfig(
|
||||
type = SubsConfig.GlobalGroupType,
|
||||
subsItemId = clickLog.subsId,
|
||||
groupKey = clickLog.groupKey,
|
||||
)
|
||||
}
|
||||
val newSubsConfig = subsConfig.copy(
|
||||
exclude = oldExclude
|
||||
.switch(
|
||||
clickLog.appId,
|
||||
clickLog.activityId
|
||||
)
|
||||
.stringify()
|
||||
)
|
||||
DbSet.subsConfigDao.insert(newSubsConfig)
|
||||
toast("更新禁用")
|
||||
})
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Text(
|
||||
text = "删除记录",
|
||||
modifier = Modifier
|
||||
.clickable(onClick = scope.launchAsFn {
|
||||
previewClickLog = null
|
||||
DbSet.clickLogDao.delete(clickLog)
|
||||
toast("删除成功")
|
||||
})
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,10 @@ package li.songe.gkd.ui
|
|||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.cachedIn
|
||||
import androidx.paging.map
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
|
@ -15,9 +19,10 @@ import javax.inject.Inject
|
|||
@HiltViewModel
|
||||
class ClickLogVm @Inject constructor() : ViewModel() {
|
||||
|
||||
val clickDataListFlow =
|
||||
combine(DbSet.clickLogDao.query(), subsIdToRawFlow) { clickLogs, subsIdToRaw ->
|
||||
clickLogs.map { c ->
|
||||
val pagingDataFlow = Pager(PagingConfig(pageSize = 100)) { DbSet.clickLogDao.pagingSource() }
|
||||
.flow.cachedIn(viewModelScope)
|
||||
.combine(subsIdToRawFlow) { pagingData, subsIdToRaw ->
|
||||
pagingData.map { c ->
|
||||
val group = if (c.groupType == SubsConfig.AppGroupType) {
|
||||
val app = subsIdToRaw[c.subsId]?.apps?.find { a -> a.id == c.appId }
|
||||
app?.groups?.find { g -> g.key == c.groupKey }
|
||||
|
@ -33,7 +38,28 @@ class ClickLogVm @Inject constructor() : ViewModel() {
|
|||
}
|
||||
Tuple3(c, group, rule)
|
||||
}
|
||||
}.stateIn(viewModelScope, SharingStarted.Eagerly, emptyList())
|
||||
}
|
||||
|
||||
|
||||
// val clickDataListFlow =
|
||||
// combine(DbSet.clickLogDao.query(), subsIdToRawFlow) { clickLogs, subsIdToRaw ->
|
||||
// clickLogs.map { c ->
|
||||
// val group = if (c.groupType == SubsConfig.AppGroupType) {
|
||||
// val app = subsIdToRaw[c.subsId]?.apps?.find { a -> a.id == c.appId }
|
||||
// app?.groups?.find { g -> g.key == c.groupKey }
|
||||
// } else {
|
||||
// subsIdToRaw[c.subsId]?.globalGroups?.find { g -> g.key == c.groupKey }
|
||||
// }
|
||||
// val rule = group?.rules?.run {
|
||||
// if (c.ruleKey != null) {
|
||||
// find { r -> r.key == c.ruleKey }
|
||||
// } else {
|
||||
// getOrNull(c.ruleIndex)
|
||||
// }
|
||||
// }
|
||||
// Tuple3(c, group, rule)
|
||||
// }
|
||||
// }.stateIn(viewModelScope, SharingStarted.Eagerly, emptyList())
|
||||
|
||||
val clickLogCountFlow =
|
||||
DbSet.clickLogDao.count().stateIn(viewModelScope, SharingStarted.Eagerly, 0)
|
||||
|
|
|
@ -122,7 +122,7 @@ fun GlobalRuleExcludePage(subsItemId: Long, groupKey: Int) {
|
|||
AppBarTextField(
|
||||
value = searchStr,
|
||||
onValueChange = { newValue -> vm.searchStrFlow.value = newValue.trim() },
|
||||
hint = "请输入应用名称",
|
||||
hint = "请输入应用名称/ID",
|
||||
modifier = Modifier.focusRequester(focusRequester)
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -272,50 +272,48 @@ fun GlobalRulePage(subsItemId: Long, focusGroupKey: Int? = null) {
|
|||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column {
|
||||
Text(text = "编辑禁用", modifier = Modifier
|
||||
.clickable {
|
||||
setMenuGroupRaw(null)
|
||||
navController.navigate(
|
||||
GlobalRuleExcludePageDestination(
|
||||
subsItemId,
|
||||
menuGroupRaw.key
|
||||
)
|
||||
Text(text = "编辑禁用", modifier = Modifier
|
||||
.clickable {
|
||||
setMenuGroupRaw(null)
|
||||
navController.navigate(
|
||||
GlobalRuleExcludePageDestination(
|
||||
subsItemId,
|
||||
menuGroupRaw.key
|
||||
)
|
||||
)
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth())
|
||||
if (editable) {
|
||||
Text(text = "编辑规则组", modifier = Modifier
|
||||
.clickable {
|
||||
setEditGroupRaw(menuGroupRaw)
|
||||
setMenuGroupRaw(null)
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth())
|
||||
if (editable) {
|
||||
Text(text = "编辑规则组", modifier = Modifier
|
||||
.clickable {
|
||||
setEditGroupRaw(menuGroupRaw)
|
||||
setMenuGroupRaw(null)
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth())
|
||||
Text(text = "删除规则组", modifier = Modifier
|
||||
.clickable {
|
||||
setMenuGroupRaw(null)
|
||||
vm.viewModelScope.launchTry {
|
||||
if (!getDialogResult("是否删除${menuGroupRaw.name}")) return@launchTry
|
||||
updateSubscription(
|
||||
rawSubs.copy(
|
||||
globalGroups = rawSubs.globalGroups.filter { g -> g.key != menuGroupRaw.key }
|
||||
)
|
||||
Text(text = "删除规则组", modifier = Modifier
|
||||
.clickable {
|
||||
setMenuGroupRaw(null)
|
||||
vm.viewModelScope.launchTry {
|
||||
if (!getDialogResult("是否删除${menuGroupRaw.name}")) return@launchTry
|
||||
updateSubscription(
|
||||
rawSubs.copy(
|
||||
globalGroups = rawSubs.globalGroups.filter { g -> g.key != menuGroupRaw.key }
|
||||
)
|
||||
val subsConfig =
|
||||
subsConfigs.find { it.groupKey == menuGroupRaw.key }
|
||||
if (subsConfig != null) {
|
||||
DbSet.subsConfigDao.delete(subsConfig)
|
||||
}
|
||||
DbSet.subsItemDao.updateMtime(rawSubs.id)
|
||||
)
|
||||
val subsConfig =
|
||||
subsConfigs.find { it.groupKey == menuGroupRaw.key }
|
||||
if (subsConfig != null) {
|
||||
DbSet.subsConfigDao.delete(subsConfig)
|
||||
}
|
||||
DbSet.subsItemDao.updateMtime(rawSubs.id)
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth(),
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth(),
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,11 +37,11 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
|
@ -123,63 +123,59 @@ fun SnapshotPage() {
|
|||
}
|
||||
})
|
||||
}, content = { contentPadding ->
|
||||
if (snapshots.isNotEmpty()) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
) {
|
||||
items(snapshots, { it.id }) { snapshot ->
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
selectedSnapshot = snapshot
|
||||
}
|
||||
.padding(10.dp)) {
|
||||
Row {
|
||||
Text(
|
||||
text = snapshot.id.format("MM-dd HH:mm:ss"),
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text(
|
||||
text = snapshot.appName ?: snapshot.appId ?: snapshot.id.toString(),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
if (snapshot.activityId != null) {
|
||||
val showActivityId =
|
||||
if (snapshot.appId != null && snapshot.activityId.startsWith(
|
||||
snapshot.appId
|
||||
)
|
||||
) {
|
||||
snapshot.activityId.substring(snapshot.appId.length)
|
||||
} else {
|
||||
snapshot.activityId
|
||||
}
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text(
|
||||
text = showActivityId, overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
) {
|
||||
items(snapshots, { it.id }) { snapshot ->
|
||||
Column(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
selectedSnapshot = snapshot
|
||||
}
|
||||
.padding(10.dp)) {
|
||||
Row {
|
||||
Text(
|
||||
text = snapshot.id.format("MM-dd HH:mm:ss"),
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text(
|
||||
text = snapshot.appName ?: snapshot.appId ?: snapshot.id.toString(),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
if (snapshot.activityId != null) {
|
||||
val showActivityId =
|
||||
if (snapshot.appId != null && snapshot.activityId.startsWith(
|
||||
snapshot.appId
|
||||
)
|
||||
) {
|
||||
snapshot.activityId.substring(snapshot.appId.length)
|
||||
} else {
|
||||
snapshot.activityId
|
||||
}
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Text(
|
||||
text = showActivityId, overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
HorizontalDivider()
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
HorizontalDivider()
|
||||
}
|
||||
} else {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(contentPadding)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(40.dp))
|
||||
Text(text = "暂无记录")
|
||||
if (snapshots.isEmpty()) {
|
||||
Text(
|
||||
text = "暂无记录",
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
selectedSnapshot?.let { snapshotVal ->
|
||||
|
@ -190,121 +186,119 @@ fun SnapshotPage() {
|
|||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column {
|
||||
val modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
Text(
|
||||
text = "查看", modifier = Modifier
|
||||
.clickable(onClick = scope.launchAsFn {
|
||||
navController.navigate(
|
||||
ImagePreviewPageDestination(
|
||||
filePath = snapshotVal.screenshotFile.absolutePath,
|
||||
title = snapshotVal.appName,
|
||||
)
|
||||
val modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
Text(
|
||||
text = "查看", modifier = Modifier
|
||||
.clickable(onClick = scope.launchAsFn {
|
||||
navController.navigate(
|
||||
ImagePreviewPageDestination(
|
||||
filePath = snapshotVal.screenshotFile.absolutePath,
|
||||
title = snapshotVal.appName,
|
||||
)
|
||||
)
|
||||
selectedSnapshot = null
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
HorizontalDivider()
|
||||
Text(
|
||||
text = "分享",
|
||||
modifier = Modifier
|
||||
.clickable(onClick = vm.viewModelScope.launchAsFn {
|
||||
val zipFile = SnapshotExt.getSnapshotZipFile(snapshotVal.id)
|
||||
context.shareFile(zipFile, "分享快照文件")
|
||||
selectedSnapshot = null
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
HorizontalDivider()
|
||||
if (snapshotVal.githubAssetId != null) {
|
||||
Text(
|
||||
text = "复制链接", modifier = Modifier
|
||||
.clickable(onClick = {
|
||||
selectedSnapshot = null
|
||||
ClipboardUtils.copyText(IMPORT_BASE_URL + snapshotVal.githubAssetId)
|
||||
toast("复制成功")
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
HorizontalDivider()
|
||||
} else {
|
||||
Text(
|
||||
text = "分享",
|
||||
modifier = Modifier
|
||||
.clickable(onClick = vm.viewModelScope.launchAsFn {
|
||||
val zipFile = SnapshotExt.getSnapshotZipFile(snapshotVal.id)
|
||||
context.shareFile(zipFile, "分享快照文件")
|
||||
text = "生成链接(需科学上网)", modifier = Modifier
|
||||
.clickable(onClick = {
|
||||
selectedSnapshot = null
|
||||
vm.uploadZip(snapshotVal)
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
HorizontalDivider()
|
||||
if (snapshotVal.githubAssetId != null) {
|
||||
Text(
|
||||
text = "复制链接", modifier = Modifier
|
||||
.clickable(onClick = {
|
||||
selectedSnapshot = null
|
||||
ClipboardUtils.copyText(IMPORT_BASE_URL + snapshotVal.githubAssetId)
|
||||
toast("复制成功")
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
text = "生成链接(需科学上网)", modifier = Modifier
|
||||
.clickable(onClick = {
|
||||
selectedSnapshot = null
|
||||
vm.uploadZip(snapshotVal)
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
}
|
||||
HorizontalDivider()
|
||||
|
||||
Text(
|
||||
text = "保存截图到相册",
|
||||
modifier = Modifier
|
||||
.clickable(onClick = vm.viewModelScope.launchAsFn {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
val isGranted =
|
||||
requestPermissionLauncher.launchForResult(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
if (!isGranted) {
|
||||
toast("保存失败,暂无权限")
|
||||
return@launchAsFn
|
||||
}
|
||||
}
|
||||
ImageUtils.save2Album(
|
||||
ImageUtils.getBitmap(snapshotVal.screenshotFile),
|
||||
Bitmap.CompressFormat.PNG,
|
||||
true
|
||||
)
|
||||
toast("保存成功")
|
||||
selectedSnapshot = null
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
HorizontalDivider()
|
||||
Text(
|
||||
text = "替换截图(去除隐私)",
|
||||
modifier = Modifier
|
||||
.clickable(onClick = vm.viewModelScope.launchAsFn {
|
||||
val uri = pickContentLauncher.launchForImageResult()
|
||||
withContext(Dispatchers.IO) {
|
||||
val oldBitmap = ImageUtils.getBitmap(snapshotVal.screenshotFile)
|
||||
val newBytes = UriUtils.uri2Bytes(uri)
|
||||
val newBitmap = ImageUtils.getBitmap(newBytes, 0)
|
||||
if (oldBitmap.width == newBitmap.width && oldBitmap.height == newBitmap.height) {
|
||||
snapshotVal.screenshotFile.writeBytes(newBytes)
|
||||
File(snapshotZipDir, "${snapshotVal.id}.zip").apply {
|
||||
if (exists()) delete()
|
||||
}
|
||||
if (snapshotVal.githubAssetId != null) {
|
||||
// 当本地快照变更时, 移除快照链接
|
||||
DbSet.snapshotDao.update(snapshotVal.copy(githubAssetId = null))
|
||||
}
|
||||
} else {
|
||||
toast("截图尺寸不一致,无法替换")
|
||||
return@withContext
|
||||
}
|
||||
}
|
||||
toast("替换成功")
|
||||
selectedSnapshot = null
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
HorizontalDivider()
|
||||
Text(
|
||||
text = "删除", modifier = Modifier
|
||||
.clickable(onClick = scope.launchAsFn {
|
||||
DbSet.snapshotDao.delete(snapshotVal)
|
||||
withContext(Dispatchers.IO) {
|
||||
SnapshotExt.removeAssets(snapshotVal.id)
|
||||
}
|
||||
selectedSnapshot = null
|
||||
})
|
||||
.then(modifier), color = colorScheme.error
|
||||
)
|
||||
}
|
||||
HorizontalDivider()
|
||||
|
||||
Text(
|
||||
text = "保存截图到相册",
|
||||
modifier = Modifier
|
||||
.clickable(onClick = vm.viewModelScope.launchAsFn {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
val isGranted =
|
||||
requestPermissionLauncher.launchForResult(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
if (!isGranted) {
|
||||
toast("保存失败,暂无权限")
|
||||
return@launchAsFn
|
||||
}
|
||||
}
|
||||
ImageUtils.save2Album(
|
||||
ImageUtils.getBitmap(snapshotVal.screenshotFile),
|
||||
Bitmap.CompressFormat.PNG,
|
||||
true
|
||||
)
|
||||
toast("保存成功")
|
||||
selectedSnapshot = null
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
HorizontalDivider()
|
||||
Text(
|
||||
text = "替换截图(去除隐私)",
|
||||
modifier = Modifier
|
||||
.clickable(onClick = vm.viewModelScope.launchAsFn {
|
||||
val uri = pickContentLauncher.launchForImageResult()
|
||||
withContext(Dispatchers.IO) {
|
||||
val oldBitmap = ImageUtils.getBitmap(snapshotVal.screenshotFile)
|
||||
val newBytes = UriUtils.uri2Bytes(uri)
|
||||
val newBitmap = ImageUtils.getBitmap(newBytes, 0)
|
||||
if (oldBitmap.width == newBitmap.width && oldBitmap.height == newBitmap.height) {
|
||||
snapshotVal.screenshotFile.writeBytes(newBytes)
|
||||
File(snapshotZipDir, "${snapshotVal.id}.zip").apply {
|
||||
if (exists()) delete()
|
||||
}
|
||||
if (snapshotVal.githubAssetId != null) {
|
||||
// 当本地快照变更时, 移除快照链接
|
||||
DbSet.snapshotDao.update(snapshotVal.copy(githubAssetId = null))
|
||||
}
|
||||
} else {
|
||||
toast("截图尺寸不一致,无法替换")
|
||||
return@withContext
|
||||
}
|
||||
}
|
||||
toast("替换成功")
|
||||
selectedSnapshot = null
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
HorizontalDivider()
|
||||
Text(
|
||||
text = "删除", modifier = Modifier
|
||||
.clickable(onClick = scope.launchAsFn {
|
||||
DbSet.snapshotDao.delete(snapshotVal)
|
||||
withContext(Dispatchers.IO) {
|
||||
SnapshotExt.removeAssets(snapshotVal.id)
|
||||
}
|
||||
selectedSnapshot = null
|
||||
})
|
||||
.then(modifier), color = colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package li.songe.gkd.ui
|
|||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
@ -50,6 +49,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
|
@ -145,7 +145,7 @@ fun SubsPage(
|
|||
AppBarTextField(
|
||||
value = searchStr,
|
||||
onValueChange = { newValue -> vm.searchStrFlow.value = newValue.trim() },
|
||||
hint = "请输入应用名称",
|
||||
hint = "请输入应用名称/ID",
|
||||
modifier = Modifier.focusRequester(focusRequester)
|
||||
)
|
||||
} else {
|
||||
|
@ -265,24 +265,15 @@ fun SubsPage(
|
|||
})
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(40.dp))
|
||||
if (appAndConfigs.isEmpty()) {
|
||||
Spacer(modifier = Modifier.height(40.dp))
|
||||
Column(
|
||||
Text(
|
||||
text = if (searchStr.isNotEmpty()) "暂无搜索结果" else "暂无规则",
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
if (searchStr.isNotEmpty()) {
|
||||
Text(text = "暂无搜索结果")
|
||||
} else {
|
||||
Text(text = "暂无规则")
|
||||
}
|
||||
}
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,31 +422,29 @@ fun SubsPage(
|
|||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column {
|
||||
Text(text = "复制", modifier = Modifier
|
||||
.clickable {
|
||||
ClipboardUtils.copyText(
|
||||
json.encodeToJson5String(menuAppRawVal)
|
||||
)
|
||||
toast("复制成功")
|
||||
menuRawApp = null
|
||||
Text(text = "复制", modifier = Modifier
|
||||
.clickable {
|
||||
ClipboardUtils.copyText(
|
||||
json.encodeToJson5String(menuAppRawVal)
|
||||
)
|
||||
toast("复制成功")
|
||||
menuRawApp = null
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
Text(text = "删除", modifier = Modifier
|
||||
.clickable {
|
||||
// 也许需要二次确认
|
||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||
updateSubscription(subsRaw.copy(apps = subsRaw.apps.filter { a -> a.id != menuAppRawVal.id }))
|
||||
DbSet.subsItemDao.update(subsItemVal.copy(mtime = System.currentTimeMillis()))
|
||||
DbSet.subsConfigDao.delete(subsItemVal.id, menuAppRawVal.id)
|
||||
toast("删除成功")
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
Text(text = "删除", modifier = Modifier
|
||||
.clickable {
|
||||
// 也许需要二次确认
|
||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||
updateSubscription(subsRaw.copy(apps = subsRaw.apps.filter { a -> a.id != menuAppRawVal.id }))
|
||||
DbSet.subsItemDao.update(subsItemVal.copy(mtime = System.currentTimeMillis()))
|
||||
DbSet.subsConfigDao.delete(subsItemVal.id, menuAppRawVal.id)
|
||||
toast("删除成功")
|
||||
}
|
||||
menuRawApp = null
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp), color = MaterialTheme.colorScheme.error)
|
||||
}
|
||||
menuRawApp = null
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp), color = MaterialTheme.colorScheme.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ import androidx.compose.ui.draw.clip
|
|||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
|
@ -106,7 +107,7 @@ fun useAppListPage(): ScaffoldExt {
|
|||
AppBarTextField(
|
||||
value = searchStr,
|
||||
onValueChange = { newValue -> vm.searchStrFlow.value = newValue.trim() },
|
||||
hint = "请输入应用名称",
|
||||
hint = "请输入应用名称/ID",
|
||||
modifier = Modifier.focusRequester(focusRequester)
|
||||
)
|
||||
} else {
|
||||
|
@ -280,6 +281,16 @@ fun useAppListPage(): ScaffoldExt {
|
|||
}
|
||||
}
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(40.dp))
|
||||
if (orderedAppInfos.isEmpty() && searchStr.isNotEmpty()) {
|
||||
Text(
|
||||
text = "暂无搜索结果",
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -102,29 +102,27 @@ fun useSettingsPage(): ScaffoldExt {
|
|||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column {
|
||||
updateTimeRadioOptions.forEach { option ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.selectable(selected = (option.second == store.updateSubsInterval),
|
||||
onClick = {
|
||||
storeFlow.value =
|
||||
store.copy(updateSubsInterval = option.second)
|
||||
|
||||
})
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
RadioButton(
|
||||
selected = (option.second == store.updateSubsInterval),
|
||||
updateTimeRadioOptions.forEach { option ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.selectable(selected = (option.second == store.updateSubsInterval),
|
||||
onClick = {
|
||||
storeFlow.value = store.copy(updateSubsInterval = option.second)
|
||||
storeFlow.value =
|
||||
store.copy(updateSubsInterval = option.second)
|
||||
|
||||
})
|
||||
Text(
|
||||
text = option.first, modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
RadioButton(
|
||||
selected = (option.second == store.updateSubsInterval),
|
||||
onClick = {
|
||||
storeFlow.value = store.copy(updateSubsInterval = option.second)
|
||||
})
|
||||
Text(
|
||||
text = option.first, modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -139,28 +137,26 @@ fun useSettingsPage(): ScaffoldExt {
|
|||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column {
|
||||
darkThemeRadioOptions.forEach { option ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.selectable(selected = (option.second == store.enableDarkTheme),
|
||||
onClick = {
|
||||
storeFlow.value =
|
||||
store.copy(enableDarkTheme = option.second)
|
||||
})
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
RadioButton(
|
||||
selected = (option.second == store.enableDarkTheme),
|
||||
darkThemeRadioOptions.forEach { option ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.selectable(selected = (option.second == store.enableDarkTheme),
|
||||
onClick = {
|
||||
storeFlow.value = store.copy(enableDarkTheme = option.second)
|
||||
storeFlow.value =
|
||||
store.copy(enableDarkTheme = option.second)
|
||||
})
|
||||
Text(
|
||||
text = option.first, modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
.padding(horizontal = 16.dp)
|
||||
) {
|
||||
RadioButton(
|
||||
selected = (option.second == store.enableDarkTheme),
|
||||
onClick = {
|
||||
storeFlow.value = store.copy(enableDarkTheme = option.second)
|
||||
})
|
||||
Text(
|
||||
text = option.first, modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -215,49 +211,47 @@ fun useSettingsPage(): ScaffoldExt {
|
|||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column {
|
||||
val modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
Text(
|
||||
text = "调用系统分享", modifier = Modifier
|
||||
.clickable(onClick = {
|
||||
showShareLogDlg = false
|
||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||
val logZipFile = File(logZipDir, "log.zip")
|
||||
ZipUtils.zipFiles(LogUtils.getLogFiles(), logZipFile)
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context, "${context.packageName}.provider", logZipFile
|
||||
)
|
||||
val intent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
type = "application/zip"
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(
|
||||
Intent.createChooser(
|
||||
intent, "分享日志文件"
|
||||
)
|
||||
)
|
||||
val modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
Text(
|
||||
text = "调用系统分享", modifier = Modifier
|
||||
.clickable(onClick = {
|
||||
showShareLogDlg = false
|
||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||
val logZipFile = File(logZipDir, "log.zip")
|
||||
ZipUtils.zipFiles(LogUtils.getLogFiles(), logZipFile)
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context, "${context.packageName}.provider", logZipFile
|
||||
)
|
||||
val intent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
type = "application/zip"
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
Text(
|
||||
text = "生成链接(需科学上网)", modifier = Modifier
|
||||
.clickable(onClick = {
|
||||
showShareLogDlg = false
|
||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||
val logZipFile = File(logZipDir, "log.zip")
|
||||
ZipUtils.zipFiles(LogUtils.getLogFiles(), logZipFile)
|
||||
vm.uploadZip(logZipFile)
|
||||
}
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
}
|
||||
context.startActivity(
|
||||
Intent.createChooser(
|
||||
intent, "分享日志文件"
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
Text(
|
||||
text = "生成链接(需科学上网)", modifier = Modifier
|
||||
.clickable(onClick = {
|
||||
showShareLogDlg = false
|
||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||
val logZipFile = File(logZipDir, "log.zip")
|
||||
ZipUtils.zipFiles(LogUtils.getLogFiles(), logZipFile)
|
||||
vm.uploadZip(logZipFile)
|
||||
}
|
||||
})
|
||||
.then(modifier)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ import android.webkit.URLUtil
|
|||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
@ -22,6 +22,7 @@ import androidx.compose.material.icons.automirrored.filled.FormatListBulleted
|
|||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
|
@ -114,83 +115,81 @@ fun useSubsManagePage(): ScaffoldExt {
|
|||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column {
|
||||
val subsRawVal = subsIdToRaw[menuSubItemVal.id]
|
||||
if (subsRawVal != null) {
|
||||
Text(text = "应用规则", modifier = Modifier
|
||||
.clickable {
|
||||
menuSubItem = null
|
||||
navController.navigate(SubsPageDestination(subsRawVal.id))
|
||||
val subsRawVal = subsIdToRaw[menuSubItemVal.id]
|
||||
if (subsRawVal != null) {
|
||||
Text(text = "应用规则", modifier = Modifier
|
||||
.clickable {
|
||||
menuSubItem = null
|
||||
navController.navigate(SubsPageDestination(subsRawVal.id))
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
Text(text = "查看类别", modifier = Modifier
|
||||
.clickable {
|
||||
menuSubItem = null
|
||||
navController.navigate(CategoryPageDestination(subsRawVal.id))
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
Text(text = "全局规则", modifier = Modifier
|
||||
.clickable {
|
||||
menuSubItem = null
|
||||
navController.navigate(GlobalRulePageDestination(subsRawVal.id))
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
}
|
||||
if (menuSubItemVal.id < 0 && subsRawVal != null) {
|
||||
Text(text = "分享文件", modifier = Modifier
|
||||
.clickable {
|
||||
menuSubItem = null
|
||||
vm.viewModelScope.launchTry {
|
||||
val subsFile = subsFolder.resolve("${menuSubItemVal.id}.json")
|
||||
context.shareFile(subsFile, "分享订阅文件")
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
Text(text = "查看类别", modifier = Modifier
|
||||
.clickable {
|
||||
menuSubItem = null
|
||||
navController.navigate(CategoryPageDestination(subsRawVal.id))
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
Text(text = "全局规则", modifier = Modifier
|
||||
.clickable {
|
||||
menuSubItem = null
|
||||
navController.navigate(GlobalRulePageDestination(subsRawVal.id))
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
}
|
||||
if (menuSubItemVal.id < 0 && subsRawVal != null) {
|
||||
Text(text = "分享文件", modifier = Modifier
|
||||
.clickable {
|
||||
menuSubItem = null
|
||||
vm.viewModelScope.launchTry {
|
||||
val subsFile = subsFolder.resolve("${menuSubItemVal.id}.json")
|
||||
context.shareFile(subsFile, "分享订阅文件")
|
||||
}
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
}
|
||||
if (menuSubItemVal.updateUrl != null) {
|
||||
Text(text = "复制链接", modifier = Modifier
|
||||
.clickable {
|
||||
menuSubItem = null
|
||||
ClipboardUtils.copyText(menuSubItemVal.updateUrl)
|
||||
toast("复制成功")
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
}
|
||||
if (subsRawVal?.supportUri != null) {
|
||||
Text(text = "问题反馈", modifier = Modifier
|
||||
.clickable {
|
||||
menuSubItem = null
|
||||
context.startActivity(
|
||||
Intent(
|
||||
Intent.ACTION_VIEW, Uri.parse(subsRawVal.supportUri)
|
||||
)
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
}
|
||||
if (menuSubItemVal.updateUrl != null) {
|
||||
Text(text = "复制链接", modifier = Modifier
|
||||
.clickable {
|
||||
menuSubItem = null
|
||||
ClipboardUtils.copyText(menuSubItemVal.updateUrl)
|
||||
toast("复制成功")
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
}
|
||||
if (subsRawVal?.supportUri != null) {
|
||||
Text(text = "问题反馈", modifier = Modifier
|
||||
.clickable {
|
||||
menuSubItem = null
|
||||
context.startActivity(
|
||||
Intent(
|
||||
Intent.ACTION_VIEW, Uri.parse(subsRawVal.supportUri)
|
||||
)
|
||||
)
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
}
|
||||
if (menuSubItemVal.id != -2L) {
|
||||
Text(text = "删除订阅",
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
deleteSubItem = menuSubItemVal
|
||||
menuSubItem = null
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp))
|
||||
HorizontalDivider()
|
||||
}
|
||||
if (menuSubItemVal.id != -2L) {
|
||||
Text(text = "删除订阅",
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
deleteSubItem = menuSubItemVal
|
||||
menuSubItem = null
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
color = MaterialTheme.colorScheme.error)
|
||||
}
|
||||
.padding(16.dp),
|
||||
color = MaterialTheme.colorScheme.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -291,35 +290,39 @@ fun useSubsManagePage(): ScaffoldExt {
|
|||
if (isDragging) 1.dp else 0.dp,
|
||||
label = "width",
|
||||
)
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
Card(
|
||||
onClick = { menuSubItem = subItem },
|
||||
modifier = Modifier
|
||||
.longPressDraggableHandle(onDragStopped = {
|
||||
val changeItems = mutableListOf<SubsItem>()
|
||||
orderSubItems.forEachIndexed { i, subsItem ->
|
||||
if (subItems[i] != subsItem) {
|
||||
changeItems.add(
|
||||
subsItem.copy(
|
||||
order = i
|
||||
.longPressDraggableHandle(
|
||||
interactionSource = interactionSource,
|
||||
onDragStopped = {
|
||||
val changeItems = mutableListOf<SubsItem>()
|
||||
orderSubItems.forEachIndexed { i, subsItem ->
|
||||
if (subItems[i] != subsItem) {
|
||||
changeItems.add(
|
||||
subsItem.copy(
|
||||
order = i
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (orderSubItems.isNotEmpty()) {
|
||||
vm.viewModelScope.launchTry {
|
||||
DbSet.subsItemDao.update(*changeItems.toTypedArray())
|
||||
if (orderSubItems.isNotEmpty()) {
|
||||
vm.viewModelScope.launchTry {
|
||||
DbSet.subsItemDao.update(*changeItems.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
)
|
||||
.animateItemPlacement()
|
||||
.padding(vertical = 3.dp, horizontal = 8.dp)
|
||||
.clickable {
|
||||
menuSubItem = subItem
|
||||
},
|
||||
.padding(vertical = 3.dp, horizontal = 8.dp),
|
||||
elevation = CardDefaults.cardElevation(draggedElevation = 10.dp),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
border = if (isDragging) BorderStroke(
|
||||
width,
|
||||
MaterialTheme.colorScheme.primary
|
||||
) else null
|
||||
) else null,
|
||||
interactionSource = interactionSource,
|
||||
) {
|
||||
SubsItemCard(
|
||||
subsItem = subItem,
|
||||
|
|
|
@ -128,9 +128,14 @@ dependencyResolutionManagement {
|
|||
library("androidx.room.runtime", "androidx.room:room-runtime:$roomVersion")
|
||||
library("androidx.room.compiler", "androidx.room:room-compiler:$roomVersion")
|
||||
library("androidx.room.ktx", "androidx.room:room-ktx:$roomVersion")
|
||||
library("androidx.room.paging", "androidx.room:room-paging:$roomVersion")
|
||||
|
||||
library("androidx.splashscreen", "androidx.core:core-splashscreen:1.0.1")
|
||||
|
||||
val pagingVersion = "3.2.1"
|
||||
library("androidx.paging.runtime", "androidx.paging:paging-runtime:$pagingVersion")
|
||||
library("androidx.paging.compose", "androidx.paging:paging-compose:$pagingVersion")
|
||||
|
||||
library(
|
||||
"google.accompanist.drawablepainter",
|
||||
"com.google.accompanist:accompanist-drawablepainter:0.34.0"
|
||||
|
@ -203,7 +208,7 @@ dependencyResolutionManagement {
|
|||
library("coil.gif", "io.coil-kt:coil-gif:$coilVersion")
|
||||
|
||||
// https://github.com/Calvin-LL/Reorderable
|
||||
library("others.reorderable", "sh.calvin.reorderable:reorderable:1.3.1")
|
||||
library("others.reorderable", "sh.calvin.reorderable:reorderable:1.3.2")
|
||||
|
||||
// https://www.objecthunter.net/exp4j/
|
||||
library("exp4j", "net.objecthunter:exp4j:0.4.8")
|
||||
|
|
Loading…
Reference in New Issue
Block a user