mirror of
https://github.com/fcitx5-android/fcitx5-android.git
synced 2026-08-02 20:16:06 +08:00
Migrate navigation graph xml to kotlin DSL
see also: https://developer.android.com/guide/navigation/design/kotlin-dsl
This commit is contained in:
parent
1858aff3e6
commit
a7af9912a5
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.core
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
data class InputMethodSubMode(val name: String, val label: String, val icon: String) {
|
||||
constructor() : this("", "", "")
|
||||
@ -74,6 +75,7 @@ data class InputMethodEntry(
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
@Serializable
|
||||
data class RawConfig(
|
||||
val name: String,
|
||||
val comment: String,
|
||||
@ -158,6 +160,7 @@ data class AddonInfo(
|
||||
val dependencies: Array<String> = arrayOf(),
|
||||
val optionalDependencies: Array<String> = arrayOf(),
|
||||
) {
|
||||
@Suppress("UNUSED") // used in JNI
|
||||
constructor(
|
||||
uniqueName: String,
|
||||
name: String,
|
||||
|
||||
@ -1,23 +1,26 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import org.fcitx.fcitx5.android.BuildConfig
|
||||
import org.fcitx.fcitx5.android.R
|
||||
import org.fcitx.fcitx5.android.ui.common.PaddingPreferenceFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.SettingsRoute
|
||||
import org.fcitx.fcitx5.android.utils.Const
|
||||
import org.fcitx.fcitx5.android.utils.addCategory
|
||||
import org.fcitx.fcitx5.android.utils.addPreference
|
||||
import org.fcitx.fcitx5.android.utils.formatDateTime
|
||||
import org.fcitx.fcitx5.android.utils.navigateWithAnim
|
||||
|
||||
class AboutFragment : PaddingPreferenceFragment() {
|
||||
|
||||
@SuppressLint("UseKtx")
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
preferenceScreen = preferenceManager.createPreferenceScreen(requireContext()).apply {
|
||||
addPreference(R.string.privacy_policy) {
|
||||
@ -27,7 +30,7 @@ class AboutFragment : PaddingPreferenceFragment() {
|
||||
R.string.open_source_licenses,
|
||||
R.string.licenses_of_third_party_libraries
|
||||
) {
|
||||
findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment)
|
||||
navigateWithAnim(SettingsRoute.License)
|
||||
}
|
||||
addPreference(R.string.source_code, R.string.github_repo) {
|
||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(Const.githubRepo)))
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
@ -17,20 +18,23 @@ import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.forEach
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDestination.Companion.hasRoute
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
import org.fcitx.fcitx5.android.BuildConfig
|
||||
import org.fcitx.fcitx5.android.R
|
||||
import org.fcitx.fcitx5.android.data.prefs.AppPrefs
|
||||
import org.fcitx.fcitx5.android.databinding.ActivityMainBinding
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.PinyinDictionaryFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.SettingsRoute
|
||||
import org.fcitx.fcitx5.android.ui.setup.SetupActivity
|
||||
import org.fcitx.fcitx5.android.utils.Const
|
||||
import org.fcitx.fcitx5.android.utils.item
|
||||
import org.fcitx.fcitx5.android.utils.navigateWithAnim
|
||||
import org.fcitx.fcitx5.android.utils.parcelable
|
||||
import org.fcitx.fcitx5.android.utils.startActivity
|
||||
import splitties.dimensions.dp
|
||||
import splitties.resources.styledColor
|
||||
@ -65,6 +69,7 @@ class MainActivity : AppCompatActivity() {
|
||||
// because navController would change toolbar title, we need to control it by ourselves
|
||||
setupToolbarMenu(binding.toolbar.menu)
|
||||
navController = binding.navHostFragment.getFragment<NavHostFragment>().navController
|
||||
navController.graph = SettingsRoute.createGraph(navController)
|
||||
binding.toolbar.setNavigationOnClickListener {
|
||||
// prevent navigate up when child fragment has enabled `OnBackPressedCallback`
|
||||
if (onBackPressedDispatcher.hasEnabledCallbacks()) {
|
||||
@ -82,38 +87,43 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
navController.addOnDestinationChangedListener { _, dest, _ ->
|
||||
dest.label?.let { viewModel.setToolbarTitle(it.toString()) }
|
||||
when (dest.id) {
|
||||
R.id.themeFragment -> viewModel.disableToolbarShadow()
|
||||
else -> viewModel.enableToolbarShadow()
|
||||
if (dest.hasRoute<SettingsRoute.Theme>()) {
|
||||
viewModel.disableToolbarShadow()
|
||||
} else {
|
||||
viewModel.enableToolbarShadow()
|
||||
}
|
||||
}
|
||||
if (intent?.action == Intent.ACTION_MAIN && SetupActivity.shouldShowUp()) {
|
||||
startActivity<SetupActivity>()
|
||||
} else {
|
||||
processIntent(intent)
|
||||
}
|
||||
addOnNewIntentListener {
|
||||
processIntent(it)
|
||||
}
|
||||
processIntent(intent)
|
||||
checkNotificationPermission()
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent) {
|
||||
super.onNewIntent(intent)
|
||||
processIntent(intent)
|
||||
}
|
||||
|
||||
private fun processIntent(intent: Intent?) {
|
||||
if (intent?.action == Intent.ACTION_VIEW) {
|
||||
intent.data?.let {
|
||||
val action = intent?.action ?: return
|
||||
when (action) {
|
||||
Intent.ACTION_MAIN -> if (SetupActivity.shouldShowUp()) {
|
||||
startActivity<SetupActivity>()
|
||||
}
|
||||
Intent.ACTION_VIEW -> intent.data?.let {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(R.string.pinyin_dict)
|
||||
.setMessage(R.string.whether_import_dict)
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
navController.popBackStack(R.id.mainFragment, false)
|
||||
navController.navigate(
|
||||
R.id.action_mainFragment_to_pinyinDictionaryFragment,
|
||||
bundleOf(PinyinDictionaryFragment.INTENT_DATA_URI to it)
|
||||
)
|
||||
navController.popBackStack(SettingsRoute.Index, false)
|
||||
navController.navigateWithAnim(SettingsRoute.PinyinDict(it))
|
||||
}
|
||||
.show()
|
||||
}
|
||||
Intent.ACTION_RUN -> {
|
||||
val route = intent.parcelable<SettingsRoute>(EXTRA_SETTINGS_ROUTE) ?: return
|
||||
navController.popBackStack(SettingsRoute.Index, false)
|
||||
navController.navigateWithAnim(route)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,13 +137,14 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
val aboutMenuItems = listOf(
|
||||
menu.item(R.string.faq) {
|
||||
@SuppressLint("UseKtx")
|
||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(Const.faqUrl)))
|
||||
},
|
||||
menu.item(R.string.developer) {
|
||||
navController.navigate(R.id.action_mainFragment_to_developerFragment)
|
||||
navController.navigateWithAnim(SettingsRoute.Developer)
|
||||
},
|
||||
menu.item(R.string.about) {
|
||||
navController.navigate(R.id.action_mainFragment_to_aboutFragment)
|
||||
navController.navigateWithAnim(SettingsRoute.About)
|
||||
}
|
||||
)
|
||||
viewModel.aboutButton.observe(this@MainActivity) { enabled ->
|
||||
@ -199,4 +210,8 @@ class MainActivity : AppCompatActivity() {
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val EXTRA_SETTINGS_ROUTE = "${BuildConfig.APPLICATION_ID}.EXTRA_SETTINGS_ROUTE"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,15 +6,15 @@ package org.fcitx.fcitx5.android.ui.main
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.PreferenceCategory
|
||||
import org.fcitx.fcitx5.android.R
|
||||
import org.fcitx.fcitx5.android.ui.common.PaddingPreferenceFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.SettingsRoute
|
||||
import org.fcitx.fcitx5.android.utils.addCategory
|
||||
import org.fcitx.fcitx5.android.utils.addPreference
|
||||
import org.fcitx.fcitx5.android.utils.navigateWithAnim
|
||||
|
||||
class MainFragment : PaddingPreferenceFragment() {
|
||||
|
||||
@ -33,10 +33,10 @@ class MainFragment : PaddingPreferenceFragment() {
|
||||
private fun PreferenceCategory.addDestinationPreference(
|
||||
@StringRes title: Int,
|
||||
@DrawableRes icon: Int,
|
||||
@IdRes destination: Int
|
||||
route: SettingsRoute
|
||||
) {
|
||||
addPreference(title, icon = icon) {
|
||||
findNavController().navigate(destination)
|
||||
navigateWithAnim(route)
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,54 +46,54 @@ class MainFragment : PaddingPreferenceFragment() {
|
||||
addDestinationPreference(
|
||||
R.string.global_options,
|
||||
R.drawable.ic_baseline_tune_24,
|
||||
R.id.action_mainFragment_to_globalConfigFragment
|
||||
SettingsRoute.GlobalConfig
|
||||
)
|
||||
addDestinationPreference(
|
||||
R.string.input_methods,
|
||||
R.drawable.ic_baseline_language_24,
|
||||
R.id.action_mainFragment_to_imListFragment
|
||||
SettingsRoute.InputMethodList
|
||||
)
|
||||
addDestinationPreference(
|
||||
R.string.addons,
|
||||
R.drawable.ic_baseline_extension_24,
|
||||
R.id.action_mainFragment_to_addonListFragment
|
||||
SettingsRoute.AddonList
|
||||
)
|
||||
}
|
||||
addCategory("Android") {
|
||||
addDestinationPreference(
|
||||
R.string.theme,
|
||||
R.drawable.ic_baseline_palette_24,
|
||||
R.id.action_mainFragment_to_themeFragment
|
||||
SettingsRoute.Theme
|
||||
)
|
||||
addDestinationPreference(
|
||||
R.string.virtual_keyboard,
|
||||
R.drawable.ic_baseline_keyboard_24,
|
||||
R.id.action_mainFragment_to_keyboardSettingsFragment
|
||||
SettingsRoute.VirtualKeyboard
|
||||
)
|
||||
addDestinationPreference(
|
||||
R.string.candidates_window,
|
||||
R.drawable.ic_baseline_list_alt_24,
|
||||
R.id.action_mainFragment_to_candidatesSettingsFragment
|
||||
SettingsRoute.CandidatesWindow
|
||||
)
|
||||
addDestinationPreference(
|
||||
R.string.clipboard,
|
||||
R.drawable.ic_clipboard,
|
||||
R.id.action_mainFragment_to_clipboardSettingsFragment
|
||||
SettingsRoute.Clipboard
|
||||
)
|
||||
addDestinationPreference(
|
||||
R.string.emoji_and_symbols,
|
||||
R.drawable.ic_baseline_emoji_symbols_24,
|
||||
R.id.action_mainFragment_to_symbolSettingsFragment
|
||||
SettingsRoute.Symbol
|
||||
)
|
||||
addDestinationPreference(
|
||||
R.string.plugins,
|
||||
R.drawable.ic_baseline_android_24,
|
||||
R.id.action_mainFragment_to_pluginFragment
|
||||
SettingsRoute.Plugin
|
||||
)
|
||||
addDestinationPreference(
|
||||
R.string.advanced,
|
||||
R.drawable.ic_baseline_more_horiz_24,
|
||||
R.id.action_mainFragment_to_advancedSettingsFragment
|
||||
SettingsRoute.Advanced
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main.settings
|
||||
|
||||
@ -39,10 +39,6 @@ abstract class FcitxPreferenceFragment : PaddingPreferenceFragment() {
|
||||
private val fcitx: FcitxConnection
|
||||
get() = viewModel.fcitx
|
||||
|
||||
fun requireStringArg(key: String) =
|
||||
requireArguments().getString(key)
|
||||
?: throw IllegalStateException("No $key found in bundle")
|
||||
|
||||
private fun save() {
|
||||
if (!configLoaded) return
|
||||
// launch "saveConfig" job under supervisorJob scope
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main.settings
|
||||
|
||||
@ -19,15 +19,18 @@ import org.fcitx.fcitx5.android.ui.common.DynamicListUi
|
||||
import org.fcitx.fcitx5.android.ui.main.MainViewModel
|
||||
import org.fcitx.fcitx5.android.utils.config.ConfigDescriptor
|
||||
import org.fcitx.fcitx5.android.utils.config.ConfigType
|
||||
import org.fcitx.fcitx5.android.utils.parcelable
|
||||
import org.fcitx.fcitx5.android.utils.lazyRoute
|
||||
|
||||
class ListFragment : Fragment() {
|
||||
|
||||
private val descriptor: ConfigDescriptor<*, out List<*>> by lazy {
|
||||
requireArguments().parcelable(ARG_DESC)!!
|
||||
val args by lazyRoute<SettingsRoute.ListConfig>()
|
||||
|
||||
private val descriptor: ConfigDescriptor<*, *> by lazy {
|
||||
args.desc
|
||||
}
|
||||
|
||||
private val cfg: RawConfig by lazy {
|
||||
requireArguments().parcelable(ARG_CFG)!!
|
||||
args.cfg
|
||||
}
|
||||
|
||||
private val viewModel: MainViewModel by activityViewModels()
|
||||
@ -158,8 +161,6 @@ class ListFragment : Fragment() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ARG_DESC = "desc"
|
||||
const val ARG_CFG = "cfg"
|
||||
val supportedSubtypes = listOf(
|
||||
ConfigType.TyEnum,
|
||||
ConfigType.TyString,
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main.settings
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.net.Uri
|
||||
@ -33,13 +34,15 @@ import org.fcitx.fcitx5.android.ui.common.OnItemChangedListener
|
||||
import org.fcitx.fcitx5.android.ui.main.MainViewModel
|
||||
import org.fcitx.fcitx5.android.utils.NaiveDustman
|
||||
import org.fcitx.fcitx5.android.utils.importErrorDialog
|
||||
import org.fcitx.fcitx5.android.utils.lazyRoute
|
||||
import org.fcitx.fcitx5.android.utils.notificationManager
|
||||
import org.fcitx.fcitx5.android.utils.parcelable
|
||||
import org.fcitx.fcitx5.android.utils.queryFileName
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
|
||||
class PinyinDictionaryFragment : Fragment(), OnItemChangedListener<PinyinDictionary> {
|
||||
|
||||
private val args by lazyRoute<SettingsRoute.PinyinDict>()
|
||||
|
||||
private val viewModel: MainViewModel by activityViewModels()
|
||||
|
||||
private lateinit var launcher: ActivityResultLauncher<String>
|
||||
@ -105,8 +108,8 @@ class PinyinDictionaryFragment : Fragment(), OnItemChangedListener<PinyinDiction
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
arguments?.parcelable<Uri>(INTENT_DATA_URI)
|
||||
?.let { importFromUri(it) }
|
||||
@SuppressLint("UseKtx")
|
||||
args.uri?.let { importFromUri(Uri.parse(it)) }
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
}
|
||||
|
||||
@ -247,6 +250,5 @@ class PinyinDictionaryFragment : Fragment(), OnItemChangedListener<PinyinDiction
|
||||
private var RELOAD_ID = 0
|
||||
private var IMPORT_ID = 0
|
||||
const val CHANNEL_ID = "pinyin_dict"
|
||||
const val INTENT_DATA_URI = "uri"
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2024 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main.settings
|
||||
|
||||
@ -8,9 +8,7 @@ import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.preference.DialogPreference
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.ListPreference
|
||||
@ -26,9 +24,6 @@ import org.fcitx.fcitx5.android.core.Key
|
||||
import org.fcitx.fcitx5.android.core.RawConfig
|
||||
import org.fcitx.fcitx5.android.data.prefs.AppPrefs
|
||||
import org.fcitx.fcitx5.android.ui.main.modified.MySwitchPreference
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.addon.AddonConfigFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.global.GlobalConfigFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.im.InputMethodConfigFragment
|
||||
import org.fcitx.fcitx5.android.utils.LongClickPreference
|
||||
import org.fcitx.fcitx5.android.utils.buildDocumentsProviderIntent
|
||||
import org.fcitx.fcitx5.android.utils.buildPrimaryStorageIntent
|
||||
@ -43,8 +38,10 @@ import org.fcitx.fcitx5.android.utils.config.ConfigDescriptor.ConfigKey
|
||||
import org.fcitx.fcitx5.android.utils.config.ConfigDescriptor.ConfigList
|
||||
import org.fcitx.fcitx5.android.utils.config.ConfigDescriptor.ConfigString
|
||||
import org.fcitx.fcitx5.android.utils.config.ConfigType
|
||||
import org.fcitx.fcitx5.android.utils.navigateWithAnim
|
||||
import org.fcitx.fcitx5.android.utils.parcelableArray
|
||||
import org.fcitx.fcitx5.android.utils.toast
|
||||
import timber.log.Timber
|
||||
|
||||
object PreferenceScreenFactory {
|
||||
|
||||
@ -61,24 +58,19 @@ object PreferenceScreenFactory {
|
||||
val cfg = raw["cfg"]
|
||||
val desc = raw["desc"]
|
||||
val store = FcitxRawConfigStore(cfg)
|
||||
|
||||
ConfigDescriptor
|
||||
.parseTopLevel(desc)
|
||||
.getOrElse { throw it }
|
||||
.let {
|
||||
screen.title = it.name
|
||||
it.values.forEach { d ->
|
||||
general(context, fragmentManager, cfg, screen, d, store, save)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: needs some error handling
|
||||
val topLevelDesc = ConfigDescriptor.parseTopLevel(desc).getOrElse { throw it }
|
||||
screen.title = topLevelDesc.name
|
||||
topLevelDesc.values.forEach {
|
||||
general(context, fragmentManager, cfg.findByName(it.name), screen, it, store, save)
|
||||
}
|
||||
return screen
|
||||
}
|
||||
|
||||
private fun general(
|
||||
context: Context,
|
||||
fragmentManager: FragmentManager,
|
||||
cfg: RawConfig,
|
||||
cfg: RawConfig?,
|
||||
screen: PreferenceScreen,
|
||||
descriptor: ConfigDescriptor<*, *>,
|
||||
store: PreferenceDataStore,
|
||||
@ -86,8 +78,9 @@ object PreferenceScreenFactory {
|
||||
) {
|
||||
|
||||
// Hide key related configs
|
||||
if (hideKeyConfig && ConfigType.pretty(descriptor.type).contains("Key"))
|
||||
if (hideKeyConfig && ConfigType.pretty(descriptor.type).contains("Key")) {
|
||||
return
|
||||
}
|
||||
|
||||
if (descriptor is ConfigCustom) {
|
||||
custom(context, fragmentManager, cfg, screen, descriptor, save)
|
||||
@ -99,70 +92,43 @@ object PreferenceScreenFactory {
|
||||
"${context.getString(R.string.unimplemented_type)} '${ConfigType.pretty(descriptor.type)}'"
|
||||
}
|
||||
|
||||
fun <T : Any> navigate(route: T): Boolean {
|
||||
return try {
|
||||
fragmentManager.primaryNavigationFragment!!.navigateWithAnim(route)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
Timber.w("Unable to navigate(route=$route): $e")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun pinyinDictionary() = Preference(context).apply {
|
||||
setOnPreferenceClickListener {
|
||||
val currentFragment = fragmentManager.findFragmentById(R.id.nav_host_fragment)!!
|
||||
val action = when (currentFragment) {
|
||||
is AddonConfigFragment -> R.id.action_addonConfigFragment_to_pinyinDictionaryFragment
|
||||
is InputMethodConfigFragment -> R.id.action_imConfigFragment_to_pinyinDictionaryFragment
|
||||
else -> throw IllegalStateException("Can not navigate to pinyin dictionary from current fragment")
|
||||
}
|
||||
currentFragment.findNavController().navigate(action)
|
||||
true
|
||||
navigate(SettingsRoute.PinyinDict(""))
|
||||
}
|
||||
}
|
||||
|
||||
fun punctuationEditor(title: String, lang: String?) = Preference(context).apply {
|
||||
setOnPreferenceClickListener {
|
||||
val currentFragment = fragmentManager.findFragmentById(R.id.nav_host_fragment)!!
|
||||
val action = when (currentFragment) {
|
||||
is AddonConfigFragment -> R.id.action_addonConfigFragment_to_punctuationEditorFragment
|
||||
is InputMethodConfigFragment -> R.id.action_imConfigFragment_to_punctuationEditorFragment
|
||||
else -> throw IllegalStateException("Can not navigate to punctuation editor from current fragment")
|
||||
}
|
||||
currentFragment.findNavController().navigate(
|
||||
action,
|
||||
bundleOf(
|
||||
PunctuationEditorFragment.TITLE to title,
|
||||
PunctuationEditorFragment.LANG to lang
|
||||
)
|
||||
)
|
||||
true
|
||||
navigate(SettingsRoute.Punctuation(title, lang))
|
||||
}
|
||||
}
|
||||
|
||||
fun quickPhraseEditor() = Preference(context).apply {
|
||||
setOnPreferenceClickListener {
|
||||
val currentFragment = fragmentManager.findFragmentById(R.id.nav_host_fragment)!!
|
||||
val action = when (currentFragment) {
|
||||
is AddonConfigFragment -> R.id.action_addonConfigFragment_to_quickPhraseListFragment
|
||||
is InputMethodConfigFragment -> R.id.action_imConfigFragment_to_quickPhraseListFragment
|
||||
else -> throw IllegalStateException("Can not navigate to quick phrase editor from current fragment")
|
||||
}
|
||||
currentFragment.findNavController().navigate(action)
|
||||
true
|
||||
navigate(SettingsRoute.QuickPhraseList)
|
||||
}
|
||||
}
|
||||
|
||||
fun tableInputMethod() = Preference(context).apply {
|
||||
setOnPreferenceClickListener {
|
||||
val currentFragment = fragmentManager.findFragmentById(R.id.nav_host_fragment)!!
|
||||
currentFragment.findNavController()
|
||||
.navigate(R.id.action_addonConfigFragment_to_tableInputMethodFragment)
|
||||
true
|
||||
navigate(SettingsRoute.TableInputMethods)
|
||||
}
|
||||
}
|
||||
|
||||
fun pinyinCustomPhrase() = Preference(context).apply {
|
||||
setOnPreferenceClickListener {
|
||||
val currentFragment = fragmentManager.findFragmentById(R.id.nav_host_fragment)!!
|
||||
val action = when (currentFragment) {
|
||||
is AddonConfigFragment -> R.id.action_addonConfigFragment_to_pinyinCustomPhraseFragment
|
||||
is InputMethodConfigFragment -> R.id.action_imConfigFragment_to_pinyinCustomPhraseFragment
|
||||
else -> throw IllegalStateException("Can not navigate to custom phrase editor from current fragment")
|
||||
}
|
||||
currentFragment.findNavController().navigate(action)
|
||||
true
|
||||
navigate(SettingsRoute.PinyinCustomPhrase)
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,25 +163,12 @@ object PreferenceScreenFactory {
|
||||
|
||||
fun listPreference(subtype: ConfigType<*>): Preference = object : Preference(context) {
|
||||
override fun onClick() {
|
||||
val currentFragment = fragmentManager.findFragmentById(R.id.nav_host_fragment)!!
|
||||
val action = when (currentFragment) {
|
||||
is GlobalConfigFragment -> R.id.action_globalConfigFragment_to_listFragment
|
||||
is InputMethodConfigFragment -> R.id.action_imConfigFragment_to_listFragment
|
||||
is AddonConfigFragment -> R.id.action_addonConfigFragment_to_listFragment
|
||||
else -> throw IllegalStateException("Can not navigate to listFragment from current fragment")
|
||||
}
|
||||
currentFragment.findNavController().navigate(
|
||||
action,
|
||||
bundleOf(
|
||||
ListFragment.ARG_CFG to cfg[descriptor.name],
|
||||
ListFragment.ARG_DESC to descriptor,
|
||||
)
|
||||
)
|
||||
navigate(SettingsRoute.ListConfig(cfg ?: RawConfig(), descriptor.raw))
|
||||
fragmentManager.setFragmentResultListener(
|
||||
descriptor.name,
|
||||
currentFragment
|
||||
fragmentManager.primaryNavigationFragment!!
|
||||
) { _, v ->
|
||||
cfg[descriptor.name].subItems = v.parcelableArray(descriptor.name)
|
||||
cfg?.subItems = v.parcelableArray(descriptor.name)
|
||||
if (callChangeListener(null)) {
|
||||
notifyChanged()
|
||||
}
|
||||
@ -224,30 +177,19 @@ object PreferenceScreenFactory {
|
||||
}.apply {
|
||||
if (subtype == ConfigType.TyKey) {
|
||||
summaryProvider = SummaryProvider<Preference> {
|
||||
val str = cfg[descriptor.name].subItems?.joinToString("\n") {
|
||||
val keys = cfg?.subItems?.joinToString("\n") {
|
||||
Key.parse(it.value).localizedString
|
||||
} ?: ""
|
||||
str.ifEmpty { context.getString(R.string.none) }
|
||||
}
|
||||
if (keys.isNullOrEmpty()) context.getString(R.string.none) else keys
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addonConfigPreference(addon: String) = Preference(context).apply {
|
||||
setOnPreferenceClickListener {
|
||||
val currentFragment = fragmentManager.findFragmentById(R.id.nav_host_fragment)!!
|
||||
val action = when (currentFragment) {
|
||||
is AddonConfigFragment -> R.id.action_addonConfigFragment_self
|
||||
is InputMethodConfigFragment -> R.id.action_imConfigFragment_to_addonConfigFragment
|
||||
else -> throw IllegalStateException("Can not navigate to addonConfigFragment from current fragment")
|
||||
}
|
||||
currentFragment.findNavController().navigate(
|
||||
action,
|
||||
bundleOf(
|
||||
AddonConfigFragment.ARG_UNIQUE_NAME to addon,
|
||||
AddonConfigFragment.ARG_NAME to (descriptor.description ?: descriptor.name)
|
||||
)
|
||||
navigate(
|
||||
SettingsRoute.AddonConfig(descriptor.description ?: descriptor.name, addon)
|
||||
)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,12 +279,12 @@ object PreferenceScreenFactory {
|
||||
private fun custom(
|
||||
context: Context,
|
||||
fragmentManager: FragmentManager,
|
||||
cfg: RawConfig,
|
||||
cfg: RawConfig?,
|
||||
screen: PreferenceScreen,
|
||||
descriptor: ConfigCustom,
|
||||
save: () -> Unit
|
||||
) {
|
||||
val subStore = FcitxRawConfigStore(cfg[descriptor.name])
|
||||
val subStore = FcitxRawConfigStore(cfg ?: RawConfig())
|
||||
val subPref = PreferenceCategory(context).apply {
|
||||
key = descriptor.name
|
||||
title = descriptor.description ?: descriptor.name
|
||||
@ -350,16 +292,8 @@ object PreferenceScreenFactory {
|
||||
isIconSpaceReserved = false
|
||||
}
|
||||
screen.addPreference(subPref)
|
||||
descriptor.customTypeDef!!.values.forEach {
|
||||
general(
|
||||
context,
|
||||
fragmentManager,
|
||||
cfg[descriptor.name],
|
||||
screen,
|
||||
it,
|
||||
subStore,
|
||||
save
|
||||
)
|
||||
descriptor.customTypeDef?.values?.forEach {
|
||||
general(context, fragmentManager, cfg?.findByName(it.name), screen, it, subStore, save)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main.settings
|
||||
|
||||
@ -15,6 +15,7 @@ import org.fcitx.fcitx5.android.data.punctuation.PunctuationMapEntry
|
||||
import org.fcitx.fcitx5.android.ui.common.BaseDynamicListUi
|
||||
import org.fcitx.fcitx5.android.ui.common.OnItemChangedListener
|
||||
import org.fcitx.fcitx5.android.utils.NaiveDustman
|
||||
import org.fcitx.fcitx5.android.utils.lazyRoute
|
||||
import org.fcitx.fcitx5.android.utils.materialTextInput
|
||||
import org.fcitx.fcitx5.android.utils.onPositiveButtonClick
|
||||
import org.fcitx.fcitx5.android.utils.str
|
||||
@ -26,6 +27,8 @@ import splitties.views.setPaddingDp
|
||||
|
||||
class PunctuationEditorFragment : ProgressFragment(), OnItemChangedListener<PunctuationMapEntry> {
|
||||
|
||||
private val args by lazyRoute<SettingsRoute.Punctuation>()
|
||||
|
||||
private lateinit var lang: String
|
||||
private lateinit var keyDesc: String
|
||||
private lateinit var mappingDesc: String
|
||||
@ -60,7 +63,7 @@ class PunctuationEditorFragment : ProgressFragment(), OnItemChangedListener<Punc
|
||||
}
|
||||
|
||||
override suspend fun initialize(): View {
|
||||
lang = requireArguments().getString(LANG, DEFAULT_LANG)
|
||||
lang = args.lang ?: DEFAULT_LANG
|
||||
val raw = fcitx.runOnReady { getPunctuationConfig(lang) }
|
||||
findDesc(raw)
|
||||
val initialEntries = PunctuationManager.parseRawConfig(raw)
|
||||
@ -163,7 +166,7 @@ class PunctuationEditorFragment : ProgressFragment(), OnItemChangedListener<Punc
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
viewModel.setToolbarTitle(requireArguments().getString(TITLE)!!)
|
||||
viewModel.setToolbarTitle(args.title)
|
||||
if (isInitialized) {
|
||||
viewModel.enableToolbarEditButton(ui.entries.isNotEmpty()) {
|
||||
ui.enterMultiSelect(requireActivity().onBackPressedDispatcher)
|
||||
@ -188,8 +191,6 @@ class PunctuationEditorFragment : ProgressFragment(), OnItemChangedListener<Punc
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TITLE = "title"
|
||||
const val LANG = "lang"
|
||||
const val DEFAULT_LANG = "zh_CN"
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main.settings
|
||||
|
||||
@ -14,32 +14,41 @@ import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.fcitx.fcitx5.android.R
|
||||
import org.fcitx.fcitx5.android.data.quickphrase.BuiltinQuickPhrase
|
||||
import org.fcitx.fcitx5.android.data.quickphrase.CustomQuickPhrase
|
||||
import org.fcitx.fcitx5.android.data.quickphrase.QuickPhrase
|
||||
import org.fcitx.fcitx5.android.data.quickphrase.QuickPhraseData
|
||||
import org.fcitx.fcitx5.android.data.quickphrase.QuickPhraseEntry
|
||||
import org.fcitx.fcitx5.android.ui.common.BaseDynamicListUi
|
||||
import org.fcitx.fcitx5.android.ui.common.OnItemChangedListener
|
||||
import org.fcitx.fcitx5.android.utils.NaiveDustman
|
||||
import org.fcitx.fcitx5.android.utils.lazyRoute
|
||||
import org.fcitx.fcitx5.android.utils.materialTextInput
|
||||
import org.fcitx.fcitx5.android.utils.onPositiveButtonClick
|
||||
import org.fcitx.fcitx5.android.utils.serializable
|
||||
import org.fcitx.fcitx5.android.utils.str
|
||||
import splitties.views.dsl.core.add
|
||||
import splitties.views.dsl.core.lParams
|
||||
import splitties.views.dsl.core.matchParent
|
||||
import splitties.views.dsl.core.verticalLayout
|
||||
import splitties.views.setPaddingDp
|
||||
import java.io.File
|
||||
|
||||
class QuickPhraseEditFragment : ProgressFragment(), OnItemChangedListener<QuickPhraseEntry> {
|
||||
private val args by lazyRoute<SettingsRoute.QuickPhraseEdit>()
|
||||
|
||||
private val quickPhrase: QuickPhrase by lazy {
|
||||
if (args.isBuiltIn) {
|
||||
BuiltinQuickPhrase(File(args.path), File(args.override ?: ""))
|
||||
} else {
|
||||
CustomQuickPhrase(File(args.path))
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var ui: BaseDynamicListUi<QuickPhraseEntry>
|
||||
|
||||
private lateinit var quickPhrase: QuickPhrase
|
||||
|
||||
private val dustman = NaiveDustman<QuickPhraseEntry>()
|
||||
|
||||
override suspend fun initialize(): View {
|
||||
quickPhrase = requireArguments().serializable(ARG)!!
|
||||
val initialEntries = withContext(Dispatchers.IO) {
|
||||
quickPhrase.loadData()
|
||||
}
|
||||
@ -185,7 +194,6 @@ class QuickPhraseEditFragment : ProgressFragment(), OnItemChangedListener<QuickP
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ARG = "quickphrase"
|
||||
const val RESULT = "dirty"
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main.settings
|
||||
|
||||
@ -17,11 +17,9 @@ import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.launch
|
||||
@ -39,6 +37,7 @@ import org.fcitx.fcitx5.android.utils.NaiveDustman
|
||||
import org.fcitx.fcitx5.android.utils.importErrorDialog
|
||||
import org.fcitx.fcitx5.android.utils.item
|
||||
import org.fcitx.fcitx5.android.utils.materialTextInput
|
||||
import org.fcitx.fcitx5.android.utils.navigateWithAnim
|
||||
import org.fcitx.fcitx5.android.utils.notificationManager
|
||||
import org.fcitx.fcitx5.android.utils.onPositiveButtonClick
|
||||
import org.fcitx.fcitx5.android.utils.queryFileName
|
||||
@ -82,10 +81,7 @@ class QuickPhraseListFragment : Fragment(), OnItemChangedListener<QuickPhrase> {
|
||||
initSettingsButton = { entry ->
|
||||
visibility = if (!entry.isEnabled) View.GONE else View.VISIBLE
|
||||
fun edit() {
|
||||
findNavController().navigate(
|
||||
R.id.action_quickPhraseListFragment_to_quickPhraseEditFragment,
|
||||
bundleOf(QuickPhraseEditFragment.ARG to entry)
|
||||
)
|
||||
navigateWithAnim(SettingsRoute.QuickPhraseEdit.from(entry))
|
||||
parentFragmentManager.setFragmentResultListener(
|
||||
QuickPhraseEditFragment.RESULT,
|
||||
this@QuickPhraseListFragment
|
||||
|
||||
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
|
||||
package org.fcitx.fcitx5.android.ui.main.settings
|
||||
|
||||
import android.net.Uri
|
||||
import android.os.Parcelable
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.createGraph
|
||||
import androidx.navigation.fragment.fragment
|
||||
import androidx.savedstate.SavedState
|
||||
import arrow.core.getOrElse
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.fcitx.fcitx5.android.R
|
||||
import org.fcitx.fcitx5.android.core.RawConfig
|
||||
import org.fcitx.fcitx5.android.data.quickphrase.BuiltinQuickPhrase
|
||||
import org.fcitx.fcitx5.android.data.quickphrase.CustomQuickPhrase
|
||||
import org.fcitx.fcitx5.android.data.quickphrase.QuickPhrase
|
||||
import org.fcitx.fcitx5.android.ui.main.AboutFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.DeveloperFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.LicensesFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.MainFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.PluginFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.addon.AddonConfigFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.addon.AddonListFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.behavior.AdvancedSettingsFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.behavior.CandidatesSettingsFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.behavior.ClipboardSettingsFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.behavior.KeyboardSettingsFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.behavior.SymbolSettingsFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.global.GlobalConfigFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.im.InputMethodConfigFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.im.InputMethodListFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.theme.ThemeFragment
|
||||
import org.fcitx.fcitx5.android.utils.config.ConfigDescriptor
|
||||
import org.fcitx.fcitx5.android.utils.parcelable
|
||||
import kotlin.reflect.typeOf
|
||||
|
||||
@Parcelize
|
||||
sealed class SettingsRoute : Parcelable {
|
||||
|
||||
/* ========== Index ========== */
|
||||
|
||||
@Serializable
|
||||
data object Index : SettingsRoute()
|
||||
|
||||
/* ========== Fcitx ========== */
|
||||
|
||||
@Serializable
|
||||
data object GlobalConfig : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object InputMethodList : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data class InputMethodConfig(val name: String, val uniqueName: String) : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object AddonList : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data class AddonConfig(val name: String, val uniqueName: String) : SettingsRoute()
|
||||
|
||||
/* ========== Android ========== */
|
||||
|
||||
@Serializable
|
||||
data object Theme : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object VirtualKeyboard : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object CandidatesWindow : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object Clipboard : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object Symbol : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object Plugin : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object Advanced : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object Developer : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object License : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object About : SettingsRoute()
|
||||
|
||||
/* ========== External ========== */
|
||||
|
||||
@Serializable
|
||||
data class ListConfig(val params: Params) : SettingsRoute() {
|
||||
@Parcelize
|
||||
@Serializable
|
||||
data class Params(val cfg: RawConfig, val desc: RawConfig) : Parcelable {
|
||||
companion object {
|
||||
// https://developer.android.com/guide/navigation/design/kotlin-dsl#custom-types
|
||||
val NavType = object : NavType<Params>(isNullableAllowed = false) {
|
||||
override fun put(bundle: SavedState, key: String, value: Params) {
|
||||
bundle.putParcelable(key, value)
|
||||
}
|
||||
|
||||
override fun get(bundle: SavedState, key: String): Params? {
|
||||
return bundle.parcelable<Params>(key)
|
||||
}
|
||||
|
||||
override fun serializeAsValue(value: Params): String {
|
||||
// Serialized values must always be Uri encoded
|
||||
return Uri.encode(Json.encodeToString(value))
|
||||
}
|
||||
|
||||
override fun parseValue(value: String): Params {
|
||||
// Navigation decodes the string before passing it to parseValue()
|
||||
return Json.decodeFromString(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(cfg: RawConfig, desc: RawConfig) : this(Params(cfg, desc))
|
||||
|
||||
val desc: ConfigDescriptor<*, *>
|
||||
get() = ConfigDescriptor.parse(params.desc).getOrElse { throw it }
|
||||
|
||||
val cfg: RawConfig
|
||||
get() = params.cfg
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class PinyinDict(val uri: String? = null) : SettingsRoute() {
|
||||
constructor(uri: Uri) : this(uri.toString())
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Punctuation(val title: String, val lang: String? = null) : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object QuickPhraseList : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data class QuickPhraseEdit(
|
||||
val path: String,
|
||||
val isBuiltIn: Boolean = false,
|
||||
val override: String? = null
|
||||
) : SettingsRoute() {
|
||||
companion object {
|
||||
fun from(q: QuickPhrase) = when (q) {
|
||||
is CustomQuickPhrase -> QuickPhraseEdit(q.file.absolutePath)
|
||||
is BuiltinQuickPhrase -> QuickPhraseEdit(
|
||||
q.file.absolutePath, true, q.override?.file?.absolutePath
|
||||
)
|
||||
else -> throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data object TableInputMethods : SettingsRoute()
|
||||
|
||||
@Serializable
|
||||
data object PinyinCustomPhrase : SettingsRoute()
|
||||
|
||||
companion object {
|
||||
fun createGraph(controller: NavController) = controller.createGraph(Index) {
|
||||
val ctx = controller.context
|
||||
|
||||
/* ========== Index ========== */
|
||||
|
||||
fragment<MainFragment, Index> {
|
||||
label = ctx.getString(R.string.app_name)
|
||||
}
|
||||
|
||||
/* ========== Fcitx ========== */
|
||||
|
||||
fragment<GlobalConfigFragment, GlobalConfig>()
|
||||
fragment<InputMethodListFragment, InputMethodList> {
|
||||
label = ctx.getString(R.string.input_methods)
|
||||
}
|
||||
fragment<InputMethodConfigFragment, InputMethodConfig>()
|
||||
fragment<AddonListFragment, AddonList> {
|
||||
label = ctx.getString(R.string.addons)
|
||||
}
|
||||
fragment<AddonConfigFragment, AddonConfig>()
|
||||
|
||||
/* ========== Android ========== */
|
||||
|
||||
fragment<ThemeFragment, Theme> {
|
||||
label = ctx.getString(R.string.theme)
|
||||
}
|
||||
fragment<KeyboardSettingsFragment, VirtualKeyboard> {
|
||||
label = ctx.getString(R.string.virtual_keyboard)
|
||||
}
|
||||
fragment<CandidatesSettingsFragment, CandidatesWindow> {
|
||||
label = ctx.getString(R.string.candidates_window)
|
||||
}
|
||||
fragment<ClipboardSettingsFragment, Clipboard> {
|
||||
label = ctx.getString(R.string.clipboard)
|
||||
}
|
||||
fragment<SymbolSettingsFragment, Symbol> {
|
||||
label = ctx.getString(R.string.emoji_and_symbols)
|
||||
}
|
||||
fragment<PluginFragment, Plugin> {
|
||||
label = ctx.getString(R.string.plugins)
|
||||
}
|
||||
fragment<AdvancedSettingsFragment, Advanced> {
|
||||
label = ctx.getString(R.string.advanced)
|
||||
}
|
||||
fragment<DeveloperFragment, Developer> {
|
||||
label = ctx.getString(R.string.developer)
|
||||
}
|
||||
fragment<LicensesFragment, License> {
|
||||
label = ctx.getString(R.string.license)
|
||||
}
|
||||
fragment<AboutFragment, About> {
|
||||
label = ctx.getString(R.string.about)
|
||||
}
|
||||
|
||||
/* ========== External ========== */
|
||||
|
||||
fragment<ListFragment, ListConfig>(
|
||||
typeMap = mapOf(typeOf<ListConfig.Params>() to ListConfig.Params.NavType)
|
||||
)
|
||||
fragment<PinyinDictionaryFragment, PinyinDict> {
|
||||
label = ctx.getString(R.string.pinyin_dict)
|
||||
}
|
||||
fragment<PunctuationEditorFragment, Punctuation>()
|
||||
fragment<QuickPhraseListFragment, QuickPhraseList> {
|
||||
label = ctx.getString(R.string.quickphrase_editor)
|
||||
}
|
||||
fragment<QuickPhraseEditFragment, QuickPhraseEdit>()
|
||||
fragment<TableInputMethodFragment, TableInputMethods> {
|
||||
label = ctx.getString(R.string.table_im)
|
||||
}
|
||||
fragment<PinyinCustomPhraseFragment, PinyinCustomPhrase>()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main.settings.addon
|
||||
|
||||
@ -8,12 +8,16 @@ import org.fcitx.fcitx5.android.R
|
||||
import org.fcitx.fcitx5.android.core.FcitxAPI
|
||||
import org.fcitx.fcitx5.android.core.RawConfig
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.FcitxPreferenceFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.SettingsRoute
|
||||
import org.fcitx.fcitx5.android.utils.lazyRoute
|
||||
|
||||
class AddonConfigFragment : FcitxPreferenceFragment() {
|
||||
override fun getPageTitle(): String = requireStringArg(ARG_NAME)
|
||||
private val args by lazyRoute<SettingsRoute.AddonConfig>()
|
||||
|
||||
override fun getPageTitle(): String = args.name
|
||||
|
||||
override suspend fun obtainConfig(fcitx: FcitxAPI): RawConfig {
|
||||
val addon = requireStringArg(ARG_UNIQUE_NAME)
|
||||
val addon = args.uniqueName
|
||||
val raw = fcitx.getAddonConfig(addon)
|
||||
if (addon == "table") {
|
||||
// append android specific "Manage Table Input Methods" to config of table addon
|
||||
@ -30,12 +34,6 @@ class AddonConfigFragment : FcitxPreferenceFragment() {
|
||||
}
|
||||
|
||||
override suspend fun saveConfig(fcitx: FcitxAPI, newConfig: RawConfig) {
|
||||
fcitx.setAddonConfig(requireStringArg(ARG_UNIQUE_NAME), newConfig)
|
||||
fcitx.setAddonConfig(args.uniqueName, newConfig)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ARG_UNIQUE_NAME = "addon"
|
||||
const val ARG_NAME = "addon_"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main.settings.addon
|
||||
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.navigation.findNavController
|
||||
import org.fcitx.fcitx5.android.R
|
||||
import org.fcitx.fcitx5.android.core.AddonInfo
|
||||
import org.fcitx.fcitx5.android.core.FcitxAPI
|
||||
@ -17,6 +15,8 @@ import org.fcitx.fcitx5.android.ui.common.BaseDynamicListUi
|
||||
import org.fcitx.fcitx5.android.ui.common.CheckBoxListUi
|
||||
import org.fcitx.fcitx5.android.ui.common.OnItemChangedListener
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.ProgressFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.SettingsRoute
|
||||
import org.fcitx.fcitx5.android.utils.navigateWithAnim
|
||||
|
||||
class AddonListFragment : ProgressFragment(), OnItemChangedListener<AddonInfo> {
|
||||
|
||||
@ -120,12 +120,8 @@ class AddonListFragment : ProgressFragment(), OnItemChangedListener<AddonInfo> {
|
||||
entry.uniqueName != "clipboard"
|
||||
) View.VISIBLE else View.INVISIBLE
|
||||
setOnClickListener {
|
||||
it.findNavController().navigate(
|
||||
R.id.action_addonListFragment_to_addonConfigFragment,
|
||||
bundleOf(
|
||||
AddonConfigFragment.ARG_UNIQUE_NAME to entry.uniqueName,
|
||||
AddonConfigFragment.ARG_NAME to entry.displayName
|
||||
)
|
||||
navigateWithAnim(
|
||||
SettingsRoute.AddonConfig(entry.displayName, entry.uniqueName)
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
@ -1,26 +1,25 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main.settings.im
|
||||
|
||||
import org.fcitx.fcitx5.android.core.FcitxAPI
|
||||
import org.fcitx.fcitx5.android.core.RawConfig
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.FcitxPreferenceFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.SettingsRoute
|
||||
import org.fcitx.fcitx5.android.utils.lazyRoute
|
||||
|
||||
class InputMethodConfigFragment : FcitxPreferenceFragment() {
|
||||
override fun getPageTitle(): String = requireStringArg(ARG_NAME)
|
||||
val args by lazyRoute<SettingsRoute.InputMethodConfig>()
|
||||
|
||||
override fun getPageTitle(): String = args.name
|
||||
|
||||
override suspend fun obtainConfig(fcitx: FcitxAPI): RawConfig {
|
||||
return fcitx.getImConfig(requireStringArg(ARG_UNIQUE_NAME))
|
||||
return fcitx.getImConfig(args.uniqueName)
|
||||
}
|
||||
|
||||
override suspend fun saveConfig(fcitx: FcitxAPI, newConfig: RawConfig) {
|
||||
fcitx.setImConfig(requireStringArg(ARG_UNIQUE_NAME), newConfig)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ARG_UNIQUE_NAME = "im"
|
||||
const val ARG_NAME = "im_"
|
||||
fcitx.setImConfig(args.uniqueName, newConfig)
|
||||
}
|
||||
}
|
||||
@ -1,21 +1,20 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.ui.main.settings.im
|
||||
|
||||
import android.os.Build
|
||||
import android.view.View
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.navigation.findNavController
|
||||
import org.fcitx.fcitx5.android.R
|
||||
import org.fcitx.fcitx5.android.core.InputMethodEntry
|
||||
import org.fcitx.fcitx5.android.daemon.launchOnReady
|
||||
import org.fcitx.fcitx5.android.core.SubtypeManager
|
||||
import org.fcitx.fcitx5.android.daemon.launchOnReady
|
||||
import org.fcitx.fcitx5.android.ui.common.BaseDynamicListUi
|
||||
import org.fcitx.fcitx5.android.ui.common.DynamicListUi
|
||||
import org.fcitx.fcitx5.android.ui.common.OnItemChangedListener
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.ProgressFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.SettingsRoute
|
||||
import org.fcitx.fcitx5.android.utils.navigateWithAnim
|
||||
|
||||
class InputMethodListFragment : ProgressFragment(), OnItemChangedListener<InputMethodEntry> {
|
||||
|
||||
@ -43,12 +42,8 @@ class InputMethodListFragment : ProgressFragment(), OnItemChangedListener<InputM
|
||||
enableOrder = true,
|
||||
initSettingsButton = { entry ->
|
||||
setOnClickListener {
|
||||
it.findNavController().navigate(
|
||||
R.id.action_imListFragment_to_imConfigFragment,
|
||||
bundleOf(
|
||||
InputMethodConfigFragment.ARG_UNIQUE_NAME to entry.uniqueName,
|
||||
InputMethodConfigFragment.ARG_NAME to entry.displayName
|
||||
)
|
||||
navigateWithAnim(
|
||||
SettingsRoute.InputMethodConfig(entry.displayName, entry.uniqueName),
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.utils
|
||||
|
||||
@ -10,15 +10,11 @@ import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.navigation.NavDeepLinkBuilder
|
||||
import org.fcitx.fcitx5.android.R
|
||||
import org.fcitx.fcitx5.android.ui.main.ClipboardEditActivity
|
||||
import org.fcitx.fcitx5.android.ui.main.MainActivity
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.im.InputMethodConfigFragment
|
||||
import org.fcitx.fcitx5.android.ui.main.settings.SettingsRoute
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
object AppUtil {
|
||||
@ -29,39 +25,25 @@ object AppUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchMainToDest(context: Context, @IdRes dest: Int, arguments: Bundle? = null) {
|
||||
NavDeepLinkBuilder(context)
|
||||
.setComponentName(MainActivity::class.java)
|
||||
.setGraph(R.navigation.settings_nav)
|
||||
.addDestination(dest, arguments)
|
||||
.createTaskStackBuilder()
|
||||
/**
|
||||
* [androidx.core.app.TaskStackBuilder.getIntents] would add unwanted flags
|
||||
* [Intent.FLAG_ACTIVITY_CLEAR_TASK] and [Intent.FLAG_ACTIVITY_TASK_ON_HOME]
|
||||
* so we must launch the Intent by ourselves
|
||||
*/
|
||||
.editIntentAt(0)?.apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
|
||||
context.startActivity(this)
|
||||
}
|
||||
private fun launchMainToDest(context: Context, route: SettingsRoute) {
|
||||
context.startActivity<MainActivity> {
|
||||
action = Intent.ACTION_RUN
|
||||
putExtra(MainActivity.EXTRA_SETTINGS_ROUTE, route)
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
|
||||
}
|
||||
}
|
||||
|
||||
fun launchMainToKeyboard(context: Context) =
|
||||
launchMainToDest(context, R.id.keyboardSettingsFragment)
|
||||
launchMainToDest(context, SettingsRoute.VirtualKeyboard)
|
||||
|
||||
fun launchMainToInputMethodList(context: Context) =
|
||||
launchMainToDest(context, R.id.imListFragment)
|
||||
launchMainToDest(context, SettingsRoute.InputMethodList)
|
||||
|
||||
fun launchMainToThemeList(context: Context) =
|
||||
launchMainToDest(context, R.id.themeFragment)
|
||||
launchMainToDest(context, SettingsRoute.Theme)
|
||||
|
||||
fun launchMainToInputMethodConfig(context: Context, uniqueName: String, displayName: String) =
|
||||
launchMainToDest(
|
||||
context, R.id.imConfigFragment, bundleOf(
|
||||
InputMethodConfigFragment.ARG_NAME to displayName,
|
||||
InputMethodConfigFragment.ARG_UNIQUE_NAME to uniqueName
|
||||
)
|
||||
)
|
||||
launchMainToDest(context, SettingsRoute.InputMethodConfig(displayName, uniqueName))
|
||||
|
||||
fun launchClipboardEdit(context: Context, id: Int, lastEntry: Boolean = false) {
|
||||
context.startActivity<ClipboardEditActivity> {
|
||||
|
||||
18
app/src/main/java/org/fcitx/fcitx5/android/utils/Fragment.kt
Normal file
18
app/src/main/java/org/fcitx/fcitx5/android/utils/Fragment.kt
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
|
||||
package org.fcitx.fcitx5.android.utils
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.toRoute
|
||||
|
||||
fun <T : Any> Fragment.navigateWithAnim(route: T) {
|
||||
findNavController().navigateWithAnim(route)
|
||||
}
|
||||
|
||||
inline fun <reified T : Any> Fragment.lazyRoute() = lazy {
|
||||
findNavController().getBackStackEntry<T>().toRoute<T>()
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
|
||||
package org.fcitx.fcitx5.android.utils
|
||||
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.navOptions
|
||||
import androidx.navigation.ui.R
|
||||
|
||||
fun <T : Any> NavController.navigateWithAnim(route: T) {
|
||||
navigate(route, navOptions {
|
||||
anim {
|
||||
enter = R.animator.nav_default_enter_anim
|
||||
exit = R.animator.nav_default_exit_anim
|
||||
popEnter = R.animator.nav_default_pop_enter_anim
|
||||
popExit = R.animator.nav_default_pop_exit_anim
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2023 Fcitx5 for Android Contributors
|
||||
* SPDX-FileCopyrightText: Copyright 2021-2025 Fcitx5 for Android Contributors
|
||||
*/
|
||||
package org.fcitx.fcitx5.android.utils.config
|
||||
|
||||
@ -11,8 +11,10 @@ import arrow.core.raise.either
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.parcelize.RawValue
|
||||
import org.fcitx.fcitx5.android.core.RawConfig
|
||||
import org.fcitx.fcitx5.android.utils.config.ConfigDescriptor.Companion.parse
|
||||
|
||||
sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
abstract val raw: RawConfig
|
||||
abstract val name: String
|
||||
abstract val type: ConfigType<T>
|
||||
abstract val description: String?
|
||||
@ -34,6 +36,7 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
|
||||
@Parcelize
|
||||
data class ConfigInt(
|
||||
override val raw: RawConfig,
|
||||
override val name: String,
|
||||
override val description: String? = null,
|
||||
override val defaultValue: Int? = null,
|
||||
@ -47,6 +50,7 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
|
||||
@Parcelize
|
||||
data class ConfigString(
|
||||
override val raw: RawConfig,
|
||||
override val name: String,
|
||||
override val description: String? = null,
|
||||
override val defaultValue: String? = null,
|
||||
@ -58,6 +62,7 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
|
||||
@Parcelize
|
||||
data class ConfigBool(
|
||||
override val raw: RawConfig,
|
||||
override val name: String,
|
||||
override val description: String? = null,
|
||||
override val defaultValue: Boolean? = null,
|
||||
@ -70,6 +75,7 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
|
||||
@Parcelize
|
||||
data class ConfigKey(
|
||||
override val raw: RawConfig,
|
||||
override val name: String,
|
||||
override val description: String? = null,
|
||||
override val defaultValue: String? = null,
|
||||
@ -82,6 +88,7 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
|
||||
@Parcelize
|
||||
data class ConfigEnum(
|
||||
override val raw: RawConfig,
|
||||
override val name: String,
|
||||
override val description: String? = null,
|
||||
override val defaultValue: String? = null,
|
||||
@ -96,6 +103,7 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
|
||||
@Parcelize
|
||||
data class ConfigCustom(
|
||||
override val raw: RawConfig,
|
||||
override val name: String,
|
||||
override val type: ConfigType.TyCustom,
|
||||
override val description: String? = null,
|
||||
@ -109,6 +117,7 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
|
||||
@Parcelize
|
||||
data class ConfigList(
|
||||
override val raw: RawConfig,
|
||||
override val name: String,
|
||||
override val type: ConfigType.TyList,
|
||||
override val description: String? = null,
|
||||
@ -124,6 +133,7 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
*/
|
||||
@Parcelize
|
||||
data class ConfigEnumList(
|
||||
override val raw: RawConfig,
|
||||
override val name: String,
|
||||
override val description: String? = null,
|
||||
override val defaultValue: List<String>? = null,
|
||||
@ -138,6 +148,7 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
|
||||
@Parcelize
|
||||
data class ConfigExternal(
|
||||
override val raw: RawConfig,
|
||||
override val name: String,
|
||||
override val description: String? = null,
|
||||
override val tooltip: String? = null,
|
||||
@ -206,11 +217,13 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
when (it) {
|
||||
ConfigType.TyBool ->
|
||||
ConfigBool(
|
||||
raw,
|
||||
raw.name,
|
||||
raw.description,
|
||||
raw.defaultValue?.toBoolean()
|
||||
)
|
||||
is ConfigType.TyCustom -> ConfigCustom(
|
||||
raw,
|
||||
raw.name,
|
||||
it,
|
||||
raw.description
|
||||
@ -218,6 +231,7 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
ConfigType.TyEnum -> {
|
||||
val entries = raw.enum ?: raise(ParseException.NoEnumFound(raw))
|
||||
ConfigEnum(
|
||||
raw,
|
||||
raw.name,
|
||||
raw.description,
|
||||
raw.defaultValue,
|
||||
@ -227,6 +241,7 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
)
|
||||
}
|
||||
ConfigType.TyInt -> ConfigInt(
|
||||
raw,
|
||||
raw.name,
|
||||
raw.description,
|
||||
raw.defaultValue?.toInt(),
|
||||
@ -234,11 +249,17 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
raw.intMax,
|
||||
raw.intMin
|
||||
)
|
||||
ConfigType.TyKey -> ConfigKey(raw.name, raw.description, raw.defaultValue)
|
||||
ConfigType.TyKey -> ConfigKey(
|
||||
raw,
|
||||
raw.name,
|
||||
raw.description,
|
||||
raw.defaultValue
|
||||
)
|
||||
is ConfigType.TyList ->
|
||||
if (it.subtype == ConfigType.TyEnum) {
|
||||
val entries = raw.enum ?: raise(ParseException.NoEnumFound(raw))
|
||||
ConfigEnumList(
|
||||
raw,
|
||||
raw.name,
|
||||
raw.description,
|
||||
raw.findByName("DefaultValue")?.subItems?.map { ele -> ele.value },
|
||||
@ -248,6 +269,7 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
)
|
||||
} else
|
||||
ConfigList(
|
||||
raw,
|
||||
raw.name,
|
||||
it,
|
||||
raw.description,
|
||||
@ -264,11 +286,13 @@ sealed class ConfigDescriptor<T, U> : Parcelable {
|
||||
}
|
||||
)
|
||||
ConfigType.TyString -> ConfigString(
|
||||
raw,
|
||||
raw.name,
|
||||
raw.description,
|
||||
raw.defaultValue
|
||||
)
|
||||
ConfigType.TyExternal -> ConfigExternal(
|
||||
raw,
|
||||
raw.name,
|
||||
raw.description,
|
||||
raw.tooltip,
|
||||
|
||||
@ -25,7 +25,6 @@
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
||||
app:navGraph="@navigation/settings_nav" />
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -1,330 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/settings_nav"
|
||||
app:startDestination="@id/mainFragment">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/mainFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.MainFragment"
|
||||
android:label="@string/app_name">
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_globalConfigFragment"
|
||||
app:destination="@id/globalConfigFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_addonListFragment"
|
||||
app:destination="@id/addonListFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_imListFragment"
|
||||
app:destination="@id/imListFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_imConfigFragment"
|
||||
app:destination="@id/imConfigFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_keyboardSettingsFragment"
|
||||
app:destination="@id/keyboardSettingsFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_candidatesSettingsFragment"
|
||||
app:destination="@id/candidatesSettingsFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_clipboardSettingsFragment"
|
||||
app:destination="@id/clipboardSettingsFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_symbolSettingsFragment"
|
||||
app:destination="@id/symbolSettingsFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_advancedSettingsFragment"
|
||||
app:destination="@id/advancedSettingsFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_themeFragment"
|
||||
app:destination="@id/themeFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_pinyinDictionaryFragment"
|
||||
app:destination="@id/pinyinDictionaryFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_developerFragment"
|
||||
app:destination="@id/developerFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_aboutFragment"
|
||||
app:destination="@id/aboutFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_pluginFragment"
|
||||
app:destination="@id/pluginFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/globalConfigFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.global.GlobalConfigFragment">
|
||||
<action
|
||||
android:id="@+id/action_globalConfigFragment_to_listFragment"
|
||||
app:destination="@id/listFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/imListFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.im.InputMethodListFragment"
|
||||
android:label="@string/input_methods">
|
||||
<action
|
||||
android:id="@+id/action_imListFragment_to_imConfigFragment"
|
||||
app:destination="@id/imConfigFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/imConfigFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.im.InputMethodConfigFragment">
|
||||
<action
|
||||
android:id="@+id/action_imConfigFragment_to_listFragment"
|
||||
app:destination="@id/listFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_imConfigFragment_to_pinyinDictionaryFragment"
|
||||
app:destination="@id/pinyinDictionaryFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_imConfigFragment_to_punctuationEditorFragment"
|
||||
app:destination="@id/punctuationEditorFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_imConfigFragment_to_quickPhraseListFragment"
|
||||
app:destination="@id/quickPhraseListFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_imConfigFragment_to_addonConfigFragment"
|
||||
app:destination="@id/addonConfigFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_imConfigFragment_to_pinyinCustomPhraseFragment"
|
||||
app:destination="@id/pinyinCustomPhraseFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/addonListFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.addon.AddonListFragment"
|
||||
android:label="@string/addons">
|
||||
<action
|
||||
android:id="@+id/action_addonListFragment_to_addonConfigFragment"
|
||||
app:destination="@id/addonConfigFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/addonConfigFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.addon.AddonConfigFragment">
|
||||
<action
|
||||
android:id="@+id/action_addonConfigFragment_to_listFragment"
|
||||
app:destination="@id/listFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_addonConfigFragment_to_pinyinDictionaryFragment"
|
||||
app:destination="@id/pinyinDictionaryFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_addonConfigFragment_to_punctuationEditorFragment"
|
||||
app:destination="@id/punctuationEditorFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_addonConfigFragment_to_quickPhraseListFragment"
|
||||
app:destination="@id/quickPhraseListFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_addonConfigFragment_self"
|
||||
app:destination="@id/addonConfigFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_addonConfigFragment_to_tableInputMethodFragment"
|
||||
app:destination="@id/tableInputMethodFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_addonConfigFragment_to_pinyinCustomPhraseFragment"
|
||||
app:destination="@id/pinyinCustomPhraseFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/keyboardSettingsFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.behavior.KeyboardSettingsFragment"
|
||||
android:label="@string/virtual_keyboard" />
|
||||
<fragment
|
||||
android:id="@+id/candidatesSettingsFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.behavior.CandidatesSettingsFragment"
|
||||
android:label="@string/candidates_window" />
|
||||
<fragment
|
||||
android:id="@+id/clipboardSettingsFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.behavior.ClipboardSettingsFragment"
|
||||
android:label="@string/clipboard" />
|
||||
<fragment
|
||||
android:id="@+id/symbolSettingsFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.behavior.SymbolSettingsFragment"
|
||||
android:label="@string/emoji_and_symbols" />
|
||||
<fragment
|
||||
android:id="@+id/advancedSettingsFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.behavior.AdvancedSettingsFragment"
|
||||
android:label="@string/advanced" />
|
||||
<fragment
|
||||
android:id="@+id/themeFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.theme.ThemeFragment"
|
||||
android:label="@string/theme">
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/listFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.ListFragment" />
|
||||
<fragment
|
||||
android:id="@+id/pinyinDictionaryFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.PinyinDictionaryFragment"
|
||||
android:label="@string/pinyin_dict" />
|
||||
<fragment
|
||||
android:id="@+id/punctuationEditorFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.PunctuationEditorFragment" />
|
||||
<fragment
|
||||
android:id="@+id/developerFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.DeveloperFragment"
|
||||
android:label="@string/developer" />
|
||||
<fragment
|
||||
android:id="@+id/aboutFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.AboutFragment"
|
||||
android:label="@string/about">
|
||||
<action
|
||||
android:id="@+id/action_aboutFragment_to_licensesFragment"
|
||||
app:destination="@id/licensesFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/licensesFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.LicensesFragment"
|
||||
android:label="@string/open_source_licenses" />
|
||||
<fragment
|
||||
android:id="@+id/quickPhraseListFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.QuickPhraseListFragment"
|
||||
android:label="@string/quickphrase_editor">
|
||||
<action
|
||||
android:id="@+id/action_quickPhraseListFragment_to_quickPhraseEditFragment"
|
||||
app:destination="@id/quickPhraseEditFragment"
|
||||
app:enterAnim="@animator/nav_default_enter_anim"
|
||||
app:exitAnim="@animator/nav_default_exit_anim"
|
||||
app:popEnterAnim="@animator/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@animator/nav_default_pop_exit_anim" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/quickPhraseEditFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.QuickPhraseEditFragment" />
|
||||
<fragment
|
||||
android:id="@+id/tableInputMethodFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.TableInputMethodFragment"
|
||||
android:label="@string/table_im" />
|
||||
<fragment
|
||||
android:id="@+id/pluginFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.PluginFragment"
|
||||
android:label="@string/plugins" />
|
||||
<fragment
|
||||
android:id="@+id/pinyinCustomPhraseFragment"
|
||||
android:name="org.fcitx.fcitx5.android.ui.main.settings.PinyinCustomPhraseFragment" />
|
||||
</navigation>
|
||||
Loading…
x
Reference in New Issue
Block a user