2022-10-15 17:38:01 +02:00
|
|
|
package eu.kanade.presentation.more.settings.screen
|
|
|
|
|
|
|
|
import android.app.Activity
|
|
|
|
import android.content.Context
|
2023-11-05 00:36:25 +01:00
|
|
|
import android.os.Build
|
2023-06-04 23:07:29 +02:00
|
|
|
import androidx.appcompat.app.AppCompatDelegate
|
2022-10-15 17:38:01 +02:00
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
|
|
import androidx.compose.runtime.ReadOnlyComposable
|
|
|
|
import androidx.compose.runtime.getValue
|
2023-06-04 23:07:29 +02:00
|
|
|
import androidx.compose.runtime.mutableStateOf
|
2022-10-15 17:38:01 +02:00
|
|
|
import androidx.compose.runtime.remember
|
2023-06-04 23:07:29 +02:00
|
|
|
import androidx.compose.runtime.setValue
|
2022-10-15 17:38:01 +02:00
|
|
|
import androidx.compose.ui.platform.LocalContext
|
|
|
|
import androidx.core.app.ActivityCompat
|
2023-06-04 23:07:29 +02:00
|
|
|
import androidx.core.os.LocaleListCompat
|
2022-10-15 17:38:01 +02:00
|
|
|
import eu.kanade.domain.ui.UiPreferences
|
2022-10-22 16:15:12 +02:00
|
|
|
import eu.kanade.domain.ui.model.TabletUiMode
|
2022-10-15 17:38:01 +02:00
|
|
|
import eu.kanade.domain.ui.model.ThemeMode
|
2022-10-19 18:57:05 +02:00
|
|
|
import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
|
2022-10-15 17:38:01 +02:00
|
|
|
import eu.kanade.presentation.more.settings.Preference
|
2023-07-27 04:57:15 +02:00
|
|
|
import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
|
2022-10-15 17:38:01 +02:00
|
|
|
import eu.kanade.tachiyomi.R
|
2023-06-04 23:07:29 +02:00
|
|
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
2022-10-22 16:15:12 +02:00
|
|
|
import eu.kanade.tachiyomi.util.system.toast
|
2022-10-15 17:38:01 +02:00
|
|
|
import kotlinx.coroutines.flow.collectLatest
|
|
|
|
import kotlinx.coroutines.flow.drop
|
|
|
|
import kotlinx.coroutines.flow.merge
|
2023-06-04 23:07:29 +02:00
|
|
|
import org.xmlpull.v1.XmlPullParser
|
2023-11-19 01:41:33 +01:00
|
|
|
import tachiyomi.core.i18n.stringResource
|
2023-11-18 19:54:56 +01:00
|
|
|
import tachiyomi.i18n.MR
|
2023-11-19 01:41:33 +01:00
|
|
|
import tachiyomi.presentation.core.i18n.stringResource
|
2023-07-20 03:57:22 +02:00
|
|
|
import tachiyomi.presentation.core.util.collectAsState
|
2022-10-15 17:38:01 +02:00
|
|
|
import uy.kohesive.injekt.Injekt
|
|
|
|
import uy.kohesive.injekt.api.get
|
2023-12-09 05:11:53 +01:00
|
|
|
import java.time.Instant
|
2022-10-15 17:38:01 +02:00
|
|
|
|
2022-11-23 15:14:55 +01:00
|
|
|
object SettingsAppearanceScreen : SearchableSettings {
|
2022-10-15 17:38:01 +02:00
|
|
|
|
|
|
|
@ReadOnlyComposable
|
|
|
|
@Composable
|
2023-11-18 19:54:56 +01:00
|
|
|
override fun getTitleRes() = MR.strings.pref_category_appearance
|
2022-10-15 17:38:01 +02:00
|
|
|
|
|
|
|
@Composable
|
|
|
|
override fun getPreferences(): List<Preference> {
|
|
|
|
val context = LocalContext.current
|
|
|
|
val uiPreferences = remember { Injekt.get<UiPreferences>() }
|
2022-10-15 17:58:24 +02:00
|
|
|
|
|
|
|
return listOf(
|
|
|
|
getThemeGroup(context = context, uiPreferences = uiPreferences),
|
2022-10-22 16:15:12 +02:00
|
|
|
getDisplayGroup(context = context, uiPreferences = uiPreferences),
|
2022-10-15 17:58:24 +02:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
private fun getThemeGroup(
|
|
|
|
context: Context,
|
|
|
|
uiPreferences: UiPreferences,
|
|
|
|
): Preference.PreferenceGroup {
|
2022-10-15 17:38:01 +02:00
|
|
|
val themeModePref = uiPreferences.themeMode()
|
2022-10-15 17:58:24 +02:00
|
|
|
val themeMode by themeModePref.collectAsState()
|
2023-07-27 04:57:15 +02:00
|
|
|
|
2022-10-15 17:38:01 +02:00
|
|
|
val appThemePref = uiPreferences.appTheme()
|
2023-07-27 04:57:15 +02:00
|
|
|
|
2022-10-15 17:38:01 +02:00
|
|
|
val amoledPref = uiPreferences.themeDarkAmoled()
|
2023-07-27 04:57:15 +02:00
|
|
|
val amoled by amoledPref.collectAsState()
|
2022-10-15 17:38:01 +02:00
|
|
|
|
2022-10-19 18:57:05 +02:00
|
|
|
LaunchedEffect(themeMode) {
|
|
|
|
setAppCompatDelegateThemeMode(themeMode)
|
2022-10-18 15:35:10 +02:00
|
|
|
}
|
|
|
|
|
2022-10-15 17:38:01 +02:00
|
|
|
LaunchedEffect(Unit) {
|
|
|
|
merge(appThemePref.changes(), amoledPref.changes())
|
|
|
|
.drop(2)
|
|
|
|
.collectLatest { (context as? Activity)?.let { ActivityCompat.recreate(it) } }
|
|
|
|
}
|
|
|
|
|
2022-10-15 17:58:24 +02:00
|
|
|
return Preference.PreferenceGroup(
|
2023-11-19 01:41:33 +01:00
|
|
|
title = stringResource(MR.strings.pref_category_theme),
|
2022-10-15 17:58:24 +02:00
|
|
|
preferenceItems = listOf(
|
|
|
|
Preference.PreferenceItem.ListPreference(
|
|
|
|
pref = themeModePref,
|
2023-11-19 01:41:33 +01:00
|
|
|
title = stringResource(MR.strings.pref_theme_mode),
|
2023-11-05 00:36:25 +01:00
|
|
|
entries = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
|
|
mapOf(
|
2023-11-19 01:41:33 +01:00
|
|
|
ThemeMode.SYSTEM to stringResource(MR.strings.theme_system),
|
|
|
|
ThemeMode.LIGHT to stringResource(MR.strings.theme_light),
|
|
|
|
ThemeMode.DARK to stringResource(MR.strings.theme_dark),
|
2023-11-05 00:36:25 +01:00
|
|
|
)
|
|
|
|
} else {
|
|
|
|
mapOf(
|
2023-11-19 01:41:33 +01:00
|
|
|
ThemeMode.LIGHT to stringResource(MR.strings.theme_light),
|
|
|
|
ThemeMode.DARK to stringResource(MR.strings.theme_dark),
|
2023-11-05 00:36:25 +01:00
|
|
|
)
|
|
|
|
},
|
2022-10-15 17:58:24 +02:00
|
|
|
),
|
2023-07-27 04:57:15 +02:00
|
|
|
Preference.PreferenceItem.CustomPreference(
|
2023-11-19 01:41:33 +01:00
|
|
|
title = stringResource(MR.strings.pref_app_theme),
|
2023-07-27 04:57:15 +02:00
|
|
|
) { item ->
|
|
|
|
val value by appThemePref.collectAsState()
|
|
|
|
AppThemePreferenceWidget(
|
|
|
|
title = item.title,
|
|
|
|
value = value,
|
|
|
|
amoled = amoled,
|
|
|
|
onItemClick = { appThemePref.set(it) },
|
|
|
|
)
|
|
|
|
},
|
2022-10-15 17:58:24 +02:00
|
|
|
Preference.PreferenceItem.SwitchPreference(
|
|
|
|
pref = amoledPref,
|
2023-11-19 01:41:33 +01:00
|
|
|
title = stringResource(MR.strings.pref_dark_theme_pure_black),
|
2022-10-15 17:58:24 +02:00
|
|
|
enabled = themeMode != ThemeMode.LIGHT,
|
|
|
|
),
|
2022-10-15 17:38:01 +02:00
|
|
|
),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
@Composable
|
2022-10-22 16:15:12 +02:00
|
|
|
private fun getDisplayGroup(
|
2022-10-15 17:38:01 +02:00
|
|
|
context: Context,
|
|
|
|
uiPreferences: UiPreferences,
|
|
|
|
): Preference.PreferenceGroup {
|
2023-06-04 23:07:29 +02:00
|
|
|
val langs = remember { getLangs(context) }
|
2023-11-05 04:28:41 +01:00
|
|
|
var currentLanguage by remember {
|
|
|
|
mutableStateOf(AppCompatDelegate.getApplicationLocales().get(0)?.toLanguageTag() ?: "")
|
|
|
|
}
|
2023-12-09 05:11:53 +01:00
|
|
|
val now = remember { Instant.now().toEpochMilli() }
|
2023-06-04 23:07:29 +02:00
|
|
|
|
2023-09-24 23:01:26 +02:00
|
|
|
val dateFormat by uiPreferences.dateFormat().collectAsState()
|
|
|
|
val formattedNow = remember(dateFormat) {
|
|
|
|
UiPreferences.dateFormat(dateFormat).format(now)
|
|
|
|
}
|
|
|
|
|
2023-06-04 23:07:29 +02:00
|
|
|
LaunchedEffect(currentLanguage) {
|
|
|
|
val locale = if (currentLanguage.isEmpty()) {
|
|
|
|
LocaleListCompat.getEmptyLocaleList()
|
|
|
|
} else {
|
|
|
|
LocaleListCompat.forLanguageTags(currentLanguage)
|
|
|
|
}
|
|
|
|
AppCompatDelegate.setApplicationLocales(locale)
|
|
|
|
}
|
|
|
|
|
2022-10-15 17:38:01 +02:00
|
|
|
return Preference.PreferenceGroup(
|
2023-11-19 01:41:33 +01:00
|
|
|
title = stringResource(MR.strings.pref_category_display),
|
2022-10-15 17:38:01 +02:00
|
|
|
preferenceItems = listOf(
|
2023-06-04 23:07:29 +02:00
|
|
|
Preference.PreferenceItem.BasicListPreference(
|
|
|
|
value = currentLanguage,
|
2023-11-19 01:41:33 +01:00
|
|
|
title = stringResource(MR.strings.pref_app_language),
|
2023-06-04 23:07:29 +02:00
|
|
|
entries = langs,
|
|
|
|
onValueChanged = { newValue ->
|
|
|
|
currentLanguage = newValue
|
|
|
|
true
|
|
|
|
},
|
|
|
|
),
|
2022-10-22 16:15:12 +02:00
|
|
|
Preference.PreferenceItem.ListPreference(
|
2022-10-27 22:50:44 +02:00
|
|
|
pref = uiPreferences.tabletUiMode(),
|
2023-11-19 01:41:33 +01:00
|
|
|
title = stringResource(MR.strings.pref_tablet_ui_mode),
|
|
|
|
entries = TabletUiMode.entries.associateWith { stringResource(it.titleRes) },
|
2022-10-22 16:15:12 +02:00
|
|
|
onValueChanged = {
|
2023-11-18 19:54:56 +01:00
|
|
|
context.toast(MR.strings.requires_app_restart)
|
2022-10-22 16:15:12 +02:00
|
|
|
true
|
|
|
|
},
|
|
|
|
),
|
2022-10-15 17:38:01 +02:00
|
|
|
Preference.PreferenceItem.ListPreference(
|
|
|
|
pref = uiPreferences.dateFormat(),
|
2023-11-19 01:41:33 +01:00
|
|
|
title = stringResource(MR.strings.pref_date_format),
|
2022-10-15 17:38:01 +02:00
|
|
|
entries = DateFormats
|
|
|
|
.associateWith {
|
|
|
|
val formattedDate = UiPreferences.dateFormat(it).format(now)
|
2023-11-19 01:41:33 +01:00
|
|
|
"${it.ifEmpty { stringResource(MR.strings.label_default) }} ($formattedDate)"
|
2022-10-15 17:38:01 +02:00
|
|
|
},
|
|
|
|
),
|
2023-09-24 23:01:26 +02:00
|
|
|
Preference.PreferenceItem.SwitchPreference(
|
|
|
|
pref = uiPreferences.relativeTime(),
|
2023-11-19 01:41:33 +01:00
|
|
|
title = stringResource(MR.strings.pref_relative_format),
|
|
|
|
subtitle = stringResource(
|
2023-11-18 19:54:56 +01:00
|
|
|
MR.strings.pref_relative_format_summary,
|
2023-11-19 01:41:33 +01:00
|
|
|
stringResource(MR.strings.relative_time_today),
|
2023-09-24 23:01:26 +02:00
|
|
|
formattedNow,
|
|
|
|
),
|
|
|
|
),
|
2022-10-15 17:38:01 +02:00
|
|
|
),
|
|
|
|
)
|
|
|
|
}
|
2023-06-04 23:07:29 +02:00
|
|
|
private fun getLangs(context: Context): Map<String, String> {
|
|
|
|
val langs = mutableListOf<Pair<String, String>>()
|
|
|
|
val parser = context.resources.getXml(R.xml.locales_config)
|
|
|
|
var eventType = parser.eventType
|
|
|
|
while (eventType != XmlPullParser.END_DOCUMENT) {
|
|
|
|
if (eventType == XmlPullParser.START_TAG && parser.name == "locale") {
|
2023-07-19 01:12:04 +02:00
|
|
|
for (i in 0..<parser.attributeCount) {
|
2023-06-04 23:07:29 +02:00
|
|
|
if (parser.getAttributeName(i) == "name") {
|
|
|
|
val langTag = parser.getAttributeValue(i)
|
|
|
|
val displayName = LocaleHelper.getDisplayName(langTag)
|
|
|
|
if (displayName.isNotEmpty()) {
|
|
|
|
langs.add(Pair(langTag, displayName))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
eventType = parser.next()
|
|
|
|
}
|
|
|
|
|
|
|
|
langs.sortBy { it.second }
|
2023-11-19 01:41:33 +01:00
|
|
|
langs.add(0, Pair("", context.stringResource(MR.strings.label_default)))
|
2023-06-04 23:07:29 +02:00
|
|
|
|
|
|
|
return langs.toMap()
|
|
|
|
}
|
2022-10-15 17:38:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private val DateFormats = listOf(
|
|
|
|
"", // Default
|
|
|
|
"MM/dd/yy",
|
|
|
|
"dd/MM/yy",
|
|
|
|
"yyyy-MM-dd",
|
|
|
|
"dd MMM yyyy",
|
|
|
|
"MMM dd, yyyy",
|
|
|
|
)
|