Skip to content

Commit

Permalink
feat: 支持导出yaml
Browse files Browse the repository at this point in the history
  • Loading branch information
jing332 committed Aug 2, 2023
1 parent 08c2637 commit ed3b930
Show file tree
Hide file tree
Showing 15 changed files with 176 additions and 26 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ dependencies {

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1'
implementation("com.charleskorn.kaml:kaml:0.55.0")

implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.activity:activity-compose:1.7.2'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.github.jing332.tts_dict_editor.const

import com.charleskorn.kaml.PolymorphismStyle
import com.charleskorn.kaml.Yaml
import com.charleskorn.kaml.YamlConfiguration
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json

Expand All @@ -12,4 +15,14 @@ object AppConst {
explicitNulls = false
}
}

val yaml by lazy {
Yaml(
configuration = YamlConfiguration(
encodeDefaults = false,
strictMode = false,
polymorphismStyle = PolymorphismStyle.Tag
)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.jing332.tts_dict_editor.const

object ExportType {
const val JSON = 0
const val CUSTOM_FORMAT = 1
const val YAML = 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.github.jing332.tts_dict_editor.replace

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
@SerialName("!org.nobody.multitts.tts.replace.ReplaceConfig")
data class ReplaceConfig(
val replaces: List<ReplaceRuleYaml>
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.github.jing332.tts_dict_editor.replace

import android.content.Context
import android.net.Uri
import com.charleskorn.kaml.decodeFromStream
import com.charleskorn.kaml.encodeToStream
import com.github.jing332.tts_dict_editor.const.AppConst
import kotlinx.serialization.encodeToString
import java.io.InputStream

class ReplaceManager(val context: Context, val uri: Uri) {
companion object {
const val TAG = "ReplaceManager"

fun toYaml(list: List<ReplaceRuleYaml>): String {
return AppConst.yaml.encodeToString(ReplaceConfig(list))
}
}

private val replaceList = mutableListOf<ReplaceRuleYaml>()

fun addReplace(replaceConfig: ReplaceRuleYaml) {
replaceList.add(replaceConfig)
}

fun getReplaceList(): List<ReplaceRuleYaml> {
return replaceList
}

fun clearReplaceList() {
replaceList.clear()
}

fun readConfigFromFile() {
context.contentResolver.openInputStream(uri)?.use {
readConfigFromInputStream(it)
return
}

throw Exception("Failed to read config file")
}

private fun readConfigFromInputStream(ins: InputStream) {
val cfg: ReplaceConfig = AppConst.yaml.decodeFromStream(ins)
replaceList.clear()
replaceList.addAll(cfg.replaces)
}

private fun updateConfigFile() {
val cfg = ReplaceConfig(replaceList)
context.contentResolver.openOutputStream(uri)?.use {
AppConst.yaml.encodeToStream(cfg, it)
return
}

throw Exception("Failed to write config file")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.github.jing332.tts_dict_editor.replace

import kotlinx.serialization.Serializable

@Serializable
data class ReplaceRuleYaml(
val activate: Boolean = false,
val name: String = "",
val regex: Boolean = false,
val source: String,
val target: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ class MainActivity : ComponentActivity() {
}


@OptIn(ExperimentalAnimationApi::class)
@Composable
fun AppNavigation(
navController: NavHostController = rememberNavController(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import me.saket.cascade.CascadeColumnScope


@Composable
internal fun CascadeColumnScope.ConfigExportUiMenu(onJson: () -> Unit, onCustomFormat: () -> Unit) {
internal fun CascadeColumnScope.ConfigExportUiMenu(
onJson: () -> Unit,
onCustomFormat: () -> Unit,
onYamlFormat: () -> Unit
) {
DropdownMenuItem(leadingIcon = {
Icon(
Icons.Filled.Output, "",
Expand All @@ -30,6 +34,16 @@ internal fun CascadeColumnScope.ConfigExportUiMenu(onJson: () -> Unit, onCustomF
},
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.new_multitts_format)) },
onClick = { onYamlFormat() })

androidx.compose.material3.DropdownMenuItem(
leadingIcon = {
Icon(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.github.jing332.tts_dict_editor.R
import com.github.jing332.tts_dict_editor.const.ExportType
import me.saket.cascade.CascadeDropdownMenu
import me.saket.cascade.rememberCascadeState

Expand All @@ -39,7 +40,7 @@ fun GroupItem(
onClick: () -> Unit,
onEdit: () -> Unit,
onDeleteAction: () -> Unit,
onExportAction: (isCustomType: Boolean) -> Unit,
onExportAction: (type: Int) -> Unit,
) {
Row(
modifier
Expand Down Expand Up @@ -90,9 +91,14 @@ fun GroupItem(
}
)

ConfigExportUiMenu(onJson = { onExportAction.invoke(false) }) {
onExportAction.invoke(true) // Custom Format
}
ConfigExportUiMenu(onJson = { onExportAction.invoke(ExportType.JSON) },
onCustomFormat = {
onExportAction.invoke(ExportType.CUSTOM_FORMAT) // Custom Format
},
onYamlFormat = {
onExportAction(ExportType.YAML)
}
)

Divider(
Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class ReplaceRuleActivity : ComponentActivity() {
contentResolver.openOutputStream(uri, "wt" /*覆写*/)
?.use { os -> os.write(txt.toByteArray()) }
}.onFailure { t ->
// errDialog = "保存文件错误" to t
longToast(getString(R.string.failed_to_save) + ": " + t.message)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -48,6 +47,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.const.ExportType
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
Expand Down Expand Up @@ -218,6 +218,12 @@ fun ReplaceRuleManagerScreen(
onCustomFormat = {
isMoreOptionsVisible = false
isVisibleCustomFormatExport = true to null
},
onYamlFormat = {
isMoreOptionsVisible = false
coroutineScope.launch {
exportedConfigText = vm.exportYaml()
}
}
)
}
Expand Down Expand Up @@ -245,18 +251,21 @@ fun ReplaceRuleManagerScreen(
onEditRule = { onEditRule.invoke(it) },
onDeleteRule = { coroutineScope.launch { vm.deleteRule(it) } },
onReorder = { from, to -> vm.reorder(from, to) },
onExportGroup = { group, isCustomFormat ->
if (isCustomFormat)
isVisibleCustomFormatExport = true to group
else
coroutineScope.launch {
exportedConfigText =
com.drake.net.utils.withDefault { vm.exportGroup(group) }
onExportGroup = { group, type ->
coroutineScope.launch {
when (type) {
ExportType.JSON -> exportedConfigText = vm.exportGroup(group)
ExportType.CUSTOM_FORMAT -> isVisibleCustomFormatExport =
true to group

ExportType.YAML -> exportedConfigText = vm.exportYaml()
}
}
},
)
}
})
}
)

if (isVisibleImportConfig)
ImportConfigDialog(
Expand Down Expand Up @@ -293,8 +302,13 @@ fun ReplaceRuleManagerScreen(
isVisibleCustomFormatExport = false to null
coroutineScope.launch {
exportedConfigText =
if (isVisibleCustomFormatExport.second == null) vm.exportByFormat(format)
else vm.exportGroupByFormat(isVisibleCustomFormatExport.second!!, format)
if (isVisibleCustomFormatExport.second == null) vm.exportByFormat(
format
)
else vm.exportGroupByFormat(
isVisibleCustomFormatExport.second!!,
format
)
}
}
)
Expand All @@ -308,7 +322,7 @@ private fun ImportConfigDialog(
onDismissRequest: () -> Unit,
onImport: (List<GroupWithReplaceRule>) -> Unit
) {
val state = rememberModalBottomSheetState(skipPartiallyExpanded = true)
// val state = rememberModalBottomSheetState(skipPartiallyExpanded = true)
var selectDialogData by remember {
mutableStateOf<List<GroupWithReplaceRule>?>(null)
}
Expand Down Expand Up @@ -337,7 +351,7 @@ private fun Screen(
onEditRule: (ReplaceRule) -> Unit,
onDeleteRule: (ReplaceRule) -> Unit,
onReorder: (fromIndex: Int, toIndex: Int) -> Unit,
onExportGroup: (ReplaceRuleGroup, Boolean) -> Unit,
onExportGroup: (ReplaceRuleGroup, Int) -> Unit,
) {
val orderState = rememberReorderableLazyListState(onMove = { from, to ->
println("from $from to $to")
Expand All @@ -350,7 +364,7 @@ private fun Screen(
.reorderable(orderState)
.detectReorderAfterLongPress(orderState)
) {
list.forEachIndexed { index, item ->
list.forEachIndexed { _, item ->
when (item) {
is ReplaceRuleGroup -> {
stickyHeader(key = "group_${item.id}") {
Expand Down Expand Up @@ -453,7 +467,7 @@ fun PreviewOrderList() {
.detectReorderAfterLongPress(orderState),
) {
items(list, key = { it }) {
ReorderableItem(state = orderState, key = it) { isDraging ->
ReorderableItem(state = orderState, key = it) { _ ->
Text(
text = it,
modifier = Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import com.github.jing332.tts_dict_editor.help.DictFileManager.Companion.toTxt
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
import com.github.jing332.tts_dict_editor.replace.ReplaceManager
import com.github.jing332.tts_dict_editor.replace.ReplaceRuleYaml
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
Expand Down Expand Up @@ -168,6 +170,18 @@ class RuleManagerViewModel : ViewModel() {
return count
}

suspend fun exportYaml(): String {
return ReplaceManager.toYaml(rules().map {
ReplaceRuleYaml(
activate = it.isEnabled,
name = it.name.ifEmpty { it.pattern },
regex = it.isRegex,
source = it.pattern,
target = it.replacement
)
})
}

suspend fun export(): String {
val gwrs = groupWithRules()
return AppConst.json.encodeToString(gwrs)
Expand All @@ -184,7 +198,7 @@ class RuleManagerViewModel : ViewModel() {
return AppConst.json.encodeToString(gwrs)
}

suspend fun exportGroupByFormat(group: ReplaceRuleGroup, format:String):String{
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) }
Expand All @@ -193,8 +207,8 @@ class RuleManagerViewModel : ViewModel() {
fun reorder(from: Int, to: Int) {
val fromItem = list[from]
val toItem = list[to]
val startIndex = min(from, to)
val endIndex = max(from, to)
// val startIndex = min(from, to)
// val endIndex = max(from, to)

if (fromItem is ReplaceRule && toItem is ReplaceRule && fromItem.groupId == toItem.groupId) {
list.add(to, list.removeAt(from))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ fun RuleEditScreen(
onResult: (ReplaceRule?) -> Unit,
) {
val vm: RuleEditViewModel = viewModel()
var isVisibleToolbar by remember { mutableStateOf(false) }
var inputKeyState = remember { mutableStateOf("") }
var toolbarKeyList: List<Pair<String, String>> by rememberDataSaverState(
key = ConfigConst.KEY_SOFT_KEYBOARD_TOOLBAR,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ fun getAppTheme(): AppTheme = themeTypeState.value
/**
* 根Context
*/
@Suppress("DEPRECATION")
@Composable
fun DictEditorTheme(
modifier: Modifier = Modifier,
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,6 @@
<string name="gray">灰色</string>
<string name="theme">主题</string>
<string name="device_not_support_dynamic_theme">您的系统不支持动态主题(需Android12及以上)</string>
<string name="new_multitts_format">新·MultiTTS</string>
<string name="failed_to_save">保存失败:%s</string>
</resources>

0 comments on commit ed3b930

Please sign in to comment.