Skip to content

Commit

Permalink
feat: 支持自定义导出格式
Browse files Browse the repository at this point in the history
  • Loading branch information
jing332 committed Jun 5, 2023
1 parent eb866d3 commit 7adf357
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 42 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ jobs:
output: "${{ github.workspace }}/app/build/outputs/apk/release"
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

- uses: actions/setup-java@v3
with:
distribution: temurin
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ jobs:
output: "${{ github.workspace }}/app/build/outputs/apk/release"
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-java@v3
with:
distribution: temurin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ package com.github.jing332.tts_dict_editor.const

object ConfigConst {
const val KEY_SOFT_KEYBOARD_TOOLBAR = "softKeyboardToolbar"

const val KEY_DICT_EXPORT_FORMAT = "exportFormat"
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.funny.data_saver.core.DataSaverConverter.registerTypeConverters
import com.funny.data_saver.core.DataSaverPreferences
import com.funny.data_saver.core.mutableDataSaverStateOf
import com.github.jing332.tts_dict_editor.app
import com.github.jing332.tts_dict_editor.const.ConfigConst
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
Expand Down Expand Up @@ -38,7 +39,13 @@ object AppConfig {

val softKeyboardToolbar = mutableDataSaverStateOf<List<Pair<String, String>>>(
dataSaverInterface = dataSaverPref,
key = "",
key = ConfigConst.KEY_SOFT_KEYBOARD_TOOLBAR,
initialValue = emptyList()
)

val dictExportFormat = mutableDataSaverStateOf<String>(
dataSaverInterface = dataSaverPref,
key = ConfigConst.KEY_DICT_EXPORT_FORMAT,
initialValue = "$1=$2"
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
Expand All @@ -28,12 +31,62 @@ import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.drake.net.utils.fileName
import com.github.jing332.tts_dict_editor.R
import com.github.jing332.tts_dict_editor.utils.ASFUriUtils.getPath
import com.talhafaki.composablesweettoast.util.SweetToastUtil

@Composable
fun CustomExportFormatDialog(
format: String,
onFormatChange: (String) -> Unit,
onConfirm: () -> Unit,
onDismissRequest: () -> Unit
) {
AlertDialog(onDismissRequest = onDismissRequest, confirmButton = {
TextButton(onClick = { onConfirm.invoke() }) {
Text(text = stringResource(id = R.string.confirm))
}
},
title = {
Text("自定义导出格式")
},
text = {
Column {
Text(
"占位符:\n$1 匹配 \n$2 替换为"
)
OutlinedTextField(
modifier = Modifier.padding(top = 8.dp),
label = { Text("格式") },
value = format,
onValueChange = onFormatChange,
)
}
}
)
}

@Preview
@Composable
fun PreviewCustomExportFormatDialog() {
var isVisible by remember { mutableStateOf(true) }
var formatState by remember { mutableStateOf("") }
if (isVisible)
CustomExportFormatDialog(
format = formatState,
onFormatChange = { formatState = it },
onDismissRequest = {
isVisible = false
},
onConfirm = {
isVisible = false
}
)
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ConfigExportBottomSheet(
Expand Down Expand Up @@ -73,7 +126,10 @@ fun ConfigExportBottomSheet(
val clipboardManager = LocalClipboardManager.current

ModalBottomSheet(onDismissRequest = onDismissRequest, modifier = Modifier.fillMaxSize()) {
Column(Modifier.padding(horizontal = 8.dp)) {
Column(
Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp)) {
Row(Modifier.align(Alignment.CenterHorizontally)) {
TextButton(
onClick = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.github.jing332.tts_dict_editor.ui.replace

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.FormatColorText
import androidx.compose.material.icons.filled.Javascript
import androidx.compose.material.icons.filled.Output
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import com.github.jing332.tts_dict_editor.R
import me.saket.cascade.CascadeColumnScope


@Composable
internal fun CascadeColumnScope.ConfigExportUiMenu(onJson: () -> Unit, onCustomFormat: () -> Unit) {
DropdownMenuItem(leadingIcon = {
Icon(
Icons.Filled.Output, "",
tint = MaterialTheme.colorScheme.onBackground
)
}, text = { Text(stringResource(id = R.string.config_export)) }, children = {
androidx.compose.material3.DropdownMenuItem(
leadingIcon = {
Icon(
Icons.Filled.Javascript, "",
tint = MaterialTheme.colorScheme.onBackground
)
},
text = { Text(stringResource(R.string.json_format)) },
onClick = { onJson.invoke() })
androidx.compose.material3.DropdownMenuItem(
leadingIcon = {
Icon(
Icons.Filled.FormatColorText, "",
tint = MaterialTheme.colorScheme.onBackground
)
},
text = { Text(stringResource(R.string.custom_format)) },
onClick = { onCustomFormat.invoke() })
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Output
import androidx.compose.material3.Divider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
Expand Down Expand Up @@ -40,7 +39,7 @@ fun GroupItem(
onClick: () -> Unit,
onEdit: () -> Unit,
onDeleteAction: () -> Unit,
onImportAction: () -> Unit,
onExportAction: (isCustomType: Boolean) -> Unit,
) {
Row(
modifier
Expand Down Expand Up @@ -90,19 +89,11 @@ fun GroupItem(
isMoreOptionsVisible = false
}
)
androidx.compose.material3.DropdownMenuItem(
leadingIcon = {
Icon(
Icons.Filled.Output, "",
tint = MaterialTheme.colorScheme.onBackground
)
},
text = { Text(stringResource(R.string.config_export)) },
onClick = {
onImportAction.invoke()
isMoreOptionsVisible = false
}
)

ConfigExportUiMenu(onJson = { onExportAction.invoke(false) }) {
onExportAction.invoke(true) // Custom Format
}

Divider(
Modifier
.fillMaxWidth()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
@file:OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class)
@file:OptIn(
ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class,
ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class
)

package com.github.jing332.tts_dict_editor.ui.replace

Expand All @@ -17,7 +20,6 @@ import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Group
import androidx.compose.material.icons.filled.Input
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Output
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
Expand Down Expand Up @@ -46,6 +48,7 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.github.jing332.tts_dict_editor.R
import com.github.jing332.tts_dict_editor.const.AppConst
import com.github.jing332.tts_dict_editor.help.AppConfig
import com.github.jing332.tts_dict_editor.help.GroupWithReplaceRule
import com.github.jing332.tts_dict_editor.help.ReplaceRule
import com.github.jing332.tts_dict_editor.help.ReplaceRuleGroup
Expand All @@ -71,7 +74,13 @@ fun ReplaceRuleManagerScreen(
val coroutineScope = rememberCoroutineScope()

var isVisibleImportConfig by remember { mutableStateOf(false) }
var exportConfigJson by remember { mutableStateOf("") }
var exportedConfigText by remember { mutableStateOf("") }
// 导出配置 Pair<isVisible, ReplaceRuleGroup>
var isVisibleCustomFormatExport by remember {
mutableStateOf<Pair<Boolean, ReplaceRuleGroup?>>(
false to null
)
}

var successToast by remember { mutableStateOf<String?>(null) }
if (successToast != null)
Expand Down Expand Up @@ -202,20 +211,17 @@ fun ReplaceRuleManagerScreen(
isVisibleImportConfig = true
}
)
androidx.compose.material3.DropdownMenuItem(
text = { Text(stringResource(R.string.config_export)) },
leadingIcon = {
Icon(
Icons.Filled.Output, "",
tint = MaterialTheme.colorScheme.onBackground
)
},
onClick = {

ConfigExportUiMenu(
onJson = {
isMoreOptionsVisible = false
coroutineScope.launch {
exportConfigJson =
com.drake.net.utils.withDefault { vm.export() }
exportedConfigText = vm.export()
}
},
onCustomFormat = {
isMoreOptionsVisible = false
isVisibleCustomFormatExport = true to null
}
)
}
Expand Down Expand Up @@ -243,11 +249,14 @@ fun ReplaceRuleManagerScreen(
onEditRule = { onEditRule.invoke(it) },
onDeleteRule = { coroutineScope.launch { vm.deleteRule(it) } },
onReorder = { from, to -> vm.reorder(from, to) },
onExportGroup = {
coroutineScope.launch {
exportConfigJson =
com.drake.net.utils.withDefault { vm.exportGroup(it) }
}
onExportGroup = { group, isCustomFormat ->
if (isCustomFormat)
isVisibleCustomFormatExport = true to group
else
coroutineScope.launch {
exportedConfigText =
com.drake.net.utils.withDefault { vm.exportGroup(group) }
}
},
)
}
Expand All @@ -268,13 +277,35 @@ fun ReplaceRuleManagerScreen(
}
)

if (exportConfigJson.isNotEmpty()) {
ConfigExportBottomSheet(json = exportConfigJson) {
exportConfigJson = ""
if (exportedConfigText.isNotEmpty()) {
val fileName =
if (exportedConfigText.contains("\"group\":") && exportedConfigText.contains("\"list\":")) "replaceRules.json" else "dict.txt"
ConfigExportBottomSheet(json = exportedConfigText, fileName) {
exportedConfigText = ""
}
}

if (isVisibleCustomFormatExport.first) {
var format by remember { AppConfig.dictExportFormat }
CustomExportFormatDialog(
format = format,
onFormatChange = { format = it },
onDismissRequest = {
isVisibleCustomFormatExport = false to null
},
onConfirm = {
isVisibleCustomFormatExport = false to null
coroutineScope.launch {
exportedConfigText =
if (isVisibleCustomFormatExport.second == null) vm.exportByFormat(format)
else vm.exportGroupByFormat(isVisibleCustomFormatExport.second!!, format)
}
}
)
}
}


@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ImportConfigDialog(
Expand Down Expand Up @@ -310,7 +341,7 @@ private fun Screen(
onEditRule: (ReplaceRule) -> Unit,
onDeleteRule: (ReplaceRule) -> Unit,
onReorder: (fromIndex: Int, toIndex: Int) -> Unit,
onExportGroup: (ReplaceRuleGroup) -> Unit,
onExportGroup: (ReplaceRuleGroup, Boolean) -> Unit,
) {
// 保存展开的分组ID 提高效率 避免每次item都要去list中查找
// var expandedGroups by remember { mutableStateOf<List<Long>>(emptyList()) }
Expand All @@ -336,7 +367,7 @@ private fun Screen(
onClick = { onChangeExpanded.invoke(item) },
onEdit = { onEditGroup.invoke(item) },
onDeleteAction = { onDeleteGroup.invoke(item) },
onImportAction = { onExportGroup.invoke(item) },
onExportAction = { onExportGroup.invoke(item, it) },
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,23 @@ class RuleManagerViewModel : ViewModel() {
return AppConst.json.encodeToString(gwrs)
}

suspend fun exportByFormat(format: String): String {
val gwrs = groupWithRules()
return gwrs.flatMap { it.list }
.joinToString("\n") { format.replace("$1", it.pattern).replace("$2", it.replacement) }
}

suspend fun exportGroup(group: ReplaceRuleGroup): String {
val gwrs = groupWithRules().filter { it.group.id == group.id }
return AppConst.json.encodeToString(gwrs)
}

suspend fun exportGroupByFormat(group: ReplaceRuleGroup, format:String):String{
val gwrs = groupWithRules().filter { it.group.id == group.id }
return gwrs.flatMap { it.list }
.joinToString("\n") { format.replace("$1", it.pattern).replace("$2", it.replacement) }
}

fun reorder(from: Int, to: Int) {
val fromItem = list[from]
val toItem = list[to]
Expand Down
Loading

0 comments on commit 7adf357

Please sign in to comment.