mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-15 15:02:49 +01:00
Merge branch 'sync-part-final' into feat/add-sync-triggers-experimental
This commit is contained in:
commit
ae3dacf913
@ -77,7 +77,7 @@ internal fun GlobalSearchContent(
|
|||||||
title = fromSourceId?.let {
|
title = fromSourceId?.let {
|
||||||
"▶ ${source.name}".takeIf { source.id == fromSourceId }
|
"▶ ${source.name}".takeIf { source.id == fromSourceId }
|
||||||
} ?: source.name,
|
} ?: source.name,
|
||||||
subtitle = LocaleHelper.getDisplayName(source.lang),
|
subtitle = LocaleHelper.getLocalizedDisplayName(source.lang),
|
||||||
onClick = { onClickSource(source) },
|
onClick = { onClickSource(source) },
|
||||||
) {
|
) {
|
||||||
when (result) {
|
when (result) {
|
||||||
|
@ -77,7 +77,7 @@ internal class StorageStep : OnboardingStep {
|
|||||||
Text(stringResource(MR.strings.onboarding_storage_help_info, stringResource(MR.strings.app_name)))
|
Text(stringResource(MR.strings.onboarding_storage_help_info, stringResource(MR.strings.app_name)))
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
onClick = { handler.openUri("https://tachiyomi.org/docs/faq/storage") },
|
onClick = { handler.openUri(SettingsDataScreen.HELP_URL) },
|
||||||
) {
|
) {
|
||||||
Text(stringResource(MR.strings.onboarding_storage_help_action))
|
Text(stringResource(MR.strings.onboarding_storage_help_action))
|
||||||
}
|
}
|
||||||
|
@ -7,9 +7,14 @@ import android.net.Uri
|
|||||||
import androidx.activity.compose.ManagedActivityResultLauncher
|
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MultiChoiceSegmentedButtonRow
|
import androidx.compose.material3.MultiChoiceSegmentedButtonRow
|
||||||
import androidx.compose.material3.SegmentedButton
|
import androidx.compose.material3.SegmentedButton
|
||||||
import androidx.compose.material3.SegmentedButtonDefaults
|
import androidx.compose.material3.SegmentedButtonDefaults
|
||||||
@ -25,6 +30,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
@ -68,11 +74,23 @@ import uy.kohesive.injekt.api.get
|
|||||||
object SettingsDataScreen : SearchableSettings {
|
object SettingsDataScreen : SearchableSettings {
|
||||||
|
|
||||||
val restorePreferenceKeyString = MR.strings.label_backup
|
val restorePreferenceKeyString = MR.strings.label_backup
|
||||||
|
const val HELP_URL = "https://tachiyomi.org/docs/faq/storage"
|
||||||
|
|
||||||
@ReadOnlyComposable
|
@ReadOnlyComposable
|
||||||
@Composable
|
@Composable
|
||||||
override fun getTitleRes() = MR.strings.label_data_storage
|
override fun getTitleRes() = MR.strings.label_data_storage
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun RowScope.AppBarAction() {
|
||||||
|
val uriHandler = LocalUriHandler.current
|
||||||
|
IconButton(onClick = { uriHandler.openUri(HELP_URL) }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||||
|
contentDescription = stringResource(MR.strings.tracking_guide),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun getPreferences(): List<Preference> {
|
override fun getPreferences(): List<Preference> {
|
||||||
val backupPreferences = Injekt.get<BackupPreferences>()
|
val backupPreferences = Injekt.get<BackupPreferences>()
|
||||||
|
@ -34,7 +34,6 @@ import tachiyomi.core.i18n.stringResource
|
|||||||
import tachiyomi.i18n.MR
|
import tachiyomi.i18n.MR
|
||||||
import tachiyomi.presentation.core.components.material.Scaffold
|
import tachiyomi.presentation.core.components.material.Scaffold
|
||||||
import tachiyomi.presentation.core.i18n.stringResource
|
import tachiyomi.presentation.core.i18n.stringResource
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
class AppLanguageScreen : Screen() {
|
class AppLanguageScreen : Screen() {
|
||||||
|
|
||||||
@ -104,9 +103,9 @@ class AppLanguageScreen : Screen() {
|
|||||||
for (i in 0..<parser.attributeCount) {
|
for (i in 0..<parser.attributeCount) {
|
||||||
if (parser.getAttributeName(i) == "name") {
|
if (parser.getAttributeName(i) == "name") {
|
||||||
val langTag = parser.getAttributeValue(i)
|
val langTag = parser.getAttributeValue(i)
|
||||||
val displayName = LocaleHelper.getDisplayName(langTag)
|
val displayName = LocaleHelper.getLocalizedDisplayName(langTag)
|
||||||
if (displayName.isNotEmpty()) {
|
if (displayName.isNotEmpty()) {
|
||||||
langs.add(Language(langTag, displayName, Locale.forLanguageTag(langTag).displayName))
|
langs.add(Language(langTag, displayName, LocaleHelper.getDisplayName(langTag)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,12 @@ import kotlinx.coroutines.MainScope
|
|||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.supervisorScope
|
import kotlinx.coroutines.supervisorScope
|
||||||
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.util.lang.launchIO
|
import tachiyomi.core.util.lang.launchIO
|
||||||
import tachiyomi.core.util.lang.withIOContext
|
import tachiyomi.core.util.lang.withIOContext
|
||||||
import tachiyomi.core.util.lang.withUIContext
|
import tachiyomi.core.util.lang.withUIContext
|
||||||
import tachiyomi.core.util.system.ImageUtil
|
import tachiyomi.core.util.system.ImageUtil
|
||||||
|
import tachiyomi.core.util.system.logcat
|
||||||
import java.io.BufferedInputStream
|
import java.io.BufferedInputStream
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@ -136,40 +138,47 @@ class PagerPageHolder(
|
|||||||
|
|
||||||
val streamFn = page.stream ?: return
|
val streamFn = page.stream ?: return
|
||||||
|
|
||||||
val (bais, isAnimated, background) = withIOContext {
|
try {
|
||||||
streamFn().buffered(16).use { stream ->
|
val (bais, isAnimated, background) = withIOContext {
|
||||||
process(item, stream).use { itemStream ->
|
streamFn().buffered(16).use { stream ->
|
||||||
val bais = ByteArrayInputStream(itemStream.readBytes())
|
process(item, stream).use { itemStream ->
|
||||||
val isAnimated = ImageUtil.isAnimatedAndSupported(bais)
|
val bais = ByteArrayInputStream(itemStream.readBytes())
|
||||||
bais.reset()
|
val isAnimated = ImageUtil.isAnimatedAndSupported(bais)
|
||||||
val background = if (!isAnimated && viewer.config.automaticBackground) {
|
bais.reset()
|
||||||
ImageUtil.chooseBackground(context, bais)
|
val background = if (!isAnimated && viewer.config.automaticBackground) {
|
||||||
} else {
|
ImageUtil.chooseBackground(context, bais)
|
||||||
null
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
bais.reset()
|
||||||
|
Triple(bais, isAnimated, background)
|
||||||
}
|
}
|
||||||
bais.reset()
|
|
||||||
Triple(bais, isAnimated, background)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
withUIContext {
|
||||||
withUIContext {
|
bais.use {
|
||||||
bais.use {
|
setImage(
|
||||||
setImage(
|
it,
|
||||||
it,
|
isAnimated,
|
||||||
isAnimated,
|
Config(
|
||||||
Config(
|
zoomDuration = viewer.config.doubleTapAnimDuration,
|
||||||
zoomDuration = viewer.config.doubleTapAnimDuration,
|
minimumScaleType = viewer.config.imageScaleType,
|
||||||
minimumScaleType = viewer.config.imageScaleType,
|
cropBorders = viewer.config.imageCropBorders,
|
||||||
cropBorders = viewer.config.imageCropBorders,
|
zoomStartPosition = viewer.config.imageZoomType,
|
||||||
zoomStartPosition = viewer.config.imageZoomType,
|
landscapeZoom = viewer.config.landscapeZoom,
|
||||||
landscapeZoom = viewer.config.landscapeZoom,
|
),
|
||||||
),
|
)
|
||||||
)
|
if (!isAnimated) {
|
||||||
if (!isAnimated) {
|
pageBackground = background
|
||||||
pageBackground = background
|
}
|
||||||
}
|
}
|
||||||
|
removeErrorLayout()
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
logcat(LogPriority.ERROR, e)
|
||||||
|
withUIContext {
|
||||||
|
setError()
|
||||||
}
|
}
|
||||||
removeErrorLayout()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,10 +23,12 @@ import kotlinx.coroutines.flow.collectLatest
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.supervisorScope
|
import kotlinx.coroutines.supervisorScope
|
||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
import logcat.LogPriority
|
||||||
import tachiyomi.core.util.lang.launchIO
|
import tachiyomi.core.util.lang.launchIO
|
||||||
import tachiyomi.core.util.lang.withIOContext
|
import tachiyomi.core.util.lang.withIOContext
|
||||||
import tachiyomi.core.util.lang.withUIContext
|
import tachiyomi.core.util.lang.withUIContext
|
||||||
import tachiyomi.core.util.system.ImageUtil
|
import tachiyomi.core.util.system.ImageUtil
|
||||||
|
import tachiyomi.core.util.system.logcat
|
||||||
import java.io.BufferedInputStream
|
import java.io.BufferedInputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
@ -184,28 +186,35 @@ class WebtoonPageHolder(
|
|||||||
|
|
||||||
val streamFn = page?.stream ?: return
|
val streamFn = page?.stream ?: return
|
||||||
|
|
||||||
val (openStream, isAnimated) = withIOContext {
|
try {
|
||||||
val stream = streamFn().buffered(16)
|
val (openStream, isAnimated) = withIOContext {
|
||||||
val openStream = process(stream)
|
val stream = streamFn().buffered(16)
|
||||||
|
val openStream = process(stream)
|
||||||
|
|
||||||
val isAnimated = ImageUtil.isAnimatedAndSupported(stream)
|
val isAnimated = ImageUtil.isAnimatedAndSupported(stream)
|
||||||
Pair(openStream, isAnimated)
|
Pair(openStream, isAnimated)
|
||||||
}
|
}
|
||||||
withUIContext {
|
withUIContext {
|
||||||
frame.setImage(
|
frame.setImage(
|
||||||
openStream,
|
openStream,
|
||||||
isAnimated,
|
isAnimated,
|
||||||
ReaderPageImageView.Config(
|
ReaderPageImageView.Config(
|
||||||
zoomDuration = viewer.config.doubleTapAnimDuration,
|
zoomDuration = viewer.config.doubleTapAnimDuration,
|
||||||
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_FIT_WIDTH,
|
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_FIT_WIDTH,
|
||||||
cropBorders = viewer.config.imageCropBorders,
|
cropBorders = viewer.config.imageCropBorders,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
removeErrorLayout()
|
removeErrorLayout()
|
||||||
}
|
}
|
||||||
// Suspend the coroutine to close the input stream only when the WebtoonPageHolder is recycled
|
// Suspend the coroutine to close the input stream only when the WebtoonPageHolder is recycled
|
||||||
suspendCancellableCoroutine<Nothing> { continuation ->
|
suspendCancellableCoroutine<Nothing> { continuation ->
|
||||||
continuation.invokeOnCancellation { openStream.close() }
|
continuation.invokeOnCancellation { openStream.close() }
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
logcat(LogPriority.ERROR, e)
|
||||||
|
withUIContext {
|
||||||
|
setError()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ object LocaleHelper {
|
|||||||
} else if (b == "all") {
|
} else if (b == "all") {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
getDisplayName(a).compareTo(getDisplayName(b))
|
getLocalizedDisplayName(a).compareTo(getLocalizedDisplayName(b))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,16 +34,26 @@ object LocaleHelper {
|
|||||||
SourcesScreenModel.PINNED_KEY -> context.stringResource(MR.strings.pinned_sources)
|
SourcesScreenModel.PINNED_KEY -> context.stringResource(MR.strings.pinned_sources)
|
||||||
"other" -> context.stringResource(MR.strings.other_source)
|
"other" -> context.stringResource(MR.strings.other_source)
|
||||||
"all" -> context.stringResource(MR.strings.multi_lang)
|
"all" -> context.stringResource(MR.strings.multi_lang)
|
||||||
else -> getDisplayName(lang)
|
else -> getLocalizedDisplayName(lang)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDisplayName(lang: String): String {
|
||||||
|
val normalizedLang = when (lang) {
|
||||||
|
"zh-CN" -> "zh-Hans"
|
||||||
|
"zh-TW" -> "zh-Hant"
|
||||||
|
else -> lang
|
||||||
|
}
|
||||||
|
|
||||||
|
return Locale.forLanguageTag(normalizedLang).displayName
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns display name of a string language code.
|
* Returns display name of a string language code.
|
||||||
*
|
*
|
||||||
* @param lang empty for system language
|
* @param lang empty for system language
|
||||||
*/
|
*/
|
||||||
fun getDisplayName(lang: String?): String {
|
fun getLocalizedDisplayName(lang: String?): String {
|
||||||
if (lang == null) {
|
if (lang == null) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user