diff --git a/.github/workflows/build_pull_request.yml b/.github/workflows/build_pull_request.yml
index 5a7bfdd10..bebc653c0 100644
--- a/.github/workflows/build_pull_request.yml
+++ b/.github/workflows/build_pull_request.yml
@@ -3,7 +3,8 @@ on:
pull_request:
paths-ignore:
- '**.md'
- - 'i18n/src/main/res/**/strings.xml'
+ - 'i18n/src/commonMain/resources/**/strings.xml'
+ - 'i18n/src/commonMain/resources/**/plurals.xml'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 4397098b5..d85e85370 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -22,7 +22,7 @@ android {
defaultConfig {
applicationId = "eu.kanade.tachiyomi"
- versionCode = 112
+ versionCode = 113
versionName = "0.14.7"
buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")
@@ -123,6 +123,7 @@ android {
buildFeatures {
viewBinding = true
compose = true
+ buildConfig = true
// Disable some unused things
aidl = false
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e7d560094..d7a1aa265 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -160,7 +160,8 @@
+ android:exported="false"
+ android:foregroundServiceType="shortService" />
Unit,
+ onLongClick: () -> Unit,
isSelected: Boolean = false,
title: String? = null,
- coverData: tachiyomi.domain.manga.model.MangaCover,
+ onClickContinueReading: (() -> Unit)? = null,
coverAlpha: Float = 1f,
coverBadgeStart: @Composable (RowScope.() -> Unit)? = null,
coverBadgeEnd: @Composable (RowScope.() -> Unit)? = null,
- onLongClick: () -> Unit,
- onClick: () -> Unit,
- onClickContinueReading: (() -> Unit)? = null,
) {
GridItemSelectable(
isSelected = isSelected,
@@ -163,15 +163,15 @@ private fun BoxScope.CoverTextOverlay(
*/
@Composable
fun MangaComfortableGridItem(
- isSelected: Boolean = false,
- title: String,
- titleMaxLines: Int = 2,
coverData: tachiyomi.domain.manga.model.MangaCover,
+ title: String,
+ onClick: () -> Unit,
+ onLongClick: () -> Unit,
+ isSelected: Boolean = false,
+ titleMaxLines: Int = 2,
coverAlpha: Float = 1f,
coverBadgeStart: (@Composable RowScope.() -> Unit)? = null,
coverBadgeEnd: (@Composable RowScope.() -> Unit)? = null,
- onLongClick: () -> Unit,
- onClick: () -> Unit,
onClickContinueReading: (() -> Unit)? = null,
) {
GridItemSelectable(
@@ -253,10 +253,10 @@ private fun MangaGridCover(
@Composable
private fun GridItemTitle(
- modifier: Modifier,
title: String,
style: TextStyle,
minLines: Int,
+ modifier: Modifier = Modifier,
maxLines: Int = 2,
) {
Text(
@@ -276,10 +276,10 @@ private fun GridItemTitle(
*/
@Composable
private fun GridItemSelectable(
- modifier: Modifier = Modifier,
isSelected: Boolean,
onClick: () -> Unit,
onLongClick: () -> Unit,
+ modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
Box(
@@ -316,13 +316,13 @@ private fun Modifier.selectedOutline(
*/
@Composable
fun MangaListItem(
- isSelected: Boolean = false,
- title: String,
coverData: tachiyomi.domain.manga.model.MangaCover,
- coverAlpha: Float = 1f,
- badge: @Composable (RowScope.() -> Unit),
- onLongClick: () -> Unit,
+ title: String,
onClick: () -> Unit,
+ onLongClick: () -> Unit,
+ badge: @Composable (RowScope.() -> Unit),
+ isSelected: Boolean = false,
+ coverAlpha: Float = 1f,
onClickContinueReading: (() -> Unit)? = null,
) {
Row(
diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt
index 991b49486..b14d2ed14 100644
--- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt
+++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaChapterListItem.kt
@@ -33,7 +33,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
@@ -189,7 +188,7 @@ fun MangaChapterListItem(
text = readProgress,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
- modifier = Modifier.alpha(ReadItemAlpha),
+ color = LocalContentColor.current.copy(alpha = ReadItemAlpha),
)
if (scanlator != null) DotSeparatorText()
}
diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt
index a643a15b2..5d33206b2 100644
--- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt
+++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaInfoHeader.kt
@@ -124,7 +124,7 @@ fun MangaInfoBox(
)
}
.blur(4.dp)
- .alpha(.2f),
+ .alpha(0.2f),
)
// Manga & source info
diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/MangaToolbar.kt b/app/src/main/java/eu/kanade/presentation/manga/components/MangaToolbar.kt
index e25eb8b25..12c14ce78 100644
--- a/app/src/main/java/eu/kanade/presentation/manga/components/MangaToolbar.kt
+++ b/app/src/main/java/eu/kanade/presentation/manga/components/MangaToolbar.kt
@@ -35,10 +35,8 @@ import tachiyomi.presentation.core.theme.active
@Composable
fun MangaToolbar(
- modifier: Modifier = Modifier,
title: String,
titleAlphaProvider: () -> Float,
- backgroundAlphaProvider: () -> Float = titleAlphaProvider,
hasFilters: Boolean,
onBackClicked: () -> Unit,
onClickFilter: () -> Unit,
@@ -47,10 +45,14 @@ fun MangaToolbar(
onClickEditCategory: (() -> Unit)?,
onClickRefresh: () -> Unit,
onClickMigrate: (() -> Unit)?,
+
// For action mode
actionModeCounter: Int,
onSelectAll: () -> Unit,
onInvertSelection: () -> Unit,
+
+ modifier: Modifier = Modifier,
+ backgroundAlphaProvider: () -> Float = titleAlphaProvider,
) {
Column(
modifier = modifier,
@@ -62,7 +64,7 @@ fun MangaToolbar(
text = if (isActionMode) actionModeCounter.toString() else title,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
- modifier = Modifier.alpha(if (isActionMode) 1f else titleAlphaProvider()),
+ color = LocalContentColor.current.copy(alpha = if (isActionMode) 1f else titleAlphaProvider()),
)
},
navigationIcon = {
diff --git a/app/src/main/java/eu/kanade/presentation/more/onboarding/GuidesStep.kt b/app/src/main/java/eu/kanade/presentation/more/onboarding/GuidesStep.kt
index 5899dae55..77e0e7b88 100644
--- a/app/src/main/java/eu/kanade/presentation/more/onboarding/GuidesStep.kt
+++ b/app/src/main/java/eu/kanade/presentation/more/onboarding/GuidesStep.kt
@@ -17,34 +17,38 @@ import eu.kanade.presentation.theme.TachiyomiTheme
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.stringResource
-@Composable
-internal fun GuidesStep(
- onRestoreBackup: () -> Unit,
-) {
- val handler = LocalUriHandler.current
+internal class GuidesStep(
+ private val onRestoreBackup: () -> Unit,
+) : OnboardingStep {
+ override val isComplete: Boolean = true
- Column(
- modifier = Modifier.padding(16.dp),
- verticalArrangement = Arrangement.spacedBy(8.dp),
- ) {
- Text(stringResource(MR.strings.onboarding_guides_new_user, stringResource(MR.strings.app_name)))
- Button(
- modifier = Modifier.fillMaxWidth(),
- onClick = { handler.openUri(GETTING_STARTED_URL) },
+ @Composable
+ override fun Content() {
+ val handler = LocalUriHandler.current
+
+ Column(
+ modifier = Modifier.padding(16.dp),
+ verticalArrangement = Arrangement.spacedBy(8.dp),
) {
- Text(stringResource(MR.strings.getting_started_guide))
- }
+ Text(stringResource(MR.strings.onboarding_guides_new_user, stringResource(MR.strings.app_name)))
+ Button(
+ modifier = Modifier.fillMaxWidth(),
+ onClick = { handler.openUri(GETTING_STARTED_URL) },
+ ) {
+ Text(stringResource(MR.strings.getting_started_guide))
+ }
- HorizontalDivider(
- color = MaterialTheme.colorScheme.onPrimaryContainer,
- )
+ HorizontalDivider(
+ color = MaterialTheme.colorScheme.onPrimaryContainer,
+ )
- Text(stringResource(MR.strings.onboarding_guides_returning_user, stringResource(MR.strings.app_name)))
- Button(
- modifier = Modifier.fillMaxWidth(),
- onClick = onRestoreBackup,
- ) {
- Text(stringResource(MR.strings.pref_restore_backup))
+ Text(stringResource(MR.strings.onboarding_guides_returning_user, stringResource(MR.strings.app_name)))
+ Button(
+ modifier = Modifier.fillMaxWidth(),
+ onClick = onRestoreBackup,
+ ) {
+ Text(stringResource(MR.strings.pref_restore_backup))
+ }
}
}
}
@@ -57,6 +61,6 @@ private fun GuidesStepPreview() {
TachiyomiTheme {
GuidesStep(
onRestoreBackup = {},
- )
+ ).Content()
}
}
diff --git a/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingScreen.kt b/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingScreen.kt
index ef42a68fc..c5fd8c2fa 100644
--- a/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingScreen.kt
+++ b/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingScreen.kt
@@ -13,15 +13,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
+import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
-import androidx.compose.ui.platform.LocalContext
-import eu.kanade.domain.ui.UiPreferences
-import eu.kanade.tachiyomi.util.system.toast
import soup.compose.material.motion.animation.materialSharedAxisX
import soup.compose.material.motion.animation.rememberSlideDistance
-import tachiyomi.domain.storage.service.StoragePreferences
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.i18n.stringResource
@@ -29,24 +26,21 @@ import tachiyomi.presentation.core.screens.InfoScreen
@Composable
fun OnboardingScreen(
- storagePreferences: StoragePreferences,
- uiPreferences: UiPreferences,
onComplete: () -> Unit,
onRestoreBackup: () -> Unit,
) {
- val context = LocalContext.current
val slideDistance = rememberSlideDistance()
- var currentStep by remember { mutableIntStateOf(0) }
- val steps: List<@Composable () -> Unit> = remember {
+ var currentStep by rememberSaveable { mutableIntStateOf(0) }
+ val steps = remember {
listOf(
- { ThemeStep(uiPreferences = uiPreferences) },
- { StorageStep(storagePref = storagePreferences.baseStorageDirectory()) },
- // TODO: prompt for notification permissions when bumping target to Android 13
- { GuidesStep(onRestoreBackup = onRestoreBackup) },
+ ThemeStep(),
+ StorageStep(),
+ PermissionStep(),
+ GuidesStep(onRestoreBackup = onRestoreBackup),
)
}
- val isLastStep = currentStep == steps.size - 1
+ val isLastStep = currentStep == steps.lastIndex
BackHandler(enabled = currentStep != 0, onBack = { currentStep-- })
@@ -61,16 +55,12 @@ fun OnboardingScreen(
MR.strings.onboarding_action_next
},
),
+ canAccept = steps[currentStep].isComplete,
onAcceptClick = {
if (isLastStep) {
onComplete()
} else {
- // TODO: this is kind of janky
- if (currentStep == 1 && !storagePreferences.baseStorageDirectory().isSet()) {
- context.toast(MR.strings.onboarding_storage_selection_required)
- } else {
- currentStep++
- }
+ currentStep++
}
},
) {
@@ -91,7 +81,7 @@ fun OnboardingScreen(
},
label = "stepContent",
) {
- steps[it]()
+ steps[it].Content()
}
}
}
diff --git a/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingStep.kt b/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingStep.kt
new file mode 100644
index 000000000..81b0a9f91
--- /dev/null
+++ b/app/src/main/java/eu/kanade/presentation/more/onboarding/OnboardingStep.kt
@@ -0,0 +1,11 @@
+package eu.kanade.presentation.more.onboarding
+
+import androidx.compose.runtime.Composable
+
+internal interface OnboardingStep {
+
+ val isComplete: Boolean
+
+ @Composable
+ fun Content()
+}
diff --git a/app/src/main/java/eu/kanade/presentation/more/onboarding/PermissionStep.kt b/app/src/main/java/eu/kanade/presentation/more/onboarding/PermissionStep.kt
new file mode 100644
index 000000000..e7e3ec598
--- /dev/null
+++ b/app/src/main/java/eu/kanade/presentation/more/onboarding/PermissionStep.kt
@@ -0,0 +1,181 @@
+package eu.kanade.presentation.more.onboarding
+
+import android.Manifest
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Build
+import android.os.PowerManager
+import android.provider.Settings
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Check
+import androidx.compose.material3.Icon
+import androidx.compose.material3.ListItem
+import androidx.compose.material3.ListItemDefaults
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.unit.dp
+import androidx.core.content.getSystemService
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import tachiyomi.i18n.MR
+import tachiyomi.presentation.core.i18n.stringResource
+import tachiyomi.presentation.core.util.secondaryItemAlpha
+
+internal class PermissionStep : OnboardingStep {
+
+ private var installGranted by mutableStateOf(false)
+ private var notificationGranted by mutableStateOf(false)
+ private var batteryGranted by mutableStateOf(false)
+
+ override val isComplete: Boolean
+ get() = installGranted
+
+ @Composable
+ override fun Content() {
+ val context = LocalContext.current
+ val lifecycleOwner = LocalLifecycleOwner.current
+
+ DisposableEffect(lifecycleOwner.lifecycle) {
+ val observer = object : DefaultLifecycleObserver {
+ override fun onResume(owner: LifecycleOwner) {
+ installGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ context.packageManager.canRequestPackageInstalls()
+ } else {
+ @Suppress("DEPRECATION")
+ Settings.Secure.getInt(context.contentResolver, Settings.Secure.INSTALL_NON_MARKET_APPS) != 0
+ }
+ notificationGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ context.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) ==
+ PackageManager.PERMISSION_GRANTED
+ } else {
+ true
+ }
+ batteryGranted = context.getSystemService()!!
+ .isIgnoringBatteryOptimizations(context.packageName)
+ }
+ }
+ lifecycleOwner.lifecycle.addObserver(observer)
+ onDispose {
+ lifecycleOwner.lifecycle.removeObserver(observer)
+ }
+ }
+
+ Column(
+ modifier = Modifier.padding(vertical = 16.dp),
+ ) {
+ SectionHeader(stringResource(MR.strings.onboarding_permission_type_required))
+
+ PermissionItem(
+ title = stringResource(MR.strings.onboarding_permission_install_apps),
+ subtitle = stringResource(MR.strings.onboarding_permission_install_apps_description),
+ granted = installGranted,
+ onButtonClick = {
+ val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {
+ data = Uri.parse("package:${context.packageName}")
+ }
+ } else {
+ Intent(Settings.ACTION_SECURITY_SETTINGS)
+ }
+ context.startActivity(intent)
+ },
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ SectionHeader(stringResource(MR.strings.onboarding_permission_type_optional))
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ val permissionRequester = rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.RequestPermission(),
+ onResult = {
+ // no-op. resulting checks is being done on resume
+ },
+ )
+ PermissionItem(
+ title = stringResource(MR.strings.onboarding_permission_notifications),
+ subtitle = stringResource(MR.strings.onboarding_permission_notifications_description),
+ granted = notificationGranted,
+ onButtonClick = { permissionRequester.launch(Manifest.permission.POST_NOTIFICATIONS) },
+ )
+ }
+
+ PermissionItem(
+ title = stringResource(MR.strings.onboarding_permission_ignore_battery_opts),
+ subtitle = stringResource(MR.strings.onboarding_permission_ignore_battery_opts_description),
+ granted = batteryGranted,
+ onButtonClick = {
+ @SuppressLint("BatteryLife")
+ val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply {
+ data = Uri.parse("package:${context.packageName}")
+ }
+ context.startActivity(intent)
+ },
+ )
+ }
+ }
+
+ @Composable
+ private fun SectionHeader(
+ text: String,
+ modifier: Modifier = Modifier,
+ ) {
+ Text(
+ text = text,
+ style = MaterialTheme.typography.titleLarge,
+ modifier = modifier
+ .padding(horizontal = 16.dp)
+ .secondaryItemAlpha(),
+ )
+ }
+
+ @Composable
+ private fun PermissionItem(
+ title: String,
+ subtitle: String,
+ granted: Boolean,
+ modifier: Modifier = Modifier,
+ onButtonClick: () -> Unit,
+ ) {
+ ListItem(
+ modifier = modifier,
+ headlineContent = { Text(text = title) },
+ supportingContent = { Text(text = subtitle) },
+ trailingContent = {
+ OutlinedButton(
+ enabled = !granted,
+ onClick = onButtonClick,
+ ) {
+ if (granted) {
+ Icon(
+ imageVector = Icons.Default.Check,
+ contentDescription = null,
+ tint = MaterialTheme.colorScheme.primary,
+ )
+ } else {
+ Text(stringResource(MR.strings.onboarding_permission_action_grant))
+ }
+ }
+ },
+ colors = ListItemDefaults.colors(containerColor = Color.Transparent),
+ )
+ }
+}
diff --git a/app/src/main/java/eu/kanade/presentation/more/onboarding/StorageStep.kt b/app/src/main/java/eu/kanade/presentation/more/onboarding/StorageStep.kt
index 062e5a7c9..74a1be4ae 100644
--- a/app/src/main/java/eu/kanade/presentation/more/onboarding/StorageStep.kt
+++ b/app/src/main/java/eu/kanade/presentation/more/onboarding/StorageStep.kt
@@ -7,46 +7,66 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import eu.kanade.presentation.more.settings.screen.SettingsDataScreen
import eu.kanade.tachiyomi.util.system.toast
-import tachiyomi.core.preference.Preference
+import kotlinx.coroutines.flow.collectLatest
+import tachiyomi.domain.storage.service.StoragePreferences
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Button
import tachiyomi.presentation.core.i18n.stringResource
+import uy.kohesive.injekt.Injekt
+import uy.kohesive.injekt.api.get
-@Composable
-internal fun StorageStep(
- storagePref: Preference,
-) {
- val context = LocalContext.current
- val pickStorageLocation = SettingsDataScreen.storageLocationPicker(storagePref)
+internal class StorageStep : OnboardingStep {
- Column(
- modifier = Modifier.padding(16.dp),
- verticalArrangement = Arrangement.spacedBy(8.dp),
- ) {
- Text(
- stringResource(
- MR.strings.onboarding_storage_info,
- stringResource(MR.strings.app_name),
- SettingsDataScreen.storageLocationText(storagePref),
- ),
- )
+ private val storagePref = Injekt.get().baseStorageDirectory()
- Button(
- modifier = Modifier.fillMaxWidth(),
- onClick = {
- try {
- pickStorageLocation.launch(null)
- } catch (e: ActivityNotFoundException) {
- context.toast(MR.strings.file_picker_error)
- }
- },
+ private var _isComplete by mutableStateOf(false)
+
+ override val isComplete: Boolean
+ get() = _isComplete
+
+ @Composable
+ override fun Content() {
+ val context = LocalContext.current
+ val pickStorageLocation = SettingsDataScreen.storageLocationPicker(storagePref)
+
+ Column(
+ modifier = Modifier.padding(16.dp),
+ verticalArrangement = Arrangement.spacedBy(8.dp),
) {
- Text(stringResource(MR.strings.onboarding_storage_action_select))
+ Text(
+ stringResource(
+ MR.strings.onboarding_storage_info,
+ stringResource(MR.strings.app_name),
+ SettingsDataScreen.storageLocationText(storagePref),
+ ),
+ )
+
+ Button(
+ modifier = Modifier.fillMaxWidth(),
+ onClick = {
+ try {
+ pickStorageLocation.launch(null)
+ } catch (e: ActivityNotFoundException) {
+ context.toast(MR.strings.file_picker_error)
+ }
+ },
+ ) {
+ Text(stringResource(MR.strings.onboarding_storage_action_select))
+ }
+ }
+
+ LaunchedEffect(Unit) {
+ storagePref.changes()
+ .collectLatest { _isComplete = storagePref.isSet() }
}
}
}
diff --git a/app/src/main/java/eu/kanade/presentation/more/onboarding/ThemeStep.kt b/app/src/main/java/eu/kanade/presentation/more/onboarding/ThemeStep.kt
index 69951e0b5..dfd7517dc 100644
--- a/app/src/main/java/eu/kanade/presentation/more/onboarding/ThemeStep.kt
+++ b/app/src/main/java/eu/kanade/presentation/more/onboarding/ThemeStep.kt
@@ -8,33 +8,40 @@ import eu.kanade.domain.ui.model.setAppCompatDelegateThemeMode
import eu.kanade.presentation.more.settings.widget.AppThemeModePreferenceWidget
import eu.kanade.presentation.more.settings.widget.AppThemePreferenceWidget
import tachiyomi.presentation.core.util.collectAsState
+import uy.kohesive.injekt.Injekt
+import uy.kohesive.injekt.api.get
-@Composable
-internal fun ThemeStep(
- uiPreferences: UiPreferences,
-) {
- val themeModePref = uiPreferences.themeMode()
- val themeMode by themeModePref.collectAsState()
+internal class ThemeStep : OnboardingStep {
- val appThemePref = uiPreferences.appTheme()
- val appTheme by appThemePref.collectAsState()
+ override val isComplete: Boolean = true
- val amoledPref = uiPreferences.themeDarkAmoled()
- val amoled by amoledPref.collectAsState()
+ private val uiPreferences: UiPreferences = Injekt.get()
- Column {
- AppThemeModePreferenceWidget(
- value = themeMode,
- onItemClick = {
- themeModePref.set(it)
- setAppCompatDelegateThemeMode(it)
- },
- )
+ @Composable
+ override fun Content() {
+ val themeModePref = uiPreferences.themeMode()
+ val themeMode by themeModePref.collectAsState()
- AppThemePreferenceWidget(
- value = appTheme,
- amoled = amoled,
- onItemClick = { appThemePref.set(it) },
- )
+ val appThemePref = uiPreferences.appTheme()
+ val appTheme by appThemePref.collectAsState()
+
+ val amoledPref = uiPreferences.themeDarkAmoled()
+ val amoled by amoledPref.collectAsState()
+
+ Column {
+ AppThemeModePreferenceWidget(
+ value = themeMode,
+ onItemClick = {
+ themeModePref.set(it)
+ setAppCompatDelegateThemeMode(it)
+ },
+ )
+
+ AppThemePreferenceWidget(
+ value = appTheme,
+ amoled = amoled,
+ onItemClick = { appThemePref.set(it) },
+ )
+ }
}
}
diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt
index c3286d78a..83ac603d9 100644
--- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt
+++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsDataScreen.kt
@@ -37,9 +37,9 @@ import eu.kanade.presentation.more.settings.screen.data.CreateBackupScreen
import eu.kanade.presentation.more.settings.widget.BasePreferenceWidget
import eu.kanade.presentation.more.settings.widget.PrefsHorizontalPadding
import eu.kanade.presentation.util.relativeTimeSpanString
-import eu.kanade.tachiyomi.data.backup.BackupCreateJob
import eu.kanade.tachiyomi.data.backup.BackupFileValidator
-import eu.kanade.tachiyomi.data.backup.BackupRestoreJob
+import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
+import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.download.DownloadCache
import eu.kanade.tachiyomi.data.sync.SyncDataJob
@@ -107,7 +107,6 @@ object SettingsDataScreen : SearchableSettings {
UniFile.fromUri(context, uri)?.let {
storageDirPref.set(it.uri.toString())
}
- Injekt.get().invalidateCache()
}
}
}
diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt
index 96c6ead6a..261a1b20a 100644
--- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt
+++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/data/CreateBackupScreen.kt
@@ -29,8 +29,8 @@ import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.util.Screen
-import eu.kanade.tachiyomi.data.backup.BackupCreateFlags
-import eu.kanade.tachiyomi.data.backup.BackupCreateJob
+import eu.kanade.tachiyomi.data.backup.create.BackupCreateFlags
+import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
import eu.kanade.tachiyomi.data.backup.models.Backup
import eu.kanade.tachiyomi.util.system.DeviceUtil
import eu.kanade.tachiyomi.util.system.toast
diff --git a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt
index 78b8fc953..07693aa3a 100644
--- a/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt
+++ b/app/src/main/java/eu/kanade/presentation/track/TrackInfoDialogHome.kt
@@ -248,7 +248,6 @@ private fun TrackDetailsItem(
Box(
modifier = modifier
.clickable(onClick = onClick)
- .alpha(if (text == null) UnsetStatusTextAlpha else 1f)
.fillMaxHeight()
.padding(12.dp),
contentAlignment = Alignment.Center,
@@ -259,7 +258,7 @@ private fun TrackDetailsItem(
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center,
- color = MaterialTheme.colorScheme.onSurface,
+ color = MaterialTheme.colorScheme.onSurface.copy(alpha = if (text == null) UnsetStatusTextAlpha else 1f),
)
}
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt
index f5f6c4f81..775bfe78d 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt
@@ -7,7 +7,7 @@ import eu.kanade.domain.base.BasePreferences
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.ui.UiPreferences
import eu.kanade.tachiyomi.core.security.SecurityPreferences
-import eu.kanade.tachiyomi.data.backup.BackupCreateJob
+import eu.kanade.tachiyomi.data.backup.create.BackupCreateJob
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
import eu.kanade.tachiyomi.data.track.TrackerManager
import eu.kanade.tachiyomi.network.NetworkPreferences
@@ -66,10 +66,6 @@ object Migrations {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
- if (oldVersion < 14) {
- // Restore jobs after upgrading to Evernote's job scheduler.
- LibraryUpdateJob.setupTask(context)
- }
if (oldVersion < 15) {
// Delete internal chapter cache dir.
File(context.cacheDir, "chapter_disk_cache").deleteRecursively()
@@ -96,11 +92,6 @@ object Migrations {
}
}
}
- if (oldVersion < 43) {
- // Restore jobs after migrating from Evernote's job scheduler to WorkManager.
- LibraryUpdateJob.setupTask(context)
- BackupCreateJob.setupTask(context)
- }
if (oldVersion < 44) {
// Reset sorting preference if using removed sort by source
val oldSortingMode = prefs.getInt(libraryPreferences.sortingMode().key(), 0)
@@ -259,9 +250,6 @@ object Migrations {
basePreferences.extensionInstaller().set(BasePreferences.ExtensionInstaller.LEGACY)
}
}
- if (oldVersion < 76) {
- BackupCreateJob.setupTask(context)
- }
if (oldVersion < 77) {
val oldReaderTap = prefs.getBoolean("reader_tap", false)
if (!oldReaderTap) {
@@ -374,9 +362,6 @@ object Migrations {
}
}
}
- if (oldVersion < 100) {
- BackupCreateJob.setupTask(context)
- }
if (oldVersion < 105) {
val pref = libraryPreferences.autoUpdateDeviceRestrictions()
if (pref.isSet() && "battery_not_low" in pref.get()) {
@@ -396,12 +381,7 @@ object Migrations {
newKey = { Preference.privateKey(it) },
)
}
- if (oldVersion < 111) {
- File(context.cacheDir, "dl_index_cache")
- .takeIf { it.exists() }
- ?.delete()
- }
- if (oldVersion < 112) {
+ if (oldVersion < 113) {
val prefsToReplace = listOf(
"pref_download_only",
"incognito_mode",
@@ -421,6 +401,9 @@ object Migrations {
filterPredicate = { it.key in prefsToReplace },
newKey = { Preference.appStateKey(it) },
)
+
+ // Deleting old download cache index files, but might as well clear it all out
+ context.cacheDir.deleteRecursively()
}
return true
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupNotifier.kt
index 71bdbcc08..be914cf5b 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupNotifier.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupNotifier.kt
@@ -68,18 +68,18 @@ class BackupNotifier(private val context: Context) {
}
}
- fun showBackupComplete(unifile: UniFile) {
+ fun showBackupComplete(file: UniFile) {
context.cancelNotification(Notifications.ID_BACKUP_PROGRESS)
with(completeNotificationBuilder) {
setContentTitle(context.stringResource(MR.strings.backup_created))
- setContentText(unifile.filePath ?: unifile.name)
+ setContentText(file.filePath ?: file.name)
clearActions()
addAction(
R.drawable.ic_share_24dp,
context.stringResource(MR.strings.action_share),
- NotificationReceiver.shareBackupPendingBroadcast(context, unifile.uri),
+ NotificationReceiver.shareBackupPendingBroadcast(context, file.uri),
)
show(Notifications.ID_BACKUP_COMPLETE)
@@ -88,13 +88,16 @@ class BackupNotifier(private val context: Context) {
fun showRestoreProgress(
content: String = "",
- contentTitle: String = context.stringResource(
- MR.strings.restoring_backup,
- ),
progress: Int = 0,
maxAmount: Int = 100,
+ sync: Boolean = false,
): NotificationCompat.Builder {
val builder = with(progressNotificationBuilder) {
+ val contentTitle = if (sync) {
+ context.stringResource(MR.strings.syncing_library)
+ } else {
+ context.stringResource(MR.strings.restoring_backup)
+ }
setContentTitle(contentTitle)
if (!preferences.hideNotificationContent().get()) {
@@ -133,10 +136,14 @@ class BackupNotifier(private val context: Context) {
errorCount: Int,
path: String?,
file: String?,
- contentTitle: String = context.stringResource(
- MR.strings.restore_completed,
- ),
+ sync: Boolean,
) {
+ val contentTitle = if (sync) {
+ context.stringResource(MR.strings.library_sync_complete)
+ } else {
+ context.stringResource(MR.strings.restore_completed)
+ }
+
context.cancelNotification(Notifications.ID_RESTORE_PROGRESS)
val timeString = context.stringResource(
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt
deleted file mode 100644
index 35377eb0f..000000000
--- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestorer.kt
+++ /dev/null
@@ -1,679 +0,0 @@
-package eu.kanade.tachiyomi.data.backup
-
-import android.content.Context
-import android.net.Uri
-import eu.kanade.domain.manga.interactor.UpdateManga
-import eu.kanade.tachiyomi.data.backup.models.BackupCategory
-import eu.kanade.tachiyomi.data.backup.models.BackupHistory
-import eu.kanade.tachiyomi.data.backup.models.BackupManga
-import eu.kanade.tachiyomi.data.backup.models.BackupPreference
-import eu.kanade.tachiyomi.data.backup.models.BackupSource
-import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
-import eu.kanade.tachiyomi.data.backup.models.BooleanPreferenceValue
-import eu.kanade.tachiyomi.data.backup.models.FloatPreferenceValue
-import eu.kanade.tachiyomi.data.backup.models.IntPreferenceValue
-import eu.kanade.tachiyomi.data.backup.models.LongPreferenceValue
-import eu.kanade.tachiyomi.data.backup.models.StringPreferenceValue
-import eu.kanade.tachiyomi.data.backup.models.StringSetPreferenceValue
-import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
-import eu.kanade.tachiyomi.source.model.copyFrom
-import eu.kanade.tachiyomi.source.sourcePreferences
-import eu.kanade.tachiyomi.util.BackupUtil
-import eu.kanade.tachiyomi.util.system.createFileInCacheDir
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.ensureActive
-import tachiyomi.core.i18n.stringResource
-import tachiyomi.core.preference.AndroidPreferenceStore
-import tachiyomi.core.preference.PreferenceStore
-import tachiyomi.data.DatabaseHandler
-import tachiyomi.data.Manga_sync
-import tachiyomi.data.Mangas
-import tachiyomi.data.UpdateStrategyColumnAdapter
-import tachiyomi.domain.category.interactor.GetCategories
-import tachiyomi.domain.chapter.interactor.GetChaptersByMangaId
-import tachiyomi.domain.chapter.model.Chapter
-import tachiyomi.domain.history.model.HistoryUpdate
-import tachiyomi.domain.library.service.LibraryPreferences
-import tachiyomi.domain.manga.interactor.FetchInterval
-import tachiyomi.domain.manga.model.Manga
-import tachiyomi.domain.sync.SyncPreferences
-import tachiyomi.domain.track.model.Track
-import tachiyomi.i18n.MR
-import uy.kohesive.injekt.Injekt
-import uy.kohesive.injekt.api.get
-import java.io.File
-import java.text.SimpleDateFormat
-import java.time.ZonedDateTime
-import java.util.Date
-import java.util.Locale
-import kotlin.math.max
-
-class BackupRestorer(
- private val context: Context,
- private val notifier: BackupNotifier,
-) {
-
- private val handler: DatabaseHandler = Injekt.get()
- private val updateManga: UpdateManga = Injekt.get()
- private val getCategories: GetCategories = Injekt.get()
- private val getChaptersByMangaId: GetChaptersByMangaId = Injekt.get()
- private val fetchInterval: FetchInterval = Injekt.get()
-
- private val preferenceStore: PreferenceStore = Injekt.get()
- private val libraryPreferences: LibraryPreferences = Injekt.get()
- private val syncPreferences: SyncPreferences = Injekt.get()
-
- private var now = ZonedDateTime.now()
- private var currentFetchWindow = fetchInterval.getWindow(now)
-
- private var restoreAmount = 0
- private var restoreProgress = 0
-
- /**
- * Mapping of source ID to source name from backup data
- */
- private var sourceMapping: Map = emptyMap()
-
- private val errors = mutableListOf>()
-
- suspend fun syncFromBackup(uri: Uri, sync: Boolean) {
- val startTime = System.currentTimeMillis()
- restoreProgress = 0
- errors.clear()
-
- performRestore(uri, sync)
-
- val endTime = System.currentTimeMillis()
- val time = endTime - startTime
-
- val logFile = writeErrorLog()
-
- if (sync) {
- syncPreferences.lastSyncTimestamp().set(Date().time)
- } else {
- notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name)
- }
- }
-
- private fun writeErrorLog(): File {
- try {
- if (errors.isNotEmpty()) {
- val file = context.createFileInCacheDir("tachiyomi_restore.txt")
- val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault())
-
- file.bufferedWriter().use { out ->
- errors.forEach { (date, message) ->
- out.write("[${sdf.format(date)}] $message\n")
- }
- }
- return file
- }
- } catch (e: Exception) {
- // Empty
- }
- return File("")
- }
-
- private suspend fun performRestore(uri: Uri, sync: Boolean) {
- val backup = BackupUtil.decodeBackup(context, uri)
-
- restoreAmount = backup.backupManga.size + 3 // +3 for categories, app prefs, source prefs
-
- // Store source mapping for error messages
- val backupMaps = backup.backupBrokenSources.map { BackupSource(it.name, it.sourceId) } + backup.backupSources
- sourceMapping = backupMaps.associate { it.sourceId to it.name }
- now = ZonedDateTime.now()
- currentFetchWindow = fetchInterval.getWindow(now)
-
- coroutineScope {
- ensureActive()
- restoreCategories(backup.backupCategories)
-
- ensureActive()
- restoreAppPreferences(backup.backupPreferences)
-
- ensureActive()
- restoreSourcePreferences(backup.backupSourcePreferences)
-
- // Restore individual manga
- backup.backupManga.forEach {
- ensureActive()
- restoreManga(it, backup.backupCategories, sync)
- }
-
- // TODO: optionally trigger online library + tracker update
- }
- }
-
- private suspend fun restoreCategories(backupCategories: List) {
- if (backupCategories.isNotEmpty()) {
- val dbCategories = getCategories.await()
- val dbCategoriesByName = dbCategories.associateBy { it.name }
-
- val categories = backupCategories.map {
- dbCategoriesByName[it.name]
- ?: handler.awaitOneExecutable {
- categoriesQueries.insert(it.name, it.order, it.flags)
- categoriesQueries.selectLastInsertedRowId()
- }.let { id -> it.toCategory(id) }
- }
-
- libraryPreferences.categorizedDisplaySettings().set(
- (dbCategories + categories)
- .distinctBy { it.flags }
- .size > 1,
- )
- }
-
- restoreProgress += 1
- showRestoreProgress(
- restoreProgress,
- restoreAmount,
- context.stringResource(MR.strings.categories),
- context.stringResource(MR.strings.restoring_backup),
- )
- }
-
- private suspend fun restoreManga(backupManga: BackupManga, backupCategories: List, sync: Boolean) {
- val manga = backupManga.getMangaImpl()
- val chapters = backupManga.getChaptersImpl()
- val categories = backupManga.categories.map { it.toInt() }
- val history =
- backupManga.brokenHistory.map { BackupHistory(it.url, it.lastRead, it.readDuration) } + backupManga.history
- val tracks = backupManga.getTrackingImpl()
-
- try {
- val dbManga = getMangaFromDatabase(manga.url, manga.source)
- val restoredManga = if (dbManga == null) {
- // Manga not in database
- restoreExistingManga(manga, chapters, categories, history, tracks, backupCategories)
- } else {
- // Manga in database
- // Copy information from manga already in database
- val updatedManga = restoreExistingManga(manga, dbManga)
- // Fetch rest of manga information
- restoreNewManga(updatedManga, chapters, categories, history, tracks, backupCategories)
- }
- updateManga.awaitUpdateFetchInterval(restoredManga, now, currentFetchWindow)
- } catch (e: Exception) {
- val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
- errors.add(Date() to "${manga.title} [$sourceName]: ${e.message}")
- }
-
- restoreProgress += 1
- if (sync) {
- showRestoreProgress(
- restoreProgress,
- restoreAmount,
- manga.title,
- context.stringResource(MR.strings.syncing_library),
- )
- } else {
- showRestoreProgress(
- restoreProgress,
- restoreAmount,
- manga.title,
- context.stringResource(MR.strings.restoring_backup),
- )
- }
- }
-
- /**
- * Returns manga
- *
- * @return [Manga], null if not found
- */
- private suspend fun getMangaFromDatabase(url: String, source: Long): Mangas? {
- return handler.awaitOneOrNull { mangasQueries.getMangaByUrlAndSource(url, source) }
- }
-
- private suspend fun restoreExistingManga(manga: Manga, dbManga: Mangas): Manga {
- var updatedManga = manga.copy(id = dbManga._id)
- updatedManga = updatedManga.copyFrom(dbManga)
- updateManga(updatedManga)
- return updatedManga
- }
-
- suspend fun updateManga(manga: Manga): Long {
- handler.await(true) {
- mangasQueries.update(
- source = manga.source,
- url = manga.url,
- artist = manga.artist,
- author = manga.author,
- description = manga.description,
- genre = manga.genre?.joinToString(separator = ", "),
- title = manga.title,
- status = manga.status,
- thumbnailUrl = manga.thumbnailUrl,
- favorite = manga.favorite,
- lastUpdate = manga.lastUpdate,
- nextUpdate = null,
- calculateInterval = null,
- initialized = manga.initialized,
- viewer = manga.viewerFlags,
- chapterFlags = manga.chapterFlags,
- coverLastModified = manga.coverLastModified,
- dateAdded = manga.dateAdded,
- mangaId = manga.id,
- updateStrategy = manga.updateStrategy.let(UpdateStrategyColumnAdapter::encode),
- )
- }
- return manga.id
- }
-
- /**
- * Fetches manga information
- *
- * @param manga manga that needs updating
- * @param chapters chapters of manga that needs updating
- * @param categories categories that need updating
- */
- private suspend fun restoreExistingManga(
- manga: Manga,
- chapters: List,
- categories: List,
- history: List,
- tracks: List
Esta versión de Android ya no es compatible
No se pudo copiar al portapapeles
- DNS por HTTPS (DoH)
+ DNS sobre HTTPS (DoH)
Los elementos de las categorías excluidas no se descargarán, ni siquiera si pertenecen a alguna de las categorías que sí estén incluidas.
Descarga automática
En horizontal
@@ -476,7 +476,7 @@
Incluir: %s
Ninguna
Los elementos de las categorías excluidas no se actualizarán, ni siquiera si pertenecen a alguna de las categorías que sí estén incluidas.
- Toca para ver los detalles del error
+ Toca para ver los detalles
Mostrar el número de elementos
Fecha de obtención del capítulo
Tipo de rotación
@@ -554,7 +554,7 @@
Advertencia: Las descargas grandes pueden llevar a que las fuentes se vuelvan cada vez más lentas y en casos extremos que los servidores limiten o impidan el acceso a Tachiyomi. Toca aquí para más información.
Actualizar todas
Actualizaciones de la aplicación
- Borrar la caché de capítulos al abrir la aplicación
+ Limpiar la caché de capítulos al abrir la aplicación
Base de datos limpia
%1$d entradas que no pertenecen a la biblioteca en la base de datos
No se pudo descargar el listado de extensiones
@@ -619,15 +619,15 @@
Borrar categoría
¿Quieres borrar la categoría «%s»\?
ErrorInterno: Mira el registro de depuración para más información
- Nombre del navegador a usar («user agent»)
- Restablecer el nombre del navegador («user agent»)
+ User agent predeterminado
+ Restablecer user agent predeterminado
Quitar todo
La app no soporta el formato RARv5
Aquí aparecerá el contenido más reciente de tu biblioteca
El widget no está disponible cuando el bloqueo de aplicación está activo
Ya se está actualizando
Marea
- La cadena con el agente de usuario no puede estar vacía
+ El valor del user agent no puede estar en blanco
Solo funciona si el capítulo actual y el que va después ya están descargados.
Descargar por adelantado
Descarga los capítulos siguientes mientras lees
@@ -654,7 +654,7 @@
Título desconocido
Ubicación incorrecta: %s
Ahora mismo
- El nombre de agente de usuario no vale
+ Valor de user agent inválido
Reindexando descargas
Abrir un elemento al azar
Parece que esta categoría está vacía
@@ -768,4 +768,29 @@
Subir un nivel
Ubicación del almacenamiento
Se utiliza para las copias de seguridad automáticas, las descargas de capítulos y la fuente local.
+ Seleccionar una carpeta
+ Guía de incorporación
+ ¿Nuevo en %s? Recomendamos consultar la guía de introducción.
+ Comenzar
+ Debe seleccionarse una carpeta
+ Bienvenido!
+ ¿Ya usaste %s antes?
+ Saltar
+ Siguiente
+ Vamos a configurar algunas cosas primero. Siempre puedes volver a cambiarlas más tarde en la configuración.
+ No se ha establecido una ubicación de almacenamiento
+ Selecciona una carpeta donde %1$s almacenará las descargas de capítulos, copias de seguridad y más.
+\n
+\nSe recomienda una carpeta dedicada.
+\n
+\nCarpeta seleccionada: %2$s
+ Permiso para instalar aplicaciones
+ Opcional
+ Requerido
+ Permiso de notificación
+ Evitar interrupciones en las actualizaciones largas de la biblioteca, descargas y restauraciones de copias de seguridad.
+ Uso de batería en segundo plano
+ Para instalar las extensiones de fuentes.
+ Recibe notificaciones sobre actualizaciones de la biblioteca y más.
+ Permitir
\ No newline at end of file
diff --git a/i18n/src/commonMain/resources/MR/fil/strings.xml b/i18n/src/commonMain/resources/MR/fil/strings.xml
index 1b63f248e..ebc249a00 100644
--- a/i18n/src/commonMain/resources/MR/fil/strings.xml
+++ b/i18n/src/commonMain/resources/MR/fil/strings.xml
@@ -99,9 +99,9 @@
Pamahalaan ang mga abiso
Seguridad at privacy
Ayos ng petsa
- Nakabukas
- Nakasara
- Sundan ang sistema
+ Madilim
+ Maliwanag
+ Sistema
Patungkol
Karagdagan
Pagta-track
@@ -115,7 +115,7 @@
Huling nabasang kabanata
Sarado
Pagkamarkahang nabasa na
- Pagkatapos basahin, kusang burahin
+ Pagkatapos basahin, awtomatikong burahin
Kapal ng gilid
Pagbabasa
Ipakita palagi ang paglipat-kabanata
@@ -133,7 +133,7 @@
Gitna
Kanan
Kaliwa
- Kusa
+ Awtomatiko
Panimulang pag-zoom
Matalinong pagsasalaki
Orihinal na laki
@@ -185,7 +185,7 @@
\nMaaaring mabasa ng isang kaduda-dudang extension ang kahit anong nakatagong credentials sa pag-login o di kaya nama\'y magsimula ng delikadong code.
\n
\nTinatanggap mo ang mga bantang ito sa pagtiwala sa certificate na ito.
- Kaduda-dudang extension
+ Di-pinagkakatiwalaang extension
I-uninstall
Tiwala
Kaduda-duda
@@ -202,17 +202,17 @@
Palaging tanungin
Default na kategorya
Maghanap ng mga bagong cover at detalye kapag nag-a-update ng Aklatan
- Kusang sariwain ang metadata
+ Awtomatikong i-refresh ang metadata
May \"Kumpleto\" na estado
Kapag naka-charge
- Kondisyon sa kusang pag-update
+ Awtomatikong ina-update ang mga paghihigpit sa device
Linggo-linggo
Kada 2 araw
Araw-araw
Kada 12 oras
Kada 6 na oras
Nakapatay
- Kusang pag-update
+ Awtomatikong pag-update
Panlahatang update
Pahiga
Patayo
@@ -385,7 +385,7 @@
Nakatutulong sa pag-update ng aklatan sa background at pag-backup
I-refresh ang mga cover sa aklatan
Binura na
- Sigurado ka ba\? Ang mga nabasang kabanata at pag-unlad ng mga wala sa aklatan ay mawawala
+ Sigurado ka ba? Ang mga nabasang kabanata at progress ng mga wala sa aklatan ay mawawala
Burahin ang nakaraan ng mga entry na hindi naka-save sa aklatan mo
Linisin ang database
Nagka-error habang nililinis
@@ -508,7 +508,7 @@
I-download na
May dagdag na mga restriksyon sa app ang ilang mga modelo ng phone na pumapatay sa mga serbisyo sa background. May impormasyon sa site na ito para maayos ang naturang problema.
Maaaring hindi gumana nang maayos ang pag-backup/pag-restore kung nakasara ang MIUI optimization.
- Nagbibigay ng mga pinahusay na mga feature para sa ilang mga source. Kusang tina-track ang mga entry kapag naidagdag ito sa iyong aklatan.
+ Nagbibigay ng mga pinahusay na mga feature para sa ilang mga source. Awtomatikong tina-track ang mga entry kapag naidagdag ito sa iyong aklatan.
Pinahusay na tracker
Hatinggabi
Berdeng Mansanas
@@ -519,7 +519,7 @@
Yin at Yang
Tako
Presas
- Gawaing likuran
+ Aktibidad sa background
Pinakamababa
Mababa
Mataas
@@ -535,9 +535,9 @@
Gabay sa Pagsisimula
Pang-tablet na UI
Tumulong sa pagsalin
- Kategoryang di-kasama
+ Mga hindi kasamang kategorya
Tungkol sa app
- Paki-install at buksan ang Shizuku para magamit ito bilang taga-install ng extension.
+ I-Install at buksan ang Shizuku para magamit ito bilang taga-install ng extension.
Di tumatakbo ang Shizuku
Legasiya
Taga-install
@@ -551,7 +551,7 @@
Dapat nagtatabi rin kayo ng mga kopya ng backup sa ibang mga lugar. Ang mga backup ay naglalaman ng sensitibong data tulad ng nakaimbak na password; mag-ingat kung ibahagi ito.
Sa Wi-Fi lang
Kada 3 araw
- Babala: maaaring humantong sa pagbagal at/o pagharang ng mga source sa Tachiyomi ang mga malalaking maramihang pag-download. I-tap para matuto pa.
+ Babala: maaaring humantong sa pagbagal at/o pagharang ng mga source sa Tachiyomi ang maramihang pag-download. I-tap para matuto pa.
Mga update sa app
I-update lahat
%1$d na entry sa database na wala sa aklatan
@@ -573,7 +573,7 @@
Hindi pa nasisimulan
Nilaktawan dahil may di pa nabasang mga kabanata
Nilaktawan dahil wala pang nabasang mga kabanata
- Kusang mag-zoom sa mga malalawak na larawan
+ Awtomatikong mag-zoom sa mga malalawak na larawan
I-pan ang mga malalapad na larawan
Matuto pa
Nilaktawan
@@ -640,7 +640,7 @@
Nilaktawan dahil hindi kailangan ang pag-update sa serye
Maghanap…
Paraan ng pagbasa, pagpapakita, nabigasyon
- Kusang pag-download, i-download agad
+ Awtomatikong pag-download, i-download nang maaga
Isahang pagsabay sa progress, pinahusay na pagsabay
Tema, ayos ng petsa & oras
Mano-mano at awtomatikong pag-backup, espasyo sa storage
@@ -768,4 +768,20 @@
Napili
Di napili
Mag-navigate pataas
+ Pumili ng folder
+ Gabay sa onboarding
+ Bago sa %s? Inirerekomenda naming tingnan ang gabay sa pagsisimula.
+ Magsimula
+ Dapat pumili ng isang folder
+ Maligayang pagdating!
+ Gumagamit ba ng %s dati?
+ Laktawan
+ Susunod
+ Mag-set up muna tayo ng ilang bagay. Maaari mo ring baguhin ang mga ito anumang oras sa mga setting sa ibang pagkakataon.
+ Walang nakatakdang lokasyon ng storage
+ Pumili ng folder kung saan mag-imbak ang %1$s ng mga na-download ng kabanata, mga backup, at higit pa.
+\n
+\nInirerekomenda ang isang nakalaang folder.
+\n
+\nNapiling folder: %2$s
\ No newline at end of file
diff --git a/i18n/src/commonMain/resources/MR/ja/strings.xml b/i18n/src/commonMain/resources/MR/ja/strings.xml
index c29c25c62..2a0896bed 100644
--- a/i18n/src/commonMain/resources/MR/ja/strings.xml
+++ b/i18n/src/commonMain/resources/MR/ja/strings.xml
@@ -296,9 +296,9 @@
最新章の更新順
章を見る
すべてキャンセル
- オフ
- オン
- システムに従う
+ ライト
+ ダーク
+ システム
通知設定
セキュリティとプライバシー
アンロックを必要とする
@@ -768,4 +768,29 @@
上に移動
保存場所
自動バックアップ、章のダウンロード、ローカル ソースの保存位置となります。
+ フォルダを選択してください
+ 初回設定ガイド
+ %sは初めて?入門ガイドをチェックしてみしましょう。
+ はじめる
+ フォルダを選択してください
+ ようこそ!
+ %sを使ったことはもうありましたか?
+ スキップ
+ 次へ
+ はじめに初回設定をしていきましょう。このあとも「設定」にていつも変更できます。
+ 保存場所が設定されていません
+ %1$sのダウンロード、バックアップなどの保存先のフォルダを設定してください。
+\n
+\nアプリ専用のフォルダの作成・使用がおすすめです。
+\n
+\n選択したフォルダ:%2$s
+ 通知の許可
+ アプリのインストールの許可
+ 時間のかかるライブラリ更新、ダウンロードやバックアップの復元などへの中断を防ぎます。
+ 任意
+ バックグラウンドでのバッテリー使用量
+ ソース拡張機能をインストールするために必要です。
+ ライブラリ更新などの通知を送信します。
+ 必須
+ 許可
\ No newline at end of file
diff --git a/i18n/src/commonMain/resources/MR/ko/strings.xml b/i18n/src/commonMain/resources/MR/ko/strings.xml
index bd031f966..d22abee8b 100644
--- a/i18n/src/commonMain/resources/MR/ko/strings.xml
+++ b/i18n/src/commonMain/resources/MR/ko/strings.xml
@@ -150,7 +150,7 @@
쿠키 삭제됨
데이터베이스 삭제
서재에 추가되지 않은 항목의 기록을 삭제합니다
- 확실합니까\? 서재에 없는 항목의 읽은 기록이 삭제됩니다
+ 확실합니까? 서재에 없는 항목의 읽기 기록이 삭제됩니다
버전
오류 보고서 전송
버그를 수정하는데 도움이 됩니다. 개인 정보는 전송되지 않습니다
@@ -309,7 +309,7 @@
배터리 최적화 끄기
MIUI 최적화가 꺼져 있을 경우 백업/복원 기능이 정상 작동하지 않을 수 있습니다.
복원이 이미 진행중 입니다
- 설정을 적용하기 위해 앱을 재시작해야 합니다
+ 앱을 재시작한 후에 적용됩니다
DNS over HTTPS (DoH)
데이터
백업이 이미 진행중입니다
@@ -448,7 +448,7 @@
없어진 소스:
로그인 되지않은 트래커:
앱 실행 시 회차 캐시 삭제
- 데이터베이스에 없는 항목이 %1$d개 있습니다
+ 서재에 없는 항목이 데이터베이스에 %1$d개 있습니다
일부 제조사는 백그라운드 서비스를 종료하는 추가적인 제한 사항이 있습니다. 자세한 사항은 웹사이트를 참조하세요.
태블릿 UI
탭
@@ -622,7 +622,7 @@
마지막 회차를 열 수 없습니다
최근에 업데이트된 항목 보기
보류 목록
- 분할하는 동안 %d 페이지를 찾을 수 없습니다
+ 분리 중 페이지 %d을 찾을 수 없습니다
RARv5 포맷은 지원되지 않습니다
앱 잠금 사용 중에는 위젯을 이용할 수 없습니다
파도
diff --git a/i18n/src/commonMain/resources/MR/nb-rNO/strings.xml b/i18n/src/commonMain/resources/MR/nb-rNO/strings.xml
index 7ee0417ac..317716a2b 100644
--- a/i18n/src/commonMain/resources/MR/nb-rNO/strings.xml
+++ b/i18n/src/commonMain/resources/MR/nb-rNO/strings.xml
@@ -300,8 +300,8 @@
Mer
Vis kapitler
Avbryt alle
- Av
- På
+ Lyst
+ Mørkt
System
Håndter merknader
Sikkerhet og personvern
@@ -768,4 +768,20 @@
Data og lagring
Ingen fil valgt
Ekskluder skanningsoversettere
+ Velg en mappe
+ Introduksjonsguide
+ Ny til %s? Vi anbefaler å sjekke ut startveiledningen.
+ Kom i gang
+ En mappe må velges
+ Velkommen!
+ Allerede brukt %s før?
+ Hopp over
+ Neste
+ La oss sette opp noen ting først. Du kan alltid endre disse i innstillingene senere også.
+ Ingen lagringsplassering angitt
+ Velg en mappe der %1$s vil lagre kapittelnedlastinger, sikkerhetskopier og mer.
+\n
+\nEn dedikert mappe anbefales.
+\n
+\nValgt mappe: %2$s
\ No newline at end of file
diff --git a/i18n/src/commonMain/resources/MR/pt-rBR/strings.xml b/i18n/src/commonMain/resources/MR/pt-rBR/strings.xml
index cf3133d7c..b32191324 100644
--- a/i18n/src/commonMain/resources/MR/pt-rBR/strings.xml
+++ b/i18n/src/commonMain/resources/MR/pt-rBR/strings.xml
@@ -783,4 +783,14 @@
\nUma pasta dedicada é recomendada.
\n
\nPasta selecionada: %2$s
+ Uma pasta deve ser selecionada
+ Permissão de notificação
+ Permissão de instalação de aplicativos
+ Evite interrupções para tarefas longas como atualizações da biblioteca, downloads e restauração de backups.
+ Opcional
+ Uso de bateria em plano de fundo
+ Para instalar extensões de fontes.
+ Seja notificado para atualizações da biblioteca e mais.
+ Obrigatório
+ Conceder
\ No newline at end of file
diff --git a/i18n/src/commonMain/resources/MR/ru/strings.xml b/i18n/src/commonMain/resources/MR/ru/strings.xml
index 7c2382369..02ca35d48 100644
--- a/i18n/src/commonMain/resources/MR/ru/strings.xml
+++ b/i18n/src/commonMain/resources/MR/ru/strings.xml
@@ -301,8 +301,8 @@
Последняя глава
Просмотреть главы
Отменить всё
- Выключен
- Включён
+ Светлая
+ Тёмная
Система
Управление уведомлениями
Безопасность и конфиденциальность
@@ -768,4 +768,20 @@
Перейти вверх
Путь хранилища
Используется для автоматических резевных копии, загрузок глав и источнике на устройстве.
+ Выбрать папку
+ Руководство для начинающих
+ Новичок в %s? Мы настоятельно рекомендуем ознакомиться с нашим руководством.
+ Начать
+ Необходимо выбрать папку
+ Добро пожаловать!
+ Уже использовали %s раньше?
+ Пропустить
+ Следующее
+ Давайте настроем парочку вещей. Вы всегда можете их поменять позже в настройках.
+ Не указан путь хранилища
+ Выберите папку где %1$s будет хранить загруженные главы, резервные копии и другое.
+\n
+\nРекомендуется использовать выделенную папку.
+\n
+\nВыбранная папка: %2$s
\ No newline at end of file
diff --git a/i18n/src/commonMain/resources/MR/sq/strings.xml b/i18n/src/commonMain/resources/MR/sq/strings.xml
index 472bf5342..5d85150c0 100644
--- a/i18n/src/commonMain/resources/MR/sq/strings.xml
+++ b/i18n/src/commonMain/resources/MR/sq/strings.xml
@@ -26,12 +26,12 @@
Rifresko
Aplikacioni i padisponueshem
Shkarkim automatik, shkarko përpara
- Aktiv
+ Errët
Molle jeshile
Livando
Yin & Yang
Yotsuba
- valët e baticës
+ Valët e Baticës
E zezë e pastër modaliteti i errët
Menaxho njoftimet
Gjuha e aplikacionit
@@ -46,7 +46,7 @@
Shfaq në listat e burimeve dhe shtesave
Sot
Shfaqja
- Artikuj për rresht
+ Përmasat e grafikut
Përditësim global
Joaktiv
Çdo 12 orë
@@ -55,11 +55,11 @@
Vetëm në Wi-Fi
Vetëm në rrjet pa matje
Gjatë karikimit
- Kapërceni përditësimin e hyrjeve
+ Kapërceni përditësimin e elementeve
Me kapituj të palexuar
Kontrolloni për kopertinë dhe detaje të reja kur përditësoni bibliotekën
Kategoria e parazgjedhur
- Regjistrimet në kategoritë e përjashtuara nuk do të përditësohen edhe nëse janë gjithashtu në kategoritë e përfshira.
+ Elementet në kategoritë e përjashtuara nuk do të përditësohen edhe nëse janë gjithashtu në kategoritë e përfshira.
Të gjitha
Asnje
Përfshi: %s
@@ -74,7 +74,7 @@
Nuk ofrohet lidhje Wi-Fi
Biblioteka juaj është bosh
Udhëzues për fillimin
- Nuk u gjet asnjë hyrje në këtë kategori
+ Nuk u gjet asnjë element në këtë kategori
Nuk ke kategori. Prekni butonin plus për të krijuar një për organizimin e bibliotekës tuaj.
WebView kërkohet për Tachiyomi
Dështoi të anashkalojë Cloudflare
@@ -96,18 +96,18 @@
Shkarkues
Përditësoni aplikacionin WebView për përputhshmëri më të mirë
E paracaktuar
- Gjurmuar
+ I gjurmuar
Cilësimet
- e palexuar
+ E palexuar
Hiq filtrin
Sipas alfabetit
Totali i kapitujve
Paralajmërim
- Totali i hyrjeve
+ Totali i elementeve
Leximi i fundit
- Vërtetoni për të konfirmuar ndryshimin
+ Vërtetohuni për të konfirmuar ndryshimin
Menuja
- Filtro
+ Filter
Sipas numrit të kapitullit
Kapitujt e shkarkuar
Burimi lokal
@@ -148,7 +148,7 @@
Biblioteka
Lexues
Shkarkimet
- Ndjekja
+ Gjurmimi
Burimet, zgjerimet, kërkimi global
Rezervime manuale & automatike
E avancuar
@@ -158,8 +158,8 @@
Rreth
Hidh regjistrat e përplasjeve, optimizimet e baterisë
Tema
- Ndiq sistemin
- Joaktiv
+ Ndiq Sistemin
+ Ndrçim
Daiquiri luleshtrydhe
Tema e aplikacionit
Dinamik
@@ -184,11 +184,11 @@
Përditëso të gjitha
Përditësimet në pritje
Aktiv
- fikur
+ Fikur
Kategoritë
- Regjistrimet e bibliotekës
+ Elementet e bibliotekës
Kapituj
- Ndjekja
+ Gjurmimi
Historia
Kontrolli i përditësimit të fundit
Numër i palexuar
@@ -237,7 +237,7 @@
Ekrani
Modaliteti i ekranit
Rrjetë kompakte
- Shiko përditësimin e fundit te bibliotekes tuaj
+ Shiko përditësimin e fundit të elementeve të bibliotekes tuaj
Ju jeni gati të hiqni \"%s\" nga biblioteka juaj
Miniaplikacioni nuk ofrohet kur kyçja e aplikacionit është aktivizuar
Në pritje
@@ -351,9 +351,9 @@
Shkarkim automatik gjatë leximit
Ruaje si arkiv CBZ
Udhëzues gjurmimi
- Shërbime të përmirësuara
+ Gjurmues të përmirësuara
Nuk ka kapitull tjetër
- Krijon dosje sipas titullit të hyrjeve
+ Krijon dosje sipas titullit të elementeve
E zezë
Modaliteti i parazgjedhur i leximit
Në formë L
@@ -385,20 +385,20 @@
Kapitulli i dytë deri tek i fundit i lexuar
Kapitulli i tretë deri tek i fundit i lexuar
Kapitulli i pestë deri tek i fundit i lexuar
- Regjistrimet në kategoritë e përjashtuara nuk do të shkarkohen edhe nëse janë gjithashtu në kategoritë e përfshira.
+ Elementet në kategoritë e përjashtuara nuk do të shkarkohen edhe nëse janë gjithashtu në kategoritë e përfshira.
Punon vetëm në hyrjet në bibliotekë dhe nëse kapitulli aktual plus kapitulli tjetër janë shkarkuar tashmë
- Shërbimet
+ Gjurmuesët
Përmirëson performancën e lexuesit
Përditëso progresin pas leximit
- Sinkronizimi i njëanshëm për të përditësuar përparimin e kapitullit në shërbimet e gjurmimit. Konfiguro gjurmimin për hyrjet individuale nga butoni i tyre i gjurmimit.
- faqeshënuar
+ Sinkronizimi i njëanshëm për të përditësuar përparimin e kapitullit në shërbimet e gjurmimit. Konfiguro gjurmimin për elementet individuale nga butoni i tyre i gjurmimit.
+ Faqeshënuar
Webtoon
I çaktivizuar
Kindle-ish
- Shërbime që ofrojnë veçori të përmirësuara për burime specifike. Regjistrimet gjurmohen automatikisht kur shtohen në bibliotekën tuaj.
+ Ofron tipare të përmirësuara për burime specifike. Elementet gjurmohen automatikisht kur shtohen në bibliotekën tuaj.
Pista
Frekuenca rezervë
- Gjurmuesit nuk kanë hyrë në:
+ I pa identifikuar ne gjurmuesit:
%02d min, %02d sek
Rezervimi/rivendosja mund të mos funksionojë siç duhet nëse Optimizimi MIUI është i çaktivizuar.
Rivendos vargun e parazgjedhur të agjentit të përdoruesit
@@ -416,7 +416,7 @@
Sipas datës së ngarkimit
Shkarko
Të palexuara
- Ndjekja
+ Gjurmimi
Lista e papërfunduar
Në listën e pritjes
Lloji
@@ -444,7 +444,7 @@
Zgjidhni të dhënat për të përfshirë
Kapitujt nuk mund të shkarkoheshin. Mund të provoni përsëri në seksionin e shkarkimeve
Përditësimet e mëdha dëmtojnë burimet dhe mund të çojnë në përditësime më të ngadalta dhe gjithashtu rritje të përdorimit të baterisë. Trokit për të mësuar më shumë.
- Hyrjet u fshinë
+ Elementet u fshinë
Çaktivizo optimizimin e baterisë
Adresa e emailit
Hyni në %1$s
@@ -459,7 +459,7 @@
Anuloni indeksin e shkarkimeve
Pastro memorjen e kapitullit në mbylljen e aplikacionit
Pastro bazën e të dhënave
- A je i sigurt\? Lexoni kapitujt dhe përparimi i hyrjeve që nuk janë në bibliotekë do të humbasin
+ A je i sigurt? Kapitujt e lexuar dhe progresi i elementeve që nuk janë në bibliotekë do të humbasin
Nuk ke burime të gozhduara
Urdhër nga
Data
@@ -506,7 +506,7 @@
Duke krijuar rezervë
Rezervimi dështoi
Lejet e ruajtjes nuk janë dhënë
- Nuk ka hyrje në bibliotekë për të rezervuar
+ Nuk ka element në bibliotekë për të rezervuar
Rivendosja është tashmë në proces
Rivendosja e rezervës
Rivendosja e rezervimit dështoi
@@ -522,7 +522,7 @@
Të dhënat
Përdorur: %1$s
Memoria e fshehtë u pastrua. %1$d skedarë janë fshirë
- %1$d hyrje jashtë bibliotekës në bazën e të dhënave
+ %1$d element jashtë bibliotekës në bazën e të dhënave
Pastro të dhënat e WebView
Rifresko kopertinat e bibliotekës
Rivendos cilësimet e lexuesit për seri
@@ -543,7 +543,7 @@
Vetëm të shkarkuarat
Modaliteti i fshehtë
Ndalon leximin e historisë
- Filtro të gjitha hyrjet në bibliotekën tuaj
+ Filtro të gjitha elementet në bibliotekën tuaj
Dil nga %1$s\?
Tani keni dalë nga llogaria
Gabim i panjohur
@@ -578,7 +578,7 @@
Kopertina u ruajt
Gabim në ndarjen e kopertinës
Jeni i sigurt që dëshironi të fshini kapitujt e zgjedhur\?
- Aplikoni gjithashtu për të gjitha hyrjet në bibliotekën time
+ Aplikoni gjithashtu për të gjitha elementet në bibliotekën time
Vendose si parësore
Nuk u gjet asnjë kapitull
A je i sigurt\?
@@ -597,7 +597,7 @@
Data e fillimit
Status
Data e mbarimit
- Të hiqet data\?
+ Hiqni datën?
Kjo do të heqë datën e përfundimit të zgjedhur më parë nga %s
Kategoritë u fshinë
Fotografia u ruajt
@@ -641,10 +641,10 @@
\n
\n Do t\'ju duhet të instaloni çdo shtesë që mungon dhe më pas të identifikoheni në shërbimet e gjurmimit për t\'i përdorur ato.
Skedar rezervë i pavlefshëm
- Rezervimi nuk përmban asnjë hyrje në bibliotekë.
+ Rezervimi nuk përmban asnjë element në bibliotekë.
Varg i parazgjedhur i agjentit të përdoruesit
Pastro memorien e kapitullit
- Fshi historikun për shënimet që nuk janë ruajtur në bibliotekën tënde
+ Fshi historikun për elementet që nuk janë ruajtur në bibliotekën tënde
Të dhënat e WebView u pastruan
Të gjitha cilësimet e lexuesit rivendosen
Përdorur për herë të fundit
@@ -679,19 +679,19 @@
Lexo
N/A
%dd
- Ndjekësit
- Hyrjet e ndjekura
+ Gjurmuesit
+ Elementet e gjurmuara
Jo tani
- Hyrjet e përfunduara
+ Elementet të përfunduara
Koha e të lezuarit
- Hyrjet
+ Elementet
Ne përditësimin global
%do
%dm
Kategorija është bosh
Në dispozicion, por burimi nuk është i instaluar: %s
Kapërceni kapitujt e kopjuar
- Fshih hyrjet tashmë në bibliotekë
+ Fshih elementet tashmë në bibliotekë
Kopjo në kujtesën e fragmenteve
Ju keni një hyrje në librarni me të njëjtin emër.
\n
@@ -700,4 +700,13 @@
%1$s gabim: %2$s
*kërkohet
U kopjua në clipboard
+ Pika e magazinimit
+ Fshi shkarkimet
+ Piket e gjurmimit
+ Hiq %s gjurmimin?
+ Hiqe gjithashtu nga %s
+ Kjo do te heq gjurmimn lokal.
+ Gjurmuesi i identifikimit
+ Koha relative
+ \"%1$s\" në vend të \"%2$s\"
\ No newline at end of file
diff --git a/i18n/src/commonMain/resources/MR/sv/strings.xml b/i18n/src/commonMain/resources/MR/sv/strings.xml
index 5b4509d0b..f8c66ebd2 100644
--- a/i18n/src/commonMain/resources/MR/sv/strings.xml
+++ b/i18n/src/commonMain/resources/MR/sv/strings.xml
@@ -301,9 +301,9 @@
Senaste kapitel
Visa kapitel
Avbryt alla
- Av
- På
- Följ systemet
+ Ljus
+ Mörk
+ System
Hantera aviseringar
Säkerhet och integritet
Kräver upplåsning
@@ -768,4 +768,29 @@
Vald
Inte vald
Navigera upp
+ Välj en mapp
+ Introduktionsguide
+ Ny till %s? Vi rekommenderar att du tar en titt på komma igång guiden.
+ Kom igång
+ En mapp måste väljas
+ Välkommen!
+ Redan använt %s förut?
+ Hoppa över
+ Nästa
+ Låt oss ställa in några saker först. Du kan alltid ändra dessa i inställningarna senare.
+ Ingen lagringsplats inställd
+ Välj en mapp där %1$s lagrar kapitelnedladdningar, säkerhetskopior och mer.
+\n
+\nEn dedikerad mapp rekommenderas.
+\n
+\nVald mapp: %2$s
+ Aviseringsbehörigheter
+ Installera app behörigheter
+ Undvik avbrott i långvariga biblioteksuppdateringar, nedladdningar och säkerhetskopieringsåterställningar.
+ Valfritt
+ Bakgrundsbatterianvändning
+ För att installera källtillägg.
+ Få aviseringar om biblioteksuppdateringar och mer.
+ Krävs
+ Bevilja
\ No newline at end of file
diff --git a/i18n/src/commonMain/resources/MR/tr/strings.xml b/i18n/src/commonMain/resources/MR/tr/strings.xml
index 73abf0de2..54adba6a9 100644
--- a/i18n/src/commonMain/resources/MR/tr/strings.xml
+++ b/i18n/src/commonMain/resources/MR/tr/strings.xml
@@ -301,9 +301,9 @@
Son bölüm
Bölümleri görüntüle
Hepsini iptal et
- Kapalı
- Açık
- Sisteme uy
+ Açık
+ Koyu
+ Sistem
Bildirimleri yönet
Güvenlik ve gizlilik
Kilit açma gerektirir
@@ -768,4 +768,29 @@
Depolama yeri
Kendiliğinden yedeklemeler, bölüm indirmeleri ve yerel kaynak için kullanılır.
Yukarı git
+ Klasör seç
+ Başlangıç rehberi
+ %s\'de yeni misiniz? Başlangıç rehberine göz atmanızı tavsiye ederiz.
+ Başlayın
+ Bir klasör seçilmelidir
+ Hoş geldiniz!
+ Daha önce %s kullandınız mı?
+ Atla
+ Sonraki
+ Önce bazı şeyleri ayarlayalım. Bunları daha sonra ayarlardan da değiştirebilirsiniz.
+ Kaydetme konumu ayarlanmadı
+ %1$s bölüm indirmelerini, yedeklemeleri ve başka şeyleri kaydedeceği bir klasör seçin.
+\n
+\nYalnızca buna ait bir klasör tavsiye edilir.
+\n
+\nSeçilen klasör: %2$s
+ Bildirim izni
+ Uygulama kurma izni
+ Uzun süreli kitaplık güncellemeleri, indirmeler ve yedekleme geri yüklemelerinin kesintiye uğramasını önleyin.
+ İsteğe bağlı
+ Arka planda pil kullanımı
+ Kaynak uzantılarını kurmak için.
+ Kitaplık güncellemeleri ve daha fazlası için bildirim alın.
+ Gerekli
+ Ver
\ No newline at end of file
diff --git a/i18n/src/commonMain/resources/MR/vi/plurals.xml b/i18n/src/commonMain/resources/MR/vi/plurals.xml
index 18fc85c64..df9978d19 100644
--- a/i18n/src/commonMain/resources/MR/vi/plurals.xml
+++ b/i18n/src/commonMain/resources/MR/vi/plurals.xml
@@ -45,4 +45,7 @@
- Đang thiếu %1$s
+
+ - %d ngày
+
\ No newline at end of file
diff --git a/i18n/src/commonMain/resources/MR/vi/strings.xml b/i18n/src/commonMain/resources/MR/vi/strings.xml
index 679f23b97..110a6c3bb 100644
--- a/i18n/src/commonMain/resources/MR/vi/strings.xml
+++ b/i18n/src/commonMain/resources/MR/vi/strings.xml
@@ -315,14 +315,14 @@
Bảo mật và quyền riêng tư
Quản lý thông báo
Định dạng ngày
- Theo hệ thống
- Bật
- Tắt
+ Hệ thống
+ Tối
+ Sáng
Thư viện
Làm mới
Chuyển tới trước
Trở lại
- Di chuyển xuống dưới
+ Di chuyển xuống cuối
Di chuyển lên đầu
Cũ nhất
Mới nhất
@@ -362,7 +362,7 @@
Chỉ hiện truyện đã tải
Hướng dẫn di chuyển nguồn
Cài đặt tìm kiếm
- Sao lưu đã đang trong quá trình thực hiện
+ Sao lưu đang trong quá trình thực hiện
Bạn có chắc không\? Tất cả lịch sử sẽ bị xoá.
Truyện trong danh mục bị loại trừ sẽ không được cập nhật.
Ngày kết thúc
@@ -528,7 +528,7 @@
Độ nhạy cho phần tự ẩn mục chính khi kéo cuộn
Hướng dẫn sử dụng khởi đầu
Giao diện máy tính bảng
- Hoạt động ngầm
+ Hoạt động nền
Thấp nhất
Thấp
Cao
@@ -635,7 +635,7 @@
Bạn sẽ xóa bỏ \"%s\" này ra khỏi thư viện của bạn
Thư viện lần cuối được cập nhật:%s
Tải Trước
- Tải trước chỉ áp dụng cho các mục ở trong thư viện và nếu chương cuối cùng đã được tải rồi
+ Tải trước chỉ áp dụng cho các mục ở trong thư viện và nếu chương cuối cùng đã được tải rồi.
Đa Ngôn Ngữ
Bỏ qua vì loạt truyện không cần cập nhật
Tìm kiếm…
@@ -709,7 +709,7 @@
Vuốt chương
Thao tác vuốt sang phải
Thao tác vuốt sang trái
- Thông tin Debug
+ Thông tin gỡ lỗi
Không thể tạo tệp sao lưu
Đặt khoảng thời gian
OK
@@ -727,4 +727,70 @@
Mở khoá %s
Cài đặt nguồn
Cài đặt ứng dụng
+ Vị trí kho chứa
+ Tạo
+ Không bao giờ
+ Chọn một thư mục
+ Giảm tình trạng bóng ma trên màn giấy điện tử
+ Hướng dẫn làm quen
+ Được sử dụng để sao lưu tự động, tải chương và nguồn cục bộ.
+ Mới với %s sao? Chúng tôi khuyên bạn nên xem hướng dẫn bắt đầu.
+ Bắt đầu
+ Áp dụng
+ Đặt để cập nhật mỗi
+ Phải chọn một thư mục
+ Quyền thông báo
+ Đoạn thời gian
+ Chỉnh về mặc định
+ Cài đặt quyền ứng dụng
+ Lọc danh mục
+ Xin chào!
+ Thêm tùy chọn
+ Lần cuối cùng tự động lưu: %s
+ Đã sử dụng %s từ trước rồi sao?
+ Tùy chỉnh đoạn thời gian
+ Được chọn
+ Không tìm thấy máy quét nào
+ Chưa chọn
+ Di chuyển bộ truyện xuống cuối
+ Máy quét
+ Bỏ qua
+ Hiện trắng khi đổi trang
+ Được cấp phép - Không có chương nào để hiển thị
+ Tránh gián đoạn quá trình cập nhật thư viện, tải xuống và khôi phục bản sao lưu trong thời gian dài.
+ Mất kết nối mạng
+ Kho chứa chiếm dụng
+ Tùy ý
+ Tiếp
+ Sử dụng pin nền
+ Để cài đặt nguồn mở rộng.
+ Đang cập nhật thư viện… (%s)
+ Chỉ mục tải xuống bị vô hiệu
+ Điều hướng trên
+ Trước tiên hãy thiết lập một số thứ nhé. Bạn có thể tùy ý chỉnh lại những cài đặt này lại sau.
+ Điểm bộ theo dõi
+ Chưa đặt vị trí kho chứa
+ Dữ liệu và kho chứa
+ Bạn có muốn lọc danh mục theo thứ tự bảng chữ cái?
+ Bỏ qua vì dự kiến hôm nay không có bản phát hành nào
+ Gửi thông báo khi thư viện cấp nhật và nhiều hơn thế.
+ Không có tập tin được chọn
+ Xóa bộ theo dõi %s?
+ Đồng thời xóa khỏi %s
+ Bắt buộc
+ Có kết quả
+ Ước tính mỗi
+ Điều này sẽ loại bỏ bộ theo dõi cục bộ.
+ Đăng nhập bộ theo dõi
+ Cho phép
+ Chọn thư mục nơi mà %1$s sẽ chứa chương truyện tải xuống, sao lưu, và những thứ khác.
+\n
+\nKhuyến khích sử dụng một thư mục chuyên dụng.
+\n
+\nThư mục được chọn: %2$s
+ Mốc thời gian liên quan
+ HTTP %d, kiểm tra trang web trong WebView
+ \"%1$s\" thay vì là \"%2$s\"
+ Không thể truy cập %s
+ Loại trừ máy quét
\ No newline at end of file
diff --git a/i18n/src/commonMain/resources/MR/zh-rCN/strings.xml b/i18n/src/commonMain/resources/MR/zh-rCN/strings.xml
index dbd2e0f09..9b522c33b 100644
--- a/i18n/src/commonMain/resources/MR/zh-rCN/strings.xml
+++ b/i18n/src/commonMain/resources/MR/zh-rCN/strings.xml
@@ -762,4 +762,7 @@
扫译者
记录平台评分
排除的扫译者
+ 更多选项
+ 已选择
+ 未选择
\ No newline at end of file
diff --git a/i18n/src/commonMain/resources/MR/zh-rTW/strings.xml b/i18n/src/commonMain/resources/MR/zh-rTW/strings.xml
index 7c3c75e89..f793614c7 100644
--- a/i18n/src/commonMain/resources/MR/zh-rTW/strings.xml
+++ b/i18n/src/commonMain/resources/MR/zh-rTW/strings.xml
@@ -291,9 +291,9 @@
書櫃
過舊
這個擴充套件已無法使用,其可能無法正確運作或導致本程式發生問題。建議解除安裝。
- 關閉
- 遵循系統
- 開啟
+ 淺色
+ 系統
+ 深色
日期格式
將套用至你書櫃中的作品
僅限下載內容
@@ -643,7 +643,7 @@
主題、日期格式
自動下載、預先下載
單向進度同步、增強式同步
- 手動與自動備份,儲存空間
+ 手動與自動備份、儲存空間
上鎖應用程式、防窺畫面
傾印當機記錄、電池效能最佳化
重新啟動應用程式
@@ -750,9 +750,9 @@
來源設定
未選擇檔案
永不
- 減少電子墨水螢幕上的殘影
+ 減少電子紙顯示器上的殘影
最後一次自動備份:%s
- 頁面轉換時閃白
+ 翻頁時閃爍白畫面
資料與儲存空間
儲存空間使用情形
歷程平台評分
@@ -768,4 +768,29 @@
向上瀏覽
儲存位置
供自動備份、章節下載和本機來源使用。
+ 選擇資料夾
+ 新手上路精靈
+ 初探 %s?我們建議你查看入門指南。
+ 開始使用
+ 必須選擇一個資料夾
+ 歡迎!
+ 已是 %s 的既有使用者?
+ 略過
+ 下一步
+ 讓我們先設定一些東西。稍後你隨時可至設定中變更這些選項。
+ 未設定儲存位置
+ 選擇供 %1$s 存放下載的章節、備份檔等內容的資料夾。
+\n
+\n建議使用專屬的資料夾。
+\n
+\n選擇的資料夾:%2$s
+ 通知權限
+ 安裝應用程式權限
+ 避免中斷書櫃更新、章節下載和還原備份等較為費時的作業。
+ 選用
+ 背景耗電量
+ 用以安裝來源擴充套件。
+ 用以傳送書櫃更新等通知。
+ 必要
+ 授予
\ No newline at end of file
diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/screens/InfoScreen.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/screens/InfoScreen.kt
index 46736d51e..e3b65079f 100644
--- a/presentation-core/src/main/java/tachiyomi/presentation/core/screens/InfoScreen.kt
+++ b/presentation-core/src/main/java/tachiyomi/presentation/core/screens/InfoScreen.kt
@@ -13,6 +13,7 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Newspaper
+import androidx.compose.material3.Button
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBarDefaults
@@ -38,6 +39,7 @@ fun InfoScreen(
subtitleText: String,
acceptText: String,
onAcceptClick: () -> Unit,
+ canAccept: Boolean = true,
rejectText: String? = null,
onRejectClick: (() -> Unit)? = null,
content: @Composable ColumnScope.() -> Unit,
@@ -63,8 +65,9 @@ fun InfoScreen(
vertical = MaterialTheme.padding.small,
),
) {
- androidx.compose.material3.Button(
+ Button(
modifier = Modifier.fillMaxWidth(),
+ enabled = canAccept,
onClick = onAcceptClick,
) {
Text(text = acceptText)
diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/util/Modifier.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/util/Modifier.kt
index 795c6e211..411fc9983 100644
--- a/presentation-core/src/main/java/tachiyomi/presentation/core/util/Modifier.kt
+++ b/presentation-core/src/main/java/tachiyomi/presentation/core/util/Modifier.kt
@@ -1,6 +1,5 @@
package tachiyomi.presentation.core.util
-import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.isSystemInDarkTheme
@@ -16,6 +15,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
@@ -28,7 +28,10 @@ import tachiyomi.presentation.core.components.material.SecondaryItemAlpha
fun Modifier.selectedBackground(isSelected: Boolean): Modifier = if (isSelected) {
composed {
val alpha = if (isSystemInDarkTheme()) 0.16f else 0.22f
- Modifier.background(MaterialTheme.colorScheme.secondary.copy(alpha = alpha))
+ val color = MaterialTheme.colorScheme.secondary.copy(alpha = alpha)
+ Modifier.drawBehind {
+ drawRect(color)
+ }
}
} else {
this