|
|
@@ -16,7 +16,6 @@ import androidx.compose.material3.SnackbarHostState
|
|
|
import androidx.compose.material3.SnackbarResult
|
|
|
import androidx.compose.runtime.Composable
|
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
|
-import androidx.compose.runtime.collectAsState
|
|
|
import androidx.compose.runtime.getValue
|
|
|
import androidx.compose.runtime.mutableStateOf
|
|
|
import androidx.compose.runtime.remember
|
|
|
@@ -43,27 +42,51 @@ import io.legado.app.ui.widget.components.card.ReorderableSelectionItem
|
|
|
import io.legado.app.ui.widget.components.filePicker.FilePickerSheet
|
|
|
import io.legado.app.ui.widget.components.icon.AppIcons
|
|
|
import io.legado.app.ui.widget.components.importComponents.BatchImportDialog
|
|
|
+import io.legado.app.ui.widget.components.importComponents.BaseImportUiState
|
|
|
import io.legado.app.ui.widget.components.importComponents.SourceInputDialog
|
|
|
import io.legado.app.ui.widget.components.lazylist.FastScrollLazyColumn
|
|
|
import io.legado.app.ui.widget.components.menuItem.RoundDropdownMenuItem
|
|
|
import io.legado.app.ui.widget.components.rules.RuleEditFields
|
|
|
import io.legado.app.ui.widget.components.rules.RuleEditSheet
|
|
|
import io.legado.app.ui.widget.components.rules.RuleListScaffold
|
|
|
+import kotlinx.coroutines.flow.Flow
|
|
|
import org.koin.androidx.compose.koinViewModel
|
|
|
import sh.calvin.reorderable.rememberReorderableLazyListState
|
|
|
|
|
|
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
|
|
@Composable
|
|
|
-fun DictRuleScreen(
|
|
|
+fun DictRuleRouteScreen(
|
|
|
viewModel: DictRuleViewModel = koinViewModel(),
|
|
|
onBackClick: () -> Unit
|
|
|
) {
|
|
|
+ val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
|
|
+ val importState by viewModel.importState.collectAsStateWithLifecycle()
|
|
|
+
|
|
|
+ DictRuleScreen(
|
|
|
+ state = uiState,
|
|
|
+ importState = importState,
|
|
|
+ events = viewModel.events,
|
|
|
+ onIntent = viewModel::onIntent,
|
|
|
+ onPasteRule = viewModel::pasteRule,
|
|
|
+ onBackClick = onBackClick,
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
|
|
|
+@Composable
|
|
|
+fun DictRuleScreen(
|
|
|
+ state: DictRuleUiState,
|
|
|
+ importState: BaseImportUiState<DictRule>,
|
|
|
+ events: Flow<BaseRuleEvent>,
|
|
|
+ onIntent: (DictRuleIntent) -> Unit,
|
|
|
+ onPasteRule: () -> DictRule?,
|
|
|
+ onBackClick: () -> Unit,
|
|
|
+) {
|
|
|
|
|
|
val context = LocalContext.current
|
|
|
- val uiState by viewModel.uiState.collectAsState()
|
|
|
|
|
|
- val rules = uiState.items
|
|
|
- val selectedIds = uiState.selectedIds
|
|
|
+ val rules = state.items
|
|
|
+ val selectedIds = state.selectedIds
|
|
|
val inSelectionMode = selectedIds.isNotEmpty()
|
|
|
|
|
|
val listState = rememberLazyListState()
|
|
|
@@ -79,16 +102,15 @@ fun DictRuleScreen(
|
|
|
|
|
|
|
|
|
val reorderableState = rememberReorderableLazyListState(listState) { from, to ->
|
|
|
- viewModel.moveItemInList(from.index, to.index)
|
|
|
+ onIntent(DictRuleIntent.MoveItem(from.index, to.index))
|
|
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.SegmentFrequentTick)
|
|
|
}
|
|
|
|
|
|
val clipboardManager = LocalClipboard.current
|
|
|
val snackbarHostState = remember { SnackbarHostState() }
|
|
|
- val importState by viewModel.importState.collectAsStateWithLifecycle()
|
|
|
|
|
|
LaunchedEffect(Unit) {
|
|
|
- viewModel.events.collect { event ->
|
|
|
+ events.collect { event ->
|
|
|
when (event) {
|
|
|
is BaseRuleEvent.ShowSnackbar -> {
|
|
|
val result = snackbarHostState.showSnackbar(
|
|
|
@@ -117,7 +139,7 @@ fun DictRuleScreen(
|
|
|
uri?.let {
|
|
|
context.contentResolver.openInputStream(it)?.use { stream ->
|
|
|
val text = stream.reader().readText()
|
|
|
- viewModel.importSource(text)
|
|
|
+ onIntent(DictRuleIntent.ImportSource(text))
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -126,7 +148,7 @@ fun DictRuleScreen(
|
|
|
val exportDoc = rememberLauncherForActivityResult(
|
|
|
contract = ActivityResultContracts.CreateDocument("application/json"),
|
|
|
onResult = { uri ->
|
|
|
- uri?.let { viewModel.exportToUri(it, rules, selectedIds) }
|
|
|
+ uri?.let { onIntent(DictRuleIntent.ExportSelection(it)) }
|
|
|
}
|
|
|
)
|
|
|
|
|
|
@@ -136,7 +158,7 @@ fun DictRuleScreen(
|
|
|
onDismissRequest = { showUrlInput = false },
|
|
|
onConfirm = {
|
|
|
showUrlInput = false
|
|
|
- viewModel.importSource(it)
|
|
|
+ onIntent(DictRuleIntent.ImportSource(it))
|
|
|
}
|
|
|
)
|
|
|
|
|
|
@@ -150,7 +172,7 @@ fun DictRuleScreen(
|
|
|
},
|
|
|
onUpload = {
|
|
|
showExportSheet = false
|
|
|
- viewModel.uploadSelectedRules(selectedIds, rules)
|
|
|
+ onIntent(DictRuleIntent.UploadSelection)
|
|
|
},
|
|
|
allowExtensions = arrayOf("json")
|
|
|
)
|
|
|
@@ -174,11 +196,11 @@ fun DictRuleScreen(
|
|
|
BatchImportDialog(
|
|
|
title = "导入词典规则",
|
|
|
importState = importState,
|
|
|
- onDismissRequest = { viewModel.cancelImport() },
|
|
|
- onToggleItem = { viewModel.toggleImportSelection(it) },
|
|
|
- onToggleAll = { viewModel.toggleImportAll(it) },
|
|
|
- onUpdateItem = { index, rule -> viewModel.updateImportItem(index, rule) },
|
|
|
- onConfirm = { viewModel.saveImportedRules() },
|
|
|
+ onDismissRequest = { onIntent(DictRuleIntent.CancelImport) },
|
|
|
+ onToggleItem = { onIntent(DictRuleIntent.ToggleImportSelection(it)) },
|
|
|
+ onToggleAll = { onIntent(DictRuleIntent.ToggleImportAll(it)) },
|
|
|
+ onUpdateItem = { index, rule -> onIntent(DictRuleIntent.UpdateImportItem(index, rule)) },
|
|
|
+ onConfirm = { onIntent(DictRuleIntent.SaveImportedRules) },
|
|
|
itemTitle = { rule -> rule.name },
|
|
|
itemSubtitle = { rule ->
|
|
|
rule.urlRule.takeIf { it.isNotBlank() }
|
|
|
@@ -187,7 +209,7 @@ fun DictRuleScreen(
|
|
|
|
|
|
LaunchedEffect(reorderableState.isAnyItemDragging) {
|
|
|
if (!reorderableState.isAnyItemDragging) {
|
|
|
- viewModel.saveSortOrder()
|
|
|
+ onIntent(DictRuleIntent.SaveSortOrder)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -197,7 +219,7 @@ fun DictRuleScreen(
|
|
|
title = stringResource(R.string.delete),
|
|
|
confirmText = stringResource(R.string.ok),
|
|
|
onConfirm = { rule ->
|
|
|
- viewModel.delete(rule)
|
|
|
+ onIntent(DictRuleIntent.DeleteRule(rule))
|
|
|
showDeleteRuleDialog = null
|
|
|
},
|
|
|
dismissText = stringResource(R.string.cancel),
|
|
|
@@ -215,16 +237,12 @@ fun DictRuleScreen(
|
|
|
editingRule = null
|
|
|
},
|
|
|
onSave = { updatedRule ->
|
|
|
- if (editingRule == null) {
|
|
|
- viewModel.insert(updatedRule)
|
|
|
- } else {
|
|
|
- viewModel.update(updatedRule)
|
|
|
- }
|
|
|
+ onIntent(DictRuleIntent.SaveRule(updatedRule, isNew = editingRule == null))
|
|
|
showEditSheet = false
|
|
|
editingRule = null
|
|
|
},
|
|
|
- onCopy = { viewModel.copyRule(it) },
|
|
|
- onPaste = { viewModel.pasteRule() },
|
|
|
+ onCopy = { onIntent(DictRuleIntent.CopyRule(it)) },
|
|
|
+ onPaste = onPasteRule,
|
|
|
toFields = { r ->
|
|
|
RuleEditFields(
|
|
|
name = r?.name ?: "",
|
|
|
@@ -247,27 +265,24 @@ fun DictRuleScreen(
|
|
|
|
|
|
RuleListScaffold(
|
|
|
title = "字典规则",
|
|
|
- state = uiState,
|
|
|
+ state = state,
|
|
|
onBackClick = { onBackClick() },
|
|
|
onSearchToggle = { active ->
|
|
|
- viewModel.setSearchMode(active)
|
|
|
+ onIntent(DictRuleIntent.SetSearchMode(active))
|
|
|
},
|
|
|
- onSearchQueryChange = { viewModel.setSearchKey(it) },
|
|
|
+ onSearchQueryChange = { onIntent(DictRuleIntent.UpdateSearchQuery(it)) },
|
|
|
searchPlaceholder = stringResource(R.string.replace_purify_search),
|
|
|
- onClearSelection = { viewModel.setSelection(emptySet()) },
|
|
|
- onSelectAll = { viewModel.setSelection(rules.map { it.id }.toSet()) },
|
|
|
+ onClearSelection = { onIntent(DictRuleIntent.ClearSelection) },
|
|
|
+ onSelectAll = { onIntent(DictRuleIntent.SelectAll) },
|
|
|
onSelectInvert = {
|
|
|
- val allIds = rules.map { it.id }.toSet()
|
|
|
- viewModel.setSelection(allIds - selectedIds)
|
|
|
+ onIntent(DictRuleIntent.InvertSelection)
|
|
|
},
|
|
|
selectionSecondaryActions = listOf(
|
|
|
ActionItem(text = stringResource(R.string.enable), onClick = {
|
|
|
- viewModel.enableSelectionByIds(selectedIds)
|
|
|
- viewModel.setSelection(emptySet())
|
|
|
+ onIntent(DictRuleIntent.EnableSelection)
|
|
|
}),
|
|
|
ActionItem(text = stringResource(R.string.disable_selection), onClick = {
|
|
|
- viewModel.disableSelectionByIds(selectedIds)
|
|
|
- viewModel.setSelection(emptySet())
|
|
|
+ onIntent(DictRuleIntent.DisableSelection)
|
|
|
}),
|
|
|
ActionItem(
|
|
|
text = stringResource(R.string.export),
|
|
|
@@ -275,8 +290,8 @@ fun DictRuleScreen(
|
|
|
),
|
|
|
onDeleteSelected = { ids ->
|
|
|
@Suppress("UNCHECKED_CAST")
|
|
|
- viewModel.delSelectionByIds(ids as Set<String>)
|
|
|
- viewModel.setSelection(emptySet())
|
|
|
+ onIntent(DictRuleIntent.SetSelection(ids as Set<String>))
|
|
|
+ onIntent(DictRuleIntent.DeleteSelection)
|
|
|
},
|
|
|
onAddClick = {
|
|
|
editingRule = null
|
|
|
@@ -311,8 +326,10 @@ fun DictRuleScreen(
|
|
|
isEnabled = item.isEnabled,
|
|
|
isSelected = selectedIds.contains(item.id),
|
|
|
inSelectionMode = inSelectionMode,
|
|
|
- onToggleSelection = { viewModel.toggleSelection(item.id) },
|
|
|
- onEnabledChange = { enabled -> viewModel.update(item.rule.copy(enabled = enabled)) },
|
|
|
+ onToggleSelection = { onIntent(DictRuleIntent.ToggleSelection(item.id)) },
|
|
|
+ onEnabledChange = { enabled ->
|
|
|
+ onIntent(DictRuleIntent.SetRuleEnabled(item.rule, enabled))
|
|
|
+ },
|
|
|
onClickEdit = { editingRule = item.rule; showEditSheet = true },
|
|
|
trailingAction = {
|
|
|
SmallPlainButton(
|
|
|
@@ -328,7 +345,7 @@ fun DictRuleScreen(
|
|
|
listState = listState,
|
|
|
items = rules,
|
|
|
selectedIds = selectedIds,
|
|
|
- onSelectionChange = { viewModel.setSelection(it) },
|
|
|
+ onSelectionChange = { onIntent(DictRuleIntent.SetSelection(it)) },
|
|
|
idProvider = { it.id },
|
|
|
modifier = Modifier
|
|
|
.fillMaxHeight()
|