mirror of
https://github.com/gkd-kit/gkd.git
synced 2024-11-16 11:42:22 +08:00
perf: subsItem card
This commit is contained in:
parent
de431cb3c3
commit
1b570cd1af
|
@ -1,11 +1,15 @@
|
||||||
package li.songe.gkd.ui.component
|
package li.songe.gkd.ui.component
|
||||||
|
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.DropdownMenu
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Switch
|
import androidx.compose.material3.Switch
|
||||||
|
@ -13,27 +17,52 @@ import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.blankj.utilcode.util.ClipboardUtils
|
||||||
|
import com.blankj.utilcode.util.ZipUtils
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
import li.songe.gkd.data.RawSubscription
|
import li.songe.gkd.data.RawSubscription
|
||||||
import li.songe.gkd.data.SubsItem
|
import li.songe.gkd.data.SubsItem
|
||||||
|
import li.songe.gkd.data.TransferData
|
||||||
|
import li.songe.gkd.data.exportTransferData
|
||||||
|
import li.songe.gkd.ui.destinations.CategoryPageDestination
|
||||||
|
import li.songe.gkd.ui.destinations.GlobalRulePageDestination
|
||||||
|
import li.songe.gkd.ui.destinations.SubsPageDestination
|
||||||
|
import li.songe.gkd.util.LocalNavController
|
||||||
|
import li.songe.gkd.util.exportZipDir
|
||||||
import li.songe.gkd.util.formatTimeAgo
|
import li.songe.gkd.util.formatTimeAgo
|
||||||
|
import li.songe.gkd.util.json
|
||||||
|
import li.songe.gkd.util.launchTry
|
||||||
import li.songe.gkd.util.map
|
import li.songe.gkd.util.map
|
||||||
|
import li.songe.gkd.util.navigate
|
||||||
|
import li.songe.gkd.util.openUri
|
||||||
|
import li.songe.gkd.util.shareFile
|
||||||
import li.songe.gkd.util.subsLoadErrorsFlow
|
import li.songe.gkd.util.subsLoadErrorsFlow
|
||||||
import li.songe.gkd.util.subsRefreshErrorsFlow
|
import li.songe.gkd.util.subsRefreshErrorsFlow
|
||||||
import li.songe.gkd.util.subsRefreshingFlow
|
import li.songe.gkd.util.subsRefreshingFlow
|
||||||
|
import li.songe.gkd.util.toast
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SubsItemCard(
|
fun SubsItemCard(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
interactionSource: MutableInteractionSource,
|
||||||
subsItem: SubsItem,
|
subsItem: SubsItem,
|
||||||
rawSubscription: RawSubscription?,
|
subscription: RawSubscription?,
|
||||||
index: Int,
|
index: Int,
|
||||||
|
vm: ViewModel,
|
||||||
onCheckedChange: ((Boolean) -> Unit)? = null,
|
onCheckedChange: ((Boolean) -> Unit)? = null,
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
@ -44,82 +73,220 @@ fun SubsItemCard(
|
||||||
subsRefreshErrorsFlow.map(scope) { it[subsItem.id] }
|
subsRefreshErrorsFlow.map(scope) { it[subsItem.id] }
|
||||||
}.collectAsState()
|
}.collectAsState()
|
||||||
val subsRefreshing by subsRefreshingFlow.collectAsState()
|
val subsRefreshing by subsRefreshingFlow.collectAsState()
|
||||||
|
var expanded by remember { mutableStateOf(false) }
|
||||||
Row(
|
Card(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
onClick = {
|
||||||
modifier = Modifier.padding(8.dp)
|
if (!subsRefreshingFlow.value) {
|
||||||
|
expanded = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = modifier.padding(16.dp, 2.dp),
|
||||||
|
shape = MaterialTheme.shapes.small,
|
||||||
|
interactionSource = interactionSource,
|
||||||
) {
|
) {
|
||||||
Column(
|
SubsMenuItem(
|
||||||
modifier = Modifier.weight(1f),
|
expanded = expanded,
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
onExpandedChange = { expanded = it },
|
||||||
|
subItem = subsItem,
|
||||||
|
subscription = subscription,
|
||||||
|
vm = vm
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier.padding(8.dp),
|
||||||
) {
|
) {
|
||||||
if (rawSubscription != null) {
|
Column(
|
||||||
Text(
|
modifier = Modifier.weight(1f),
|
||||||
text = index.toString() + ". " + (rawSubscription.name),
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
maxLines = 1,
|
) {
|
||||||
softWrap = false,
|
if (subscription != null) {
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
style = MaterialTheme.typography.bodyLarge,
|
|
||||||
)
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
|
||||||
) {
|
|
||||||
Text(
|
Text(
|
||||||
text = subsItem.sourceText,
|
text = index.toString() + ". " + (subscription.name),
|
||||||
style = MaterialTheme.typography.bodyMedium
|
maxLines = 1,
|
||||||
|
softWrap = false,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
style = MaterialTheme.typography.bodyLarge,
|
||||||
)
|
)
|
||||||
Text(
|
Row(
|
||||||
text = formatTimeAgo(subsItem.mtime),
|
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
) {
|
||||||
)
|
|
||||||
if (subsItem.id >= 0) {
|
|
||||||
Text(
|
Text(
|
||||||
text = "v" + (rawSubscription.version.toString()),
|
text = subsItem.sourceText,
|
||||||
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = formatTimeAgo(subsItem.mtime),
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
)
|
)
|
||||||
|
if (subsItem.id >= 0) {
|
||||||
|
Text(
|
||||||
|
text = "v" + (subscription.version.toString()),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
Text(
|
||||||
Text(
|
text = subscription.numText,
|
||||||
text = rawSubscription.numText,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
color = if (subscription.groupsSize == 0) {
|
||||||
color = if (rawSubscription.groupsSize == 0) {
|
LocalContentColor.current.copy(alpha = 0.5f)
|
||||||
LocalContentColor.current.copy(alpha = 0.5f)
|
} else {
|
||||||
} else {
|
LocalContentColor.current
|
||||||
LocalContentColor.current
|
}
|
||||||
}
|
)
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Text(
|
|
||||||
text = "${index}. id:${subsItem.id}",
|
|
||||||
maxLines = 1,
|
|
||||||
softWrap = false,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
)
|
|
||||||
val color = if (subsLoadError != null) {
|
|
||||||
MaterialTheme.colorScheme.error
|
|
||||||
} else {
|
} else {
|
||||||
Color.Unspecified
|
Text(
|
||||||
|
text = "${index}. id:${subsItem.id}",
|
||||||
|
maxLines = 1,
|
||||||
|
softWrap = false,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
val color = if (subsLoadError != null) {
|
||||||
|
MaterialTheme.colorScheme.error
|
||||||
|
} else {
|
||||||
|
Color.Unspecified
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = subsLoadError?.message
|
||||||
|
?: if (subsRefreshing) "加载中..." else "文件不存在",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = color
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Text(
|
if (subsRefreshError != null) {
|
||||||
text = subsLoadError?.message
|
Text(
|
||||||
?: if (subsRefreshing) "加载中..." else "文件不存在",
|
text = "加载错误: ${subsRefreshError?.message}",
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
color = color
|
color = MaterialTheme.colorScheme.error
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(modifier = Modifier.width(10.dp))
|
||||||
|
Switch(
|
||||||
|
checked = subsItem.enable,
|
||||||
|
onCheckedChange = onCheckedChange,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SubsMenuItem(
|
||||||
|
expanded: Boolean,
|
||||||
|
onExpandedChange: ((Boolean) -> Unit),
|
||||||
|
subItem: SubsItem,
|
||||||
|
subscription: RawSubscription?,
|
||||||
|
vm: ViewModel
|
||||||
|
) {
|
||||||
|
val navController = LocalNavController.current
|
||||||
|
val context = LocalContext.current
|
||||||
|
DropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = { onExpandedChange(false) }
|
||||||
|
) {
|
||||||
|
if (subscription != null) {
|
||||||
|
if (subItem.id < 0 || subscription.apps.isNotEmpty()) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = {
|
||||||
|
Text(text = "应用规则")
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
onExpandedChange(false)
|
||||||
|
navController.navigate(SubsPageDestination(subItem.id))
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (subsRefreshError != null) {
|
if (subItem.id < 0 || subscription.categories.isNotEmpty()) {
|
||||||
Text(
|
DropdownMenuItem(
|
||||||
text = "加载错误: ${subsRefreshError?.message}",
|
text = {
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
Text(text = "规则类别")
|
||||||
color = MaterialTheme.colorScheme.error
|
},
|
||||||
|
onClick = {
|
||||||
|
onExpandedChange(false)
|
||||||
|
navController.navigate(CategoryPageDestination(subItem.id))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (subItem.id < 0 || subscription.globalGroups.isNotEmpty()) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = {
|
||||||
|
Text(text = "全局规则")
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
onExpandedChange(false)
|
||||||
|
navController.navigate(GlobalRulePageDestination(subItem.id))
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.width(10.dp))
|
DropdownMenuItem(
|
||||||
Switch(
|
text = {
|
||||||
checked = subsItem.enable,
|
Text(text = "导出数据")
|
||||||
onCheckedChange = onCheckedChange,
|
},
|
||||||
|
onClick = {
|
||||||
|
onExpandedChange(false)
|
||||||
|
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||||
|
val transferDataFile = exportZipDir.resolve("${TransferData.TYPE}.json")
|
||||||
|
transferDataFile.writeText(
|
||||||
|
json.encodeToString(
|
||||||
|
exportTransferData(
|
||||||
|
listOf(
|
||||||
|
subItem.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val file = exportZipDir.resolve("backup-${subItem.id}.zip")
|
||||||
|
if (file.exists()) {
|
||||||
|
file.delete()
|
||||||
|
}
|
||||||
|
ZipUtils.zipFiles(listOf(transferDataFile), file)
|
||||||
|
transferDataFile.delete()
|
||||||
|
context.shareFile(file, "分享数据文件")
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
subItem.updateUrl?.let {
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = {
|
||||||
|
Text(text = "复制链接")
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
onExpandedChange(false)
|
||||||
|
ClipboardUtils.copyText(subItem.updateUrl)
|
||||||
|
toast("复制成功")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
subscription?.supportUri?.let { supportUri ->
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = {
|
||||||
|
Text(text = "问题反馈")
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
onExpandedChange(false)
|
||||||
|
context.openUri(supportUri)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (subItem.id != -2L) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = {
|
||||||
|
Text(text = "删除订阅", color = MaterialTheme.colorScheme.error)
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
onExpandedChange(false)
|
||||||
|
vm.viewModelScope.launchTry {
|
||||||
|
val result = getDialogResult(
|
||||||
|
"删除订阅",
|
||||||
|
"是否删除订阅 ${subscription?.name ?: subItem.id} ?",
|
||||||
|
)
|
||||||
|
if (!result) return@launchTry
|
||||||
|
subItem.removeAssets()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package li.songe.gkd.ui.home
|
||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.webkit.URLUtil
|
import android.webkit.URLUtil
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
@ -16,21 +15,17 @@ import androidx.compose.foundation.layout.wrapContentSize
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.FormatListBulleted
|
import androidx.compose.material.icons.automirrored.filled.FormatListBulleted
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.MoreVert
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Card
|
|
||||||
import androidx.compose.material3.DropdownMenu
|
import androidx.compose.material3.DropdownMenu
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
import androidx.compose.material3.HorizontalDivider
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.LocalTextStyle
|
import androidx.compose.material3.LocalTextStyle
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
|
@ -49,43 +44,27 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.window.Dialog
|
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.blankj.utilcode.util.ClipboardUtils
|
|
||||||
import com.blankj.utilcode.util.UriUtils
|
import com.blankj.utilcode.util.UriUtils
|
||||||
import com.blankj.utilcode.util.ZipUtils
|
|
||||||
import com.dylanc.activityresult.launcher.launchForResult
|
import com.dylanc.activityresult.launcher.launchForResult
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.serialization.encodeToString
|
|
||||||
import li.songe.gkd.data.SubsItem
|
|
||||||
import li.songe.gkd.data.TransferData
|
import li.songe.gkd.data.TransferData
|
||||||
import li.songe.gkd.data.exportTransferData
|
|
||||||
import li.songe.gkd.data.importTransferData
|
import li.songe.gkd.data.importTransferData
|
||||||
import li.songe.gkd.db.DbSet
|
import li.songe.gkd.db.DbSet
|
||||||
import li.songe.gkd.ui.component.SubsItemCard
|
import li.songe.gkd.ui.component.SubsItemCard
|
||||||
import li.songe.gkd.ui.component.getDialogResult
|
import li.songe.gkd.ui.component.getDialogResult
|
||||||
import li.songe.gkd.ui.destinations.CategoryPageDestination
|
|
||||||
import li.songe.gkd.ui.destinations.GlobalRulePageDestination
|
|
||||||
import li.songe.gkd.ui.destinations.SubsPageDestination
|
|
||||||
import li.songe.gkd.util.LocalLauncher
|
import li.songe.gkd.util.LocalLauncher
|
||||||
import li.songe.gkd.util.LocalNavController
|
|
||||||
import li.songe.gkd.util.checkSubsUpdate
|
import li.songe.gkd.util.checkSubsUpdate
|
||||||
import li.songe.gkd.util.exportZipDir
|
|
||||||
import li.songe.gkd.util.isSafeUrl
|
import li.songe.gkd.util.isSafeUrl
|
||||||
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.navigate
|
|
||||||
import li.songe.gkd.util.openUri
|
|
||||||
import li.songe.gkd.util.readFileZipByteArray
|
import li.songe.gkd.util.readFileZipByteArray
|
||||||
import li.songe.gkd.util.shareFile
|
|
||||||
import li.songe.gkd.util.subsFolder
|
|
||||||
import li.songe.gkd.util.subsIdToRawFlow
|
import li.songe.gkd.util.subsIdToRawFlow
|
||||||
import li.songe.gkd.util.subsItemsFlow
|
import li.songe.gkd.util.subsItemsFlow
|
||||||
import li.songe.gkd.util.subsRefreshingFlow
|
import li.songe.gkd.util.subsRefreshingFlow
|
||||||
|
@ -99,8 +78,6 @@ val subsNav = BottomNavItem(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun useSubsManagePage(): ScaffoldExt {
|
fun useSubsManagePage(): ScaffoldExt {
|
||||||
val context = LocalContext.current
|
|
||||||
val navController = LocalNavController.current
|
|
||||||
val launcher = LocalLauncher.current
|
val launcher = LocalLauncher.current
|
||||||
|
|
||||||
val vm = hiltViewModel<HomeVm>()
|
val vm = hiltViewModel<HomeVm>()
|
||||||
|
@ -114,127 +91,12 @@ fun useSubsManagePage(): ScaffoldExt {
|
||||||
orderSubItems = subItems
|
orderSubItems = subItems
|
||||||
}
|
}
|
||||||
|
|
||||||
var menuSubItem: SubsItem? by remember { mutableStateOf(null) }
|
|
||||||
|
|
||||||
var showAddLinkDialog by remember { mutableStateOf(false) }
|
var showAddLinkDialog by remember { mutableStateOf(false) }
|
||||||
var link by remember { mutableStateOf("") }
|
var link by remember { mutableStateOf("") }
|
||||||
|
|
||||||
val refreshing by subsRefreshingFlow.collectAsState()
|
val refreshing by subsRefreshingFlow.collectAsState()
|
||||||
val pullRefreshState = rememberPullRefreshState(refreshing, { checkSubsUpdate(true) })
|
val pullRefreshState = rememberPullRefreshState(refreshing, { checkSubsUpdate(true) })
|
||||||
|
|
||||||
menuSubItem?.let { menuSubItemVal ->
|
|
||||||
Dialog(onDismissRequest = { menuSubItem = null }) {
|
|
||||||
Card(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(16.dp),
|
|
||||||
shape = RoundedCornerShape(16.dp),
|
|
||||||
) {
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
Text(text = "导出数据", modifier = Modifier
|
|
||||||
.clickable {
|
|
||||||
menuSubItem = null
|
|
||||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
|
||||||
val transferDataFile = exportZipDir.resolve("${TransferData.TYPE}.json")
|
|
||||||
transferDataFile.writeText(
|
|
||||||
json.encodeToString(
|
|
||||||
exportTransferData(
|
|
||||||
listOf(
|
|
||||||
menuSubItemVal.id
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val file =
|
|
||||||
exportZipDir.resolve("backup-${System.currentTimeMillis()}.zip")
|
|
||||||
ZipUtils.zipFiles(listOf(transferDataFile), file)
|
|
||||||
transferDataFile.delete()
|
|
||||||
context.shareFile(file, "分享数据文件")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.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.openUri(subsRawVal.supportUri)
|
|
||||||
}
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(16.dp))
|
|
||||||
HorizontalDivider()
|
|
||||||
}
|
|
||||||
if (menuSubItemVal.id != -2L) {
|
|
||||||
Text(text = "删除订阅", modifier = Modifier
|
|
||||||
.clickable {
|
|
||||||
menuSubItem = null
|
|
||||||
vm.viewModelScope.launchTry {
|
|
||||||
val result = getDialogResult(
|
|
||||||
"删除订阅",
|
|
||||||
"是否删除订阅 ${subsIdToRaw[menuSubItemVal.id]?.name} ?",
|
|
||||||
)
|
|
||||||
if (!result) return@launchTry
|
|
||||||
menuSubItemVal.removeAssets()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(16.dp), color = MaterialTheme.colorScheme.error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LaunchedEffect(showAddLinkDialog) {
|
LaunchedEffect(showAddLinkDialog) {
|
||||||
if (!showAddLinkDialog) {
|
if (!showAddLinkDialog) {
|
||||||
link = ""
|
link = ""
|
||||||
|
@ -405,12 +267,7 @@ fun useSubsManagePage(): ScaffoldExt {
|
||||||
enabled = !refreshing,
|
enabled = !refreshing,
|
||||||
) {
|
) {
|
||||||
val interactionSource = remember { MutableInteractionSource() }
|
val interactionSource = remember { MutableInteractionSource() }
|
||||||
Card(
|
SubsItemCard(
|
||||||
onClick = {
|
|
||||||
if (!refreshing) {
|
|
||||||
menuSubItem = subItem
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.longPressDraggableHandle(
|
.longPressDraggableHandle(
|
||||||
enabled = !refreshing,
|
enabled = !refreshing,
|
||||||
|
@ -425,22 +282,18 @@ fun useSubsManagePage(): ScaffoldExt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
.padding(vertical = 3.dp, horizontal = 8.dp),
|
|
||||||
shape = RoundedCornerShape(8.dp),
|
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
) {
|
subsItem = subItem,
|
||||||
SubsItemCard(
|
subscription = subsIdToRaw[subItem.id],
|
||||||
subsItem = subItem,
|
index = index + 1,
|
||||||
rawSubscription = subsIdToRaw[subItem.id],
|
vm = vm,
|
||||||
index = index + 1,
|
onCheckedChange = { checked ->
|
||||||
onCheckedChange = { checked ->
|
vm.viewModelScope.launch {
|
||||||
vm.viewModelScope.launch {
|
DbSet.subsItemDao.updateEnable(subItem.id, checked)
|
||||||
DbSet.subsItemDao.updateEnable(subItem.id, checked)
|
}
|
||||||
}
|
},
|
||||||
},
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item {
|
item {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user