Migrate to multiplatform string resources (#10147)
* Migrate to multiplatform string resources * Move plurals translations into separate files * Fix lint check on generated files
This commit is contained in:
@@ -55,7 +55,9 @@ import org.acra.config.httpSender
|
||||
import org.acra.ktx.initAcra
|
||||
import org.acra.sender.HttpSender
|
||||
import org.conscrypt.Conscrypt
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.widget.WidgetManager
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@@ -104,8 +106,8 @@ class App : Application(), DefaultLifecycleObserver, ImageLoaderFactory {
|
||||
Notifications.ID_INCOGNITO_MODE,
|
||||
Notifications.CHANNEL_INCOGNITO_MODE,
|
||||
) {
|
||||
setContentTitle(getString(R.string.pref_incognito_mode))
|
||||
setContentText(getString(R.string.notification_incognito_text))
|
||||
setContentTitle(localize(MR.strings.pref_incognito_mode))
|
||||
setContentText(localize(MR.strings.notification_incognito_text))
|
||||
setSmallIcon(R.drawable.ic_glasses_24dp)
|
||||
setOngoing(true)
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import tachiyomi.core.preference.plusAssign
|
||||
import tachiyomi.domain.backup.service.BackupPreferences
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED
|
||||
import tachiyomi.i18n.MR
|
||||
import java.io.File
|
||||
|
||||
object Migrations {
|
||||
@@ -146,7 +147,7 @@ object Migrations {
|
||||
// v53: switched from WebView to OAuth
|
||||
if (trackerManager.myAnimeList.isLoggedIn) {
|
||||
trackerManager.myAnimeList.logout()
|
||||
context.toast(R.string.myanimelist_relogin)
|
||||
context.toast(MR.strings.myanimelist_relogin)
|
||||
}
|
||||
}
|
||||
if (oldVersion < 57) {
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.Manifest
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_APP_PREFS
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_CATEGORY
|
||||
import eu.kanade.tachiyomi.data.backup.BackupCreateFlags.BACKUP_CHAPTER
|
||||
@@ -38,6 +37,7 @@ import logcat.LogPriority
|
||||
import okio.buffer
|
||||
import okio.gzip
|
||||
import okio.sink
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.preference.Preference
|
||||
import tachiyomi.core.preference.PreferenceStore
|
||||
import tachiyomi.core.util.system.logcat
|
||||
@@ -49,6 +49,7 @@ import tachiyomi.domain.history.interactor.GetHistory
|
||||
import tachiyomi.domain.manga.interactor.GetFavorites
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.FileOutputStream
|
||||
@@ -75,7 +76,7 @@ class BackupCreator(
|
||||
*/
|
||||
suspend fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String {
|
||||
if (!context.hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
|
||||
throw IllegalStateException(context.getString(R.string.missing_storage_permission))
|
||||
throw IllegalStateException(context.localize(MR.strings.missing_storage_permission))
|
||||
}
|
||||
|
||||
val databaseManga = getFavorites.await()
|
||||
@@ -110,7 +111,7 @@ class BackupCreator(
|
||||
UniFile.fromUri(context, uri)
|
||||
}
|
||||
)
|
||||
?: throw Exception(context.getString(R.string.create_backup_file_error))
|
||||
?: throw Exception(context.localize(MR.strings.create_backup_file_error))
|
||||
|
||||
if (!file.isFile) {
|
||||
throw IllegalStateException("Failed to get handle on a backup file")
|
||||
@@ -118,7 +119,7 @@ class BackupCreator(
|
||||
|
||||
val byteArray = parser.encodeToByteArray(BackupSerializer, backup)
|
||||
if (byteArray.isEmpty()) {
|
||||
throw IllegalStateException(context.getString(R.string.empty_backup_error))
|
||||
throw IllegalStateException(context.localize(MR.strings.empty_backup_error))
|
||||
}
|
||||
|
||||
file.openOutputStream().also {
|
||||
|
||||
@@ -2,10 +2,11 @@ package eu.kanade.tachiyomi.data.backup
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.track.TrackerManager
|
||||
import eu.kanade.tachiyomi.util.BackupUtil
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@@ -28,7 +29,7 @@ class BackupFileValidator(
|
||||
}
|
||||
|
||||
if (backup.backupManga.isEmpty()) {
|
||||
throw IllegalStateException(context.getString(R.string.invalid_backup_file_missing_manga))
|
||||
throw IllegalStateException(context.localize(MR.strings.invalid_backup_file_missing_manga))
|
||||
}
|
||||
|
||||
val sources = backup.backupSources.associate { it.sourceId to it.name }
|
||||
|
||||
@@ -12,6 +12,9 @@ import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import eu.kanade.tachiyomi.util.system.cancelNotification
|
||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||
import eu.kanade.tachiyomi.util.system.notify
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.i18n.localizePlural
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import java.util.concurrent.TimeUnit
|
||||
@@ -44,7 +47,7 @@ class BackupNotifier(private val context: Context) {
|
||||
|
||||
fun showBackupProgress(): NotificationCompat.Builder {
|
||||
val builder = with(progressNotificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.creating_backup))
|
||||
setContentTitle(context.localize(MR.strings.creating_backup))
|
||||
|
||||
setProgress(0, 0, true)
|
||||
}
|
||||
@@ -58,7 +61,7 @@ class BackupNotifier(private val context: Context) {
|
||||
context.cancelNotification(Notifications.ID_BACKUP_PROGRESS)
|
||||
|
||||
with(completeNotificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.creating_backup_error))
|
||||
setContentTitle(context.localize(MR.strings.creating_backup_error))
|
||||
setContentText(error)
|
||||
|
||||
show(Notifications.ID_BACKUP_COMPLETE)
|
||||
@@ -69,13 +72,13 @@ class BackupNotifier(private val context: Context) {
|
||||
context.cancelNotification(Notifications.ID_BACKUP_PROGRESS)
|
||||
|
||||
with(completeNotificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.backup_created))
|
||||
setContentTitle(context.localize(MR.strings.backup_created))
|
||||
setContentText(unifile.filePath ?: unifile.name)
|
||||
|
||||
clearActions()
|
||||
addAction(
|
||||
R.drawable.ic_share_24dp,
|
||||
context.getString(R.string.action_share),
|
||||
context.localize(MR.strings.action_share),
|
||||
NotificationReceiver.shareBackupPendingBroadcast(
|
||||
context,
|
||||
unifile.uri,
|
||||
@@ -89,8 +92,8 @@ class BackupNotifier(private val context: Context) {
|
||||
|
||||
fun showRestoreProgress(
|
||||
content: String = "",
|
||||
contentTitle: String = context.getString(
|
||||
R.string.restoring_backup,
|
||||
contentTitle: String = context.localize(
|
||||
MR.strings.restoring_backup,
|
||||
),
|
||||
progress: Int = 0,
|
||||
maxAmount: Int = 100,
|
||||
@@ -108,7 +111,7 @@ class BackupNotifier(private val context: Context) {
|
||||
clearActions()
|
||||
addAction(
|
||||
R.drawable.ic_close_24dp,
|
||||
context.getString(R.string.action_cancel),
|
||||
context.localize(MR.strings.action_cancel),
|
||||
NotificationReceiver.cancelRestorePendingBroadcast(context, Notifications.ID_RESTORE_PROGRESS),
|
||||
)
|
||||
}
|
||||
@@ -122,7 +125,7 @@ class BackupNotifier(private val context: Context) {
|
||||
context.cancelNotification(Notifications.ID_RESTORE_PROGRESS)
|
||||
|
||||
with(completeNotificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.restoring_backup_error))
|
||||
setContentTitle(context.localize(MR.strings.restoring_backup_error))
|
||||
setContentText(error)
|
||||
|
||||
show(Notifications.ID_RESTORE_COMPLETE)
|
||||
@@ -134,14 +137,14 @@ class BackupNotifier(private val context: Context) {
|
||||
errorCount: Int,
|
||||
path: String?,
|
||||
file: String?,
|
||||
contentTitle: String = context.getString(
|
||||
R.string.restore_completed,
|
||||
contentTitle: String = context.localize(
|
||||
MR.strings.restore_completed,
|
||||
),
|
||||
) {
|
||||
context.cancelNotification(Notifications.ID_RESTORE_PROGRESS)
|
||||
|
||||
val timeString = context.getString(
|
||||
R.string.restore_duration,
|
||||
val timeString = context.localize(
|
||||
MR.strings.restore_duration,
|
||||
TimeUnit.MILLISECONDS.toMinutes(time),
|
||||
TimeUnit.MILLISECONDS.toSeconds(time) - TimeUnit.MINUTES.toSeconds(
|
||||
TimeUnit.MILLISECONDS.toMinutes(time),
|
||||
@@ -151,8 +154,8 @@ class BackupNotifier(private val context: Context) {
|
||||
with(completeNotificationBuilder) {
|
||||
setContentTitle(contentTitle)
|
||||
setContentText(
|
||||
context.resources.getQuantityString(
|
||||
R.plurals.restore_completed_message,
|
||||
context.localizePlural(
|
||||
MR.plurals.restore_completed_message,
|
||||
errorCount,
|
||||
timeString,
|
||||
errorCount,
|
||||
@@ -168,7 +171,7 @@ class BackupNotifier(private val context: Context) {
|
||||
setContentIntent(errorLogIntent)
|
||||
addAction(
|
||||
R.drawable.ic_folder_24dp,
|
||||
context.getString(R.string.action_show_errors),
|
||||
context.localize(MR.strings.action_show_errors),
|
||||
errorLogIntent,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,14 +9,15 @@ import androidx.work.ForegroundInfo
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.util.system.cancelNotification
|
||||
import eu.kanade.tachiyomi.util.system.isRunning
|
||||
import eu.kanade.tachiyomi.util.system.workManager
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
class BackupRestoreJob(private val context: Context, workerParams: WorkerParameters) :
|
||||
CoroutineWorker(context, workerParams) {
|
||||
@@ -40,7 +41,7 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet
|
||||
Result.success()
|
||||
} catch (e: Exception) {
|
||||
if (e is CancellationException) {
|
||||
notifier.showRestoreError(context.getString(R.string.restoring_backup_canceled))
|
||||
notifier.showRestoreError(context.localize(MR.strings.restoring_backup_canceled))
|
||||
Result.success()
|
||||
} else {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
|
||||
@@ -3,7 +3,6 @@ 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.R
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupHistory
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
||||
@@ -23,6 +22,7 @@ import eu.kanade.tachiyomi.util.BackupUtil
|
||||
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.isActive
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.preference.AndroidPreferenceStore
|
||||
import tachiyomi.core.preference.PreferenceStore
|
||||
import tachiyomi.data.DatabaseHandler
|
||||
@@ -37,6 +37,7 @@ import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.domain.manga.interactor.FetchInterval
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
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
|
||||
@@ -93,7 +94,7 @@ class BackupRestorer(
|
||||
errors.size,
|
||||
logFile.parent,
|
||||
logFile.name,
|
||||
contentTitle = context.getString(R.string.library_sync_complete),
|
||||
contentTitle = context.localize(MR.strings.library_sync_complete),
|
||||
)
|
||||
} else {
|
||||
notifier.showRestoreComplete(time, errors.size, logFile.parent, logFile.name)
|
||||
@@ -192,8 +193,8 @@ class BackupRestorer(
|
||||
showRestoreProgress(
|
||||
restoreProgress,
|
||||
restoreAmount,
|
||||
context.getString(R.string.categories),
|
||||
context.getString(R.string.restoring_backup),
|
||||
context.localize(MR.strings.categories),
|
||||
context.localize(MR.strings.restoring_backup),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -229,14 +230,14 @@ class BackupRestorer(
|
||||
restoreProgress,
|
||||
restoreAmount,
|
||||
manga.title,
|
||||
context.getString(R.string.syncing_library),
|
||||
context.localize(MR.strings.syncing_library),
|
||||
)
|
||||
} else {
|
||||
showRestoreProgress(
|
||||
restoreProgress,
|
||||
restoreAmount,
|
||||
manga.title,
|
||||
context.getString(R.string.restoring_backup),
|
||||
context.localize(MR.strings.restoring_backup),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -633,8 +634,8 @@ class BackupRestorer(
|
||||
showRestoreProgress(
|
||||
restoreProgress,
|
||||
restoreAmount,
|
||||
context.getString(R.string.app_settings),
|
||||
context.getString(R.string.restoring_backup),
|
||||
context.localize(MR.strings.app_settings),
|
||||
context.localize(MR.strings.restoring_backup),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -648,8 +649,8 @@ class BackupRestorer(
|
||||
showRestoreProgress(
|
||||
restoreProgress,
|
||||
restoreAmount,
|
||||
context.getString(R.string.source_settings),
|
||||
context.getString(R.string.restoring_backup),
|
||||
context.localize(MR.strings.source_settings),
|
||||
context.localize(MR.strings.restoring_backup),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package eu.kanade.tachiyomi.data.download
|
||||
|
||||
import android.content.Context
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
@@ -15,6 +14,7 @@ import kotlinx.coroutines.flow.merge
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.category.interactor.GetCategories
|
||||
@@ -22,6 +22,7 @@ import tachiyomi.domain.chapter.model.Chapter
|
||||
import tachiyomi.domain.download.service.DownloadPreferences
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@@ -158,7 +159,7 @@ class DownloadManager(
|
||||
.filter { "image" in it.type.orEmpty() }
|
||||
|
||||
if (files.isEmpty()) {
|
||||
throw Exception(context.getString(R.string.page_list_empty_error))
|
||||
throw Exception(context.localize(MR.strings.page_list_empty_error))
|
||||
}
|
||||
|
||||
return files.sortedBy { it.name }
|
||||
|
||||
@@ -14,6 +14,8 @@ import eu.kanade.tachiyomi.util.lang.chop
|
||||
import eu.kanade.tachiyomi.util.system.cancelNotification
|
||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||
import eu.kanade.tachiyomi.util.system.notify
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.regex.Pattern
|
||||
|
||||
@@ -78,13 +80,13 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
// Pause action
|
||||
addAction(
|
||||
R.drawable.ic_pause_24dp,
|
||||
context.getString(R.string.action_pause),
|
||||
context.localize(MR.strings.action_pause),
|
||||
NotificationReceiver.pauseDownloadsPendingBroadcast(context),
|
||||
)
|
||||
}
|
||||
|
||||
val downloadingProgressText = context.getString(
|
||||
R.string.chapter_downloading_progress,
|
||||
val downloadingProgressText = context.localize(
|
||||
MR.strings.chapter_downloading_progress,
|
||||
download.downloadedImages,
|
||||
download.pages!!.size,
|
||||
)
|
||||
@@ -115,8 +117,8 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
*/
|
||||
fun onPaused() {
|
||||
with(progressNotificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.chapter_paused))
|
||||
setContentText(context.getString(R.string.download_notifier_download_paused))
|
||||
setContentTitle(context.localize(MR.strings.chapter_paused))
|
||||
setContentText(context.localize(MR.strings.download_notifier_download_paused))
|
||||
setSmallIcon(R.drawable.ic_pause_24dp)
|
||||
setProgress(0, 0, false)
|
||||
setOngoing(false)
|
||||
@@ -126,13 +128,13 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
// Resume action
|
||||
addAction(
|
||||
R.drawable.ic_play_arrow_24dp,
|
||||
context.getString(R.string.action_resume),
|
||||
context.localize(MR.strings.action_resume),
|
||||
NotificationReceiver.resumeDownloadsPendingBroadcast(context),
|
||||
)
|
||||
// Clear action
|
||||
addAction(
|
||||
R.drawable.ic_close_24dp,
|
||||
context.getString(R.string.action_cancel_all),
|
||||
context.localize(MR.strings.action_cancel_all),
|
||||
NotificationReceiver.clearDownloadsPendingBroadcast(context),
|
||||
)
|
||||
|
||||
@@ -162,7 +164,7 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
*/
|
||||
fun onWarning(reason: String, timeout: Long? = null, contentIntent: PendingIntent? = null) {
|
||||
with(errorNotificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.download_notifier_downloader_title))
|
||||
setContentTitle(context.localize(MR.strings.download_notifier_downloader_title))
|
||||
setStyle(NotificationCompat.BigTextStyle().bigText(reason))
|
||||
setSmallIcon(R.drawable.ic_warning_white_24dp)
|
||||
setAutoCancel(true)
|
||||
@@ -190,9 +192,9 @@ internal class DownloadNotifier(private val context: Context) {
|
||||
// Create notification
|
||||
with(errorNotificationBuilder) {
|
||||
setContentTitle(
|
||||
mangaTitle?.plus(": $chapter") ?: context.getString(R.string.download_notifier_downloader_title),
|
||||
mangaTitle?.plus(": $chapter") ?: context.localize(MR.strings.download_notifier_downloader_title),
|
||||
)
|
||||
setContentText(error ?: context.getString(R.string.download_notifier_unknown_error))
|
||||
setContentText(error ?: context.localize(MR.strings.download_notifier_unknown_error))
|
||||
setSmallIcon(R.drawable.ic_warning_white_24dp)
|
||||
clearActions()
|
||||
setContentIntent(NotificationHandler.openDownloadManagerPendingActivity(context))
|
||||
|
||||
@@ -3,17 +3,18 @@ package eu.kanade.tachiyomi.data.download
|
||||
import android.content.Context
|
||||
import androidx.core.net.toUri
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.chapter.model.Chapter
|
||||
import tachiyomi.domain.download.service.DownloadPreferences
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@@ -58,7 +59,7 @@ class DownloadProvider(
|
||||
.createDirectory(getMangaDirName(mangaTitle))
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e) { "Invalid download directory" }
|
||||
throw Exception(context.getString(R.string.invalid_location, downloadsDir))
|
||||
throw Exception(context.localize(MR.strings.invalid_location, downloadsDir))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,8 @@ import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import eu.kanade.tachiyomi.R
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.util.system.acquireWakeLock
|
||||
import eu.kanade.tachiyomi.util.system.isConnectedToWifi
|
||||
@@ -27,9 +26,11 @@ import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import logcat.LogPriority
|
||||
import ru.beryukhov.reactivenetwork.ReactiveNetwork
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.lang.withUIContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.download.service.DownloadPreferences
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
/**
|
||||
@@ -111,8 +112,8 @@ class DownloadService : Service() {
|
||||
return null
|
||||
}
|
||||
|
||||
private fun downloaderStop(@StringRes string: Int) {
|
||||
downloadManager.downloaderStop(getString(string))
|
||||
private fun downloaderStop(string: StringResource) {
|
||||
downloadManager.downloaderStop(localize(string))
|
||||
}
|
||||
|
||||
private fun listenNetworkChanges() {
|
||||
@@ -122,20 +123,20 @@ class DownloadService : Service() {
|
||||
withUIContext {
|
||||
if (isOnline()) {
|
||||
if (downloadPreferences.downloadOnlyOverWifi().get() && !isConnectedToWifi()) {
|
||||
downloaderStop(R.string.download_notifier_text_only_wifi)
|
||||
downloaderStop(MR.strings.download_notifier_text_only_wifi)
|
||||
} else {
|
||||
val started = downloadManager.downloaderStart()
|
||||
if (!started) stopSelf()
|
||||
}
|
||||
} else {
|
||||
downloaderStop(R.string.download_notifier_no_network)
|
||||
downloaderStop(MR.strings.download_notifier_no_network)
|
||||
}
|
||||
}
|
||||
}
|
||||
.catch { error ->
|
||||
withUIContext {
|
||||
logcat(LogPriority.ERROR, error)
|
||||
toast(R.string.download_queue_error)
|
||||
toast(MR.strings.download_queue_error)
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
@@ -144,7 +145,7 @@ class DownloadService : Service() {
|
||||
|
||||
private fun getPlaceholderNotification(): Notification {
|
||||
return notificationBuilder(Notifications.CHANNEL_DOWNLOADER_PROGRESS) {
|
||||
setContentTitle(getString(R.string.download_notifier_downloader_title))
|
||||
setContentTitle(localize(MR.strings.download_notifier_downloader_title))
|
||||
}.build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.content.Context
|
||||
import com.hippo.unifile.UniFile
|
||||
import eu.kanade.domain.chapter.model.toSChapter
|
||||
import eu.kanade.domain.manga.model.getComicInfo
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateNotifier
|
||||
@@ -41,6 +40,7 @@ import kotlinx.coroutines.supervisorScope
|
||||
import logcat.LogPriority
|
||||
import nl.adaptivity.xmlutil.serialization.XML
|
||||
import okhttp3.Response
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.metadata.comicinfo.COMIC_INFO_FILE
|
||||
import tachiyomi.core.metadata.comicinfo.ComicInfo
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
@@ -54,6 +54,7 @@ import tachiyomi.domain.chapter.model.Chapter
|
||||
import tachiyomi.domain.download.service.DownloadPreferences
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.BufferedOutputStream
|
||||
@@ -302,7 +303,7 @@ class Downloader(
|
||||
) {
|
||||
withUIContext {
|
||||
notifier.onWarning(
|
||||
context.getString(R.string.download_queue_size_warning),
|
||||
context.localize(MR.strings.download_queue_size_warning),
|
||||
WARNING_NOTIF_TIMEOUT_MS,
|
||||
NotificationHandler.openUrl(context, LibraryUpdateNotifier.HELP_WARNING_URL),
|
||||
)
|
||||
@@ -325,7 +326,7 @@ class Downloader(
|
||||
if (availSpace != -1L && availSpace < MIN_DISK_SPACE) {
|
||||
download.status = Download.State.ERROR
|
||||
notifier.onError(
|
||||
context.getString(R.string.download_insufficient_space),
|
||||
context.localize(MR.strings.download_insufficient_space),
|
||||
download.chapter.name,
|
||||
download.manga.title,
|
||||
)
|
||||
@@ -342,7 +343,7 @@ class Downloader(
|
||||
val pages = download.source.getPageList(download.chapter.toSChapter())
|
||||
|
||||
if (pages.isEmpty()) {
|
||||
throw Exception(context.getString(R.string.page_list_empty_error))
|
||||
throw Exception(context.localize(MR.strings.page_list_empty_error))
|
||||
}
|
||||
// Don't trust index from source
|
||||
val reIndexedPages = pages.mapIndexed { index, page -> Page(index, page.url, page.imageUrl, page.uri) }
|
||||
@@ -546,7 +547,7 @@ class Downloader(
|
||||
try {
|
||||
val filenamePrefix = String.format("%03d", page.number)
|
||||
val imageFile = tmpDir.listFiles()?.firstOrNull { it.name.orEmpty().startsWith(filenamePrefix) }
|
||||
?: error(context.getString(R.string.download_notifier_split_page_not_found, page.number))
|
||||
?: error(context.localize(MR.strings.download_notifier_split_page_not_found, page.number))
|
||||
|
||||
// If the original page was previously split, then skip
|
||||
if (imageFile.name.orEmpty().startsWith("${filenamePrefix}__")) return
|
||||
|
||||
@@ -16,16 +16,13 @@ import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.copyFrom
|
||||
import eu.kanade.domain.manga.model.toSManga
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.source.UnmeteredSource
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
||||
import eu.kanade.tachiyomi.util.prepUpdateCover
|
||||
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
|
||||
@@ -41,6 +38,7 @@ import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.preference.getAndSet
|
||||
import tachiyomi.core.util.lang.withIOContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
@@ -62,9 +60,9 @@ import tachiyomi.domain.manga.interactor.FetchInterval
|
||||
import tachiyomi.domain.manga.interactor.GetLibraryManga
|
||||
import tachiyomi.domain.manga.interactor.GetManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.toMangaUpdate
|
||||
import tachiyomi.domain.source.model.SourceNotInstalledException
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
@@ -114,22 +112,14 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
logcat(LogPriority.ERROR, e) { "Not allowed to set foreground job" }
|
||||
}
|
||||
|
||||
val target = inputData.getString(KEY_TARGET)?.let { Target.valueOf(it) } ?: Target.CHAPTERS
|
||||
|
||||
// If this is a chapter update, set the last update time to now
|
||||
if (target == Target.CHAPTERS) {
|
||||
libraryPreferences.lastUpdatedTimestamp().set(Date().time)
|
||||
}
|
||||
libraryPreferences.lastUpdatedTimestamp().set(Date().time)
|
||||
|
||||
val categoryId = inputData.getLong(KEY_CATEGORY, -1L)
|
||||
addMangaToQueue(categoryId)
|
||||
|
||||
return withIOContext {
|
||||
try {
|
||||
when (target) {
|
||||
Target.CHAPTERS -> updateChapterList()
|
||||
Target.COVERS -> updateCovers()
|
||||
}
|
||||
updateChapterList()
|
||||
Result.success()
|
||||
} catch (e: Exception) {
|
||||
if (e is CancellationException) {
|
||||
@@ -191,29 +181,32 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
.filter {
|
||||
when {
|
||||
it.manga.updateStrategy != UpdateStrategy.ALWAYS_UPDATE -> {
|
||||
skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_always_update))
|
||||
skippedUpdates.add(it.manga to context.localize(MR.strings.skipped_reason_not_always_update))
|
||||
false
|
||||
}
|
||||
|
||||
MANGA_NON_COMPLETED in restrictions && it.manga.status.toInt() == SManga.COMPLETED -> {
|
||||
skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_completed))
|
||||
skippedUpdates.add(it.manga to context.localize(MR.strings.skipped_reason_completed))
|
||||
false
|
||||
}
|
||||
|
||||
MANGA_HAS_UNREAD in restrictions && it.unreadCount != 0L -> {
|
||||
skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_caught_up))
|
||||
skippedUpdates.add(it.manga to context.localize(MR.strings.skipped_reason_not_caught_up))
|
||||
false
|
||||
}
|
||||
|
||||
MANGA_NON_READ in restrictions && it.totalChapters > 0L && !it.hasStarted -> {
|
||||
skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_started))
|
||||
skippedUpdates.add(it.manga to context.localize(MR.strings.skipped_reason_not_started))
|
||||
false
|
||||
}
|
||||
|
||||
MANGA_OUTSIDE_RELEASE_PERIOD in restrictions && it.manga.nextUpdate > fetchWindow.second -> {
|
||||
skippedUpdates.add(it.manga to context.getString(R.string.skipped_reason_not_in_release_period))
|
||||
skippedUpdates.add(
|
||||
it.manga to context.localize(MR.strings.skipped_reason_not_in_release_period),
|
||||
)
|
||||
false
|
||||
}
|
||||
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
@@ -294,10 +287,10 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
val errorMessage = when (e) {
|
||||
is NoChaptersException -> context.getString(R.string.no_chapters_error)
|
||||
is NoChaptersException -> context.localize(MR.strings.no_chapters_error)
|
||||
// failedUpdates will already have the source, don't need to copy it into the message
|
||||
is SourceNotInstalledException -> context.getString(
|
||||
R.string.loader_not_implemented_error,
|
||||
is SourceNotInstalledException -> context.localize(
|
||||
MR.strings.loader_not_implemented_error,
|
||||
)
|
||||
else -> e.message
|
||||
}
|
||||
@@ -359,51 +352,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
return syncChaptersWithSource.await(chapters, dbManga, source, false, fetchWindow)
|
||||
}
|
||||
|
||||
private suspend fun updateCovers() {
|
||||
val semaphore = Semaphore(5)
|
||||
val progressCount = AtomicInteger(0)
|
||||
val currentlyUpdatingManga = CopyOnWriteArrayList<Manga>()
|
||||
|
||||
coroutineScope {
|
||||
mangaToUpdate.groupBy { it.manga.source }
|
||||
.values
|
||||
.map { mangaInSource ->
|
||||
async {
|
||||
semaphore.withPermit {
|
||||
mangaInSource.forEach { libraryManga ->
|
||||
val manga = libraryManga.manga
|
||||
ensureActive()
|
||||
|
||||
withUpdateNotification(
|
||||
currentlyUpdatingManga,
|
||||
progressCount,
|
||||
manga,
|
||||
) {
|
||||
val source = sourceManager.get(manga.source) ?: return@withUpdateNotification
|
||||
try {
|
||||
val networkManga = source.getMangaDetails(manga.toSManga())
|
||||
val updatedManga = manga.prepUpdateCover(coverCache, networkManga, true)
|
||||
.copyFrom(networkManga)
|
||||
try {
|
||||
updateManga.await(updatedManga.toMangaUpdate())
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR) { "Manga doesn't exist anymore" }
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
// Ignore errors and continue
|
||||
logcat(LogPriority.ERROR, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
}
|
||||
|
||||
notifier.cancelProgressNotification()
|
||||
}
|
||||
|
||||
private suspend fun withUpdateNotification(
|
||||
updatingManga: CopyOnWriteArrayList<Manga>,
|
||||
completed: AtomicInteger,
|
||||
@@ -440,7 +388,7 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
if (errors.isNotEmpty()) {
|
||||
val file = context.createFileInCacheDir("tachiyomi_update_errors.txt")
|
||||
file.bufferedWriter().use { out ->
|
||||
out.write(context.getString(R.string.library_errors_help, ERROR_LOG_HELP_URL) + "\n\n")
|
||||
out.write(context.localize(MR.strings.library_errors_help, ERROR_LOG_HELP_URL) + "\n\n")
|
||||
// Error file format:
|
||||
// ! Error
|
||||
// # Source
|
||||
@@ -462,14 +410,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
return File("")
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines what should be updated within a service execution.
|
||||
*/
|
||||
enum class Target {
|
||||
CHAPTERS, // Manga chapters
|
||||
COVERS, // Manga covers
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "LibraryUpdate"
|
||||
private const val WORK_NAME_AUTO = "LibraryUpdate-auto"
|
||||
@@ -484,11 +424,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
*/
|
||||
private const val KEY_CATEGORY = "category"
|
||||
|
||||
/**
|
||||
* Key that defines what should be updated.
|
||||
*/
|
||||
private const val KEY_TARGET = "target"
|
||||
|
||||
fun cancelAllWorks(context: Context) {
|
||||
context.workManager.cancelAllWorkByTag(TAG)
|
||||
}
|
||||
@@ -534,7 +469,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
fun startNow(
|
||||
context: Context,
|
||||
category: Category? = null,
|
||||
target: Target = Target.CHAPTERS,
|
||||
): Boolean {
|
||||
val wm = context.workManager
|
||||
if (wm.isRunning(TAG)) {
|
||||
@@ -544,7 +478,6 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
||||
|
||||
val inputData = workDataOf(
|
||||
KEY_CATEGORY to category?.id,
|
||||
KEY_TARGET to target.name,
|
||||
)
|
||||
val request = OneTimeWorkRequestBuilder<LibraryUpdateJob>()
|
||||
.addTag(TAG)
|
||||
|
||||
@@ -26,9 +26,12 @@ import eu.kanade.tachiyomi.util.system.getBitmapOrNull
|
||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||
import eu.kanade.tachiyomi.util.system.notify
|
||||
import tachiyomi.core.Constants
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.i18n.localizePlural
|
||||
import tachiyomi.core.util.lang.launchUI
|
||||
import tachiyomi.domain.chapter.model.Chapter
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.NumberFormat
|
||||
|
||||
@@ -58,12 +61,12 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
*/
|
||||
val progressNotificationBuilder by lazy {
|
||||
context.notificationBuilder(Notifications.CHANNEL_LIBRARY_PROGRESS) {
|
||||
setContentTitle(context.getString(R.string.app_name))
|
||||
setContentTitle(context.localize(MR.strings.app_name))
|
||||
setSmallIcon(R.drawable.ic_refresh_24dp)
|
||||
setLargeIcon(notificationBitmap)
|
||||
setOngoing(true)
|
||||
setOnlyAlertOnce(true)
|
||||
addAction(R.drawable.ic_close_24dp, context.getString(R.string.action_cancel), cancelIntent)
|
||||
addAction(R.drawable.ic_close_24dp, context.localize(MR.strings.action_cancel), cancelIntent)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,14 +80,14 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
fun showProgressNotification(manga: List<Manga>, current: Int, total: Int) {
|
||||
if (preferences.hideNotificationContent().get()) {
|
||||
progressNotificationBuilder
|
||||
.setContentTitle(context.getString(R.string.notification_check_updates))
|
||||
.setContentTitle(context.localize(MR.strings.notification_check_updates))
|
||||
.setContentText("($current/$total)")
|
||||
} else {
|
||||
val updatingText = manga.joinToString("\n") { it.title.chop(40) }
|
||||
progressNotificationBuilder
|
||||
.setContentTitle(
|
||||
context.getString(
|
||||
R.string.notification_updating_progress,
|
||||
context.localize(
|
||||
MR.strings.notification_updating_progress,
|
||||
percentFormatter.format(current.toFloat() / total),
|
||||
),
|
||||
)
|
||||
@@ -104,8 +107,8 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
Notifications.ID_LIBRARY_SIZE_WARNING,
|
||||
Notifications.CHANNEL_LIBRARY_PROGRESS,
|
||||
) {
|
||||
setContentTitle(context.getString(R.string.label_warning))
|
||||
setStyle(NotificationCompat.BigTextStyle().bigText(context.getString(R.string.notification_size_warning)))
|
||||
setContentTitle(context.localize(MR.strings.label_warning))
|
||||
setStyle(NotificationCompat.BigTextStyle().bigText(context.localize(MR.strings.notification_size_warning)))
|
||||
setSmallIcon(R.drawable.ic_warning_white_24dp)
|
||||
setTimeoutAfter(Downloader.WARNING_NOTIF_TIMEOUT_MS)
|
||||
setContentIntent(NotificationHandler.openUrl(context, HELP_WARNING_URL))
|
||||
@@ -127,8 +130,8 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
Notifications.ID_LIBRARY_ERROR,
|
||||
Notifications.CHANNEL_LIBRARY_ERROR,
|
||||
) {
|
||||
setContentTitle(context.resources.getString(R.string.notification_update_error, failed))
|
||||
setContentText(context.getString(R.string.action_show_errors))
|
||||
setContentTitle(context.localize(MR.strings.notification_update_error, failed))
|
||||
setContentText(context.localize(MR.strings.action_show_errors))
|
||||
setSmallIcon(R.drawable.ic_tachi)
|
||||
|
||||
setContentIntent(NotificationReceiver.openErrorLogPendingActivity(context, uri))
|
||||
@@ -149,8 +152,8 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
Notifications.ID_LIBRARY_SKIPPED,
|
||||
Notifications.CHANNEL_LIBRARY_SKIPPED,
|
||||
) {
|
||||
setContentTitle(context.resources.getString(R.string.notification_update_skipped, skipped))
|
||||
setContentText(context.getString(R.string.learn_more))
|
||||
setContentTitle(context.localize(MR.strings.notification_update_skipped, skipped))
|
||||
setContentText(context.localize(MR.strings.learn_more))
|
||||
setSmallIcon(R.drawable.ic_tachi)
|
||||
setContentIntent(NotificationHandler.openUrl(context, HELP_SKIPPED_URL))
|
||||
}
|
||||
@@ -167,13 +170,13 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
Notifications.ID_NEW_CHAPTERS,
|
||||
Notifications.CHANNEL_NEW_CHAPTERS,
|
||||
) {
|
||||
setContentTitle(context.getString(R.string.notification_new_chapters))
|
||||
setContentTitle(context.localize(MR.strings.notification_new_chapters))
|
||||
if (updates.size == 1 && !preferences.hideNotificationContent().get()) {
|
||||
setContentText(updates.first().first.title.chop(NOTIF_TITLE_MAX_LEN))
|
||||
} else {
|
||||
setContentText(
|
||||
context.resources.getQuantityString(
|
||||
R.plurals.notification_new_chapters_summary,
|
||||
context.localizePlural(
|
||||
MR.plurals.notification_new_chapters_summary,
|
||||
updates.size,
|
||||
updates.size,
|
||||
),
|
||||
@@ -243,7 +246,7 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
// Mark chapters as read action
|
||||
addAction(
|
||||
R.drawable.ic_glasses_24dp,
|
||||
context.getString(R.string.action_mark_as_read),
|
||||
context.localize(MR.strings.action_mark_as_read),
|
||||
NotificationReceiver.markAsReadPendingBroadcast(
|
||||
context,
|
||||
manga,
|
||||
@@ -254,7 +257,7 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
// View chapters action
|
||||
addAction(
|
||||
R.drawable.ic_book_24dp,
|
||||
context.getString(R.string.action_view_chapters),
|
||||
context.localize(MR.strings.action_view_chapters),
|
||||
NotificationReceiver.openChapterPendingActivity(
|
||||
context,
|
||||
manga,
|
||||
@@ -266,7 +269,7 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
if (chapters.size <= Downloader.CHAPTERS_PER_SOURCE_QUEUE_WARNING_THRESHOLD) {
|
||||
addAction(
|
||||
android.R.drawable.stat_sys_download_done,
|
||||
context.getString(R.string.action_download),
|
||||
context.localize(MR.strings.action_download),
|
||||
NotificationReceiver.downloadChaptersPendingBroadcast(
|
||||
context,
|
||||
manga,
|
||||
@@ -306,8 +309,8 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
// No sensible chapter numbers to show (i.e. no chapters have parsed chapter number)
|
||||
0 -> {
|
||||
// "1 new chapter" or "5 new chapters"
|
||||
context.resources.getQuantityString(
|
||||
R.plurals.notification_chapters_generic,
|
||||
context.localizePlural(
|
||||
MR.plurals.notification_chapters_generic,
|
||||
chapters.size,
|
||||
chapters.size,
|
||||
)
|
||||
@@ -317,14 +320,14 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
val remaining = chapters.size - displayableChapterNumbers.size
|
||||
if (remaining == 0) {
|
||||
// "Chapter 2.5"
|
||||
context.resources.getString(
|
||||
R.string.notification_chapters_single,
|
||||
context.localize(
|
||||
MR.strings.notification_chapters_single,
|
||||
displayableChapterNumbers.first(),
|
||||
)
|
||||
} else {
|
||||
// "Chapter 2.5 and 10 more"
|
||||
context.resources.getString(
|
||||
R.string.notification_chapters_single_and_more,
|
||||
context.localize(
|
||||
MR.strings.notification_chapters_single_and_more,
|
||||
displayableChapterNumbers.first(),
|
||||
remaining,
|
||||
)
|
||||
@@ -339,16 +342,16 @@ class LibraryUpdateNotifier(private val context: Context) {
|
||||
val joinedChapterNumbers = displayableChapterNumbers
|
||||
.take(NOTIF_MAX_CHAPTERS)
|
||||
.joinToString(", ")
|
||||
context.resources.getQuantityString(
|
||||
R.plurals.notification_chapters_multiple_and_more,
|
||||
context.localizePlural(
|
||||
MR.plurals.notification_chapters_multiple_and_more,
|
||||
remaining,
|
||||
joinedChapterNumbers,
|
||||
remaining,
|
||||
)
|
||||
} else {
|
||||
// "Chapters 1, 2.5, 3"
|
||||
context.resources.getString(
|
||||
R.string.notification_chapters_multiple,
|
||||
context.localize(
|
||||
MR.strings.notification_chapters_multiple,
|
||||
displayableChapterNumbers.joinToString(", "),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
package eu.kanade.tachiyomi.data.library
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkInfo
|
||||
import androidx.work.WorkQuery
|
||||
import androidx.work.WorkerParameters
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.copyFrom
|
||||
import eu.kanade.domain.manga.model.toSManga
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.source.UnmeteredSource
|
||||
import eu.kanade.tachiyomi.util.prepUpdateCover
|
||||
import eu.kanade.tachiyomi.util.system.isRunning
|
||||
import eu.kanade.tachiyomi.util.system.workManager
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.util.lang.withIOContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.library.model.LibraryManga
|
||||
import tachiyomi.domain.manga.interactor.GetLibraryManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.manga.model.toMangaUpdate
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
class MetadataUpdateJob(private val context: Context, workerParams: WorkerParameters) :
|
||||
CoroutineWorker(context, workerParams) {
|
||||
|
||||
private val sourceManager: SourceManager = Injekt.get()
|
||||
private val coverCache: CoverCache = Injekt.get()
|
||||
private val getLibraryManga: GetLibraryManga = Injekt.get()
|
||||
private val updateManga: UpdateManga = Injekt.get()
|
||||
|
||||
private val notifier = LibraryUpdateNotifier(context)
|
||||
|
||||
private var mangaToUpdate: List<LibraryManga> = mutableListOf()
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
try {
|
||||
setForeground(getForegroundInfo())
|
||||
} catch (e: IllegalStateException) {
|
||||
logcat(LogPriority.ERROR, e) { "Not allowed to set foreground job" }
|
||||
}
|
||||
|
||||
addMangaToQueue()
|
||||
|
||||
return withIOContext {
|
||||
try {
|
||||
updateMetadata()
|
||||
Result.success()
|
||||
} catch (e: Exception) {
|
||||
if (e is CancellationException) {
|
||||
// Assume success although cancelled
|
||||
Result.success()
|
||||
} else {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
Result.failure()
|
||||
}
|
||||
} finally {
|
||||
notifier.cancelProgressNotification()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getForegroundInfo(): ForegroundInfo {
|
||||
val notifier = LibraryUpdateNotifier(context)
|
||||
return ForegroundInfo(
|
||||
Notifications.ID_LIBRARY_PROGRESS,
|
||||
notifier.progressNotificationBuilder.build(),
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds list of manga to be updated.
|
||||
*/
|
||||
private fun addMangaToQueue() {
|
||||
mangaToUpdate = runBlocking { getLibraryManga.await() }
|
||||
|
||||
// Warn when excessively checking a single source
|
||||
val maxUpdatesFromSource = mangaToUpdate
|
||||
.groupBy { it.manga.source }
|
||||
.filterKeys { sourceManager.get(it) !is UnmeteredSource }
|
||||
.maxOfOrNull { it.value.size } ?: 0
|
||||
if (maxUpdatesFromSource > MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD) {
|
||||
notifier.showQueueSizeWarningNotification()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun updateMetadata() {
|
||||
val semaphore = Semaphore(5)
|
||||
val progressCount = AtomicInteger(0)
|
||||
val currentlyUpdatingManga = CopyOnWriteArrayList<Manga>()
|
||||
|
||||
coroutineScope {
|
||||
mangaToUpdate.groupBy { it.manga.source }
|
||||
.values
|
||||
.map { mangaInSource ->
|
||||
async {
|
||||
semaphore.withPermit {
|
||||
mangaInSource.forEach { libraryManga ->
|
||||
val manga = libraryManga.manga
|
||||
ensureActive()
|
||||
|
||||
withUpdateNotification(
|
||||
currentlyUpdatingManga,
|
||||
progressCount,
|
||||
manga,
|
||||
) {
|
||||
val source = sourceManager.get(manga.source) ?: return@withUpdateNotification
|
||||
try {
|
||||
val networkManga = source.getMangaDetails(manga.toSManga())
|
||||
val updatedManga = manga.prepUpdateCover(coverCache, networkManga, true)
|
||||
.copyFrom(networkManga)
|
||||
try {
|
||||
updateManga.await(updatedManga.toMangaUpdate())
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR) { "Manga doesn't exist anymore" }
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
// Ignore errors and continue
|
||||
logcat(LogPriority.ERROR, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.awaitAll()
|
||||
}
|
||||
|
||||
notifier.cancelProgressNotification()
|
||||
}
|
||||
|
||||
private suspend fun withUpdateNotification(
|
||||
updatingManga: CopyOnWriteArrayList<Manga>,
|
||||
completed: AtomicInteger,
|
||||
manga: Manga,
|
||||
block: suspend () -> Unit,
|
||||
) = coroutineScope {
|
||||
ensureActive()
|
||||
|
||||
updatingManga.add(manga)
|
||||
notifier.showProgressNotification(
|
||||
updatingManga,
|
||||
completed.get(),
|
||||
mangaToUpdate.size,
|
||||
)
|
||||
|
||||
block()
|
||||
|
||||
ensureActive()
|
||||
|
||||
updatingManga.remove(manga)
|
||||
completed.getAndIncrement()
|
||||
notifier.showProgressNotification(
|
||||
updatingManga,
|
||||
completed.get(),
|
||||
mangaToUpdate.size,
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "MetadataUpdate"
|
||||
private const val WORK_NAME_MANUAL = "MetadataUpdate"
|
||||
|
||||
private const val MANGA_PER_SOURCE_QUEUE_WARNING_THRESHOLD = 60
|
||||
|
||||
fun startNow(context: Context): Boolean {
|
||||
val wm = context.workManager
|
||||
if (wm.isRunning(TAG)) {
|
||||
// Already running either as a scheduled or manual job
|
||||
return false
|
||||
}
|
||||
val request = OneTimeWorkRequestBuilder<MetadataUpdateJob>()
|
||||
.addTag(TAG)
|
||||
.addTag(WORK_NAME_MANUAL)
|
||||
.build()
|
||||
wm.enqueueUniqueWork(WORK_NAME_MANUAL, ExistingWorkPolicy.KEEP, request)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun stop(context: Context) {
|
||||
val wm = context.workManager
|
||||
val workQuery = WorkQuery.Builder.fromTags(listOf(TAG))
|
||||
.addStates(listOf(WorkInfo.State.RUNNING))
|
||||
.build()
|
||||
wm.getWorkInfos(workQuery).get()
|
||||
// Should only return one work but just in case
|
||||
.forEach {
|
||||
wm.cancelWorkById(it.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.net.toUri
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.backup.BackupRestoreJob
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||
@@ -32,6 +31,7 @@ import tachiyomi.domain.download.service.DownloadPreferences
|
||||
import tachiyomi.domain.manga.interactor.GetManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
@@ -173,7 +173,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
||||
}
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
context.toast(R.string.chapter_error)
|
||||
context.toast(MR.strings.chapter_error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@ import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.app.NotificationManagerCompat.IMPORTANCE_DEFAULT
|
||||
import androidx.core.app.NotificationManagerCompat.IMPORTANCE_HIGH
|
||||
import androidx.core.app.NotificationManagerCompat.IMPORTANCE_LOW
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.buildNotificationChannel
|
||||
import eu.kanade.tachiyomi.util.system.buildNotificationChannelGroup
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
/**
|
||||
* Class to manage the basic information of all the notifications used in the app.
|
||||
@@ -102,16 +103,16 @@ object Notifications {
|
||||
notificationManager.createNotificationChannelGroupsCompat(
|
||||
listOf(
|
||||
buildNotificationChannelGroup(GROUP_BACKUP_RESTORE) {
|
||||
setName(context.getString(R.string.label_backup))
|
||||
setName(context.localize(MR.strings.label_backup))
|
||||
},
|
||||
buildNotificationChannelGroup(GROUP_DOWNLOADER) {
|
||||
setName(context.getString(R.string.download_notifier_downloader_title))
|
||||
setName(context.localize(MR.strings.download_notifier_downloader_title))
|
||||
},
|
||||
buildNotificationChannelGroup(GROUP_LIBRARY) {
|
||||
setName(context.getString(R.string.label_library))
|
||||
setName(context.localize(MR.strings.label_library))
|
||||
},
|
||||
buildNotificationChannelGroup(GROUP_APK_UPDATES) {
|
||||
setName(context.getString(R.string.label_recent_updates))
|
||||
setName(context.localize(MR.strings.label_recent_updates))
|
||||
},
|
||||
),
|
||||
)
|
||||
@@ -119,57 +120,57 @@ object Notifications {
|
||||
notificationManager.createNotificationChannelsCompat(
|
||||
listOf(
|
||||
buildNotificationChannel(CHANNEL_COMMON, IMPORTANCE_LOW) {
|
||||
setName(context.getString(R.string.channel_common))
|
||||
setName(context.localize(MR.strings.channel_common))
|
||||
},
|
||||
buildNotificationChannel(CHANNEL_LIBRARY_PROGRESS, IMPORTANCE_LOW) {
|
||||
setName(context.getString(R.string.channel_progress))
|
||||
setName(context.localize(MR.strings.channel_progress))
|
||||
setGroup(GROUP_LIBRARY)
|
||||
setShowBadge(false)
|
||||
},
|
||||
buildNotificationChannel(CHANNEL_LIBRARY_ERROR, IMPORTANCE_LOW) {
|
||||
setName(context.getString(R.string.channel_errors))
|
||||
setName(context.localize(MR.strings.channel_errors))
|
||||
setGroup(GROUP_LIBRARY)
|
||||
setShowBadge(false)
|
||||
},
|
||||
buildNotificationChannel(CHANNEL_LIBRARY_SKIPPED, IMPORTANCE_LOW) {
|
||||
setName(context.getString(R.string.channel_skipped))
|
||||
setName(context.localize(MR.strings.channel_skipped))
|
||||
setGroup(GROUP_LIBRARY)
|
||||
setShowBadge(false)
|
||||
},
|
||||
buildNotificationChannel(CHANNEL_NEW_CHAPTERS, IMPORTANCE_DEFAULT) {
|
||||
setName(context.getString(R.string.channel_new_chapters))
|
||||
setName(context.localize(MR.strings.channel_new_chapters))
|
||||
},
|
||||
buildNotificationChannel(CHANNEL_DOWNLOADER_PROGRESS, IMPORTANCE_LOW) {
|
||||
setName(context.getString(R.string.channel_progress))
|
||||
setName(context.localize(MR.strings.channel_progress))
|
||||
setGroup(GROUP_DOWNLOADER)
|
||||
setShowBadge(false)
|
||||
},
|
||||
buildNotificationChannel(CHANNEL_DOWNLOADER_ERROR, IMPORTANCE_LOW) {
|
||||
setName(context.getString(R.string.channel_errors))
|
||||
setName(context.localize(MR.strings.channel_errors))
|
||||
setGroup(GROUP_DOWNLOADER)
|
||||
setShowBadge(false)
|
||||
},
|
||||
buildNotificationChannel(CHANNEL_BACKUP_RESTORE_PROGRESS, IMPORTANCE_LOW) {
|
||||
setName(context.getString(R.string.channel_progress))
|
||||
setName(context.localize(MR.strings.channel_progress))
|
||||
setGroup(GROUP_BACKUP_RESTORE)
|
||||
setShowBadge(false)
|
||||
},
|
||||
buildNotificationChannel(CHANNEL_BACKUP_RESTORE_COMPLETE, IMPORTANCE_HIGH) {
|
||||
setName(context.getString(R.string.channel_complete))
|
||||
setName(context.localize(MR.strings.channel_complete))
|
||||
setGroup(GROUP_BACKUP_RESTORE)
|
||||
setShowBadge(false)
|
||||
setSound(null, null)
|
||||
},
|
||||
buildNotificationChannel(CHANNEL_INCOGNITO_MODE, IMPORTANCE_LOW) {
|
||||
setName(context.getString(R.string.pref_incognito_mode))
|
||||
setName(context.localize(MR.strings.pref_incognito_mode))
|
||||
},
|
||||
buildNotificationChannel(CHANNEL_APP_UPDATE, IMPORTANCE_DEFAULT) {
|
||||
setGroup(GROUP_APK_UPDATES)
|
||||
setName(context.getString(R.string.channel_app_updates))
|
||||
setName(context.localize(MR.strings.channel_app_updates))
|
||||
},
|
||||
buildNotificationChannel(CHANNEL_EXTENSIONS_UPDATE, IMPORTANCE_DEFAULT) {
|
||||
setGroup(GROUP_APK_UPDATES)
|
||||
setName(context.getString(R.string.channel_ext_updates))
|
||||
setName(context.localize(MR.strings.channel_ext_updates))
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
@@ -10,14 +10,15 @@ import android.provider.MediaStore
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.contentValuesOf
|
||||
import androidx.core.net.toUri
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.storage.cacheImageDir
|
||||
import eu.kanade.tachiyomi.util.storage.getUriCompat
|
||||
import logcat.LogPriority
|
||||
import okio.IOException
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.system.ImageUtil
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.i18n.MR
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
@@ -70,7 +71,7 @@ class ImageSaver(
|
||||
val imageLocation = (image.location as Location.Pictures).relativePath
|
||||
val relativePath = listOf(
|
||||
Environment.DIRECTORY_PICTURES,
|
||||
context.getString(R.string.app_name),
|
||||
context.localize(MR.strings.app_name),
|
||||
imageLocation,
|
||||
).joinToString(File.separator)
|
||||
|
||||
@@ -85,7 +86,7 @@ class ImageSaver(
|
||||
context.contentResolver.insert(
|
||||
pictureDir,
|
||||
contentValues,
|
||||
) ?: throw IOException(context.getString(R.string.error_saving_picture))
|
||||
) ?: throw IOException(context.localize(MR.strings.error_saving_picture))
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -96,7 +97,7 @@ class ImageSaver(
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
throw IOException(context.getString(R.string.error_saving_picture))
|
||||
throw IOException(context.localize(MR.strings.error_saving_picture))
|
||||
}
|
||||
|
||||
DiskUtil.scanMedia(context, picture)
|
||||
@@ -184,7 +185,7 @@ sealed interface Location {
|
||||
is Pictures -> {
|
||||
val file = File(
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
|
||||
context.getString(R.string.app_name),
|
||||
context.localize(MR.strings.app_name),
|
||||
)
|
||||
if (relativePath.isNotEmpty()) {
|
||||
return File(
|
||||
|
||||
@@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.data.track
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
@@ -28,8 +28,7 @@ interface Tracker {
|
||||
|
||||
fun getStatusList(): List<Int>
|
||||
|
||||
@StringRes
|
||||
fun getStatus(status: Int): Int?
|
||||
fun getStatus(status: Int): StringResource?
|
||||
|
||||
fun getReadingStatus(): Int
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package eu.kanade.tachiyomi.data.track.anilist
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.StringRes
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||
@@ -12,6 +12,7 @@ import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
@@ -60,14 +61,13 @@ class Anilist(id: Long) : BaseTracker(id, "AniList"), DeletableTracker {
|
||||
return listOf(READING, COMPLETED, ON_HOLD, DROPPED, PLAN_TO_READ, REREADING)
|
||||
}
|
||||
|
||||
@StringRes
|
||||
override fun getStatus(status: Int): Int? = when (status) {
|
||||
READING -> R.string.reading
|
||||
PLAN_TO_READ -> R.string.plan_to_read
|
||||
COMPLETED -> R.string.completed
|
||||
ON_HOLD -> R.string.on_hold
|
||||
DROPPED -> R.string.dropped
|
||||
REREADING -> R.string.repeating
|
||||
override fun getStatus(status: Int): StringResource? = when (status) {
|
||||
READING -> MR.strings.reading
|
||||
PLAN_TO_READ -> MR.strings.plan_to_read
|
||||
COMPLETED -> MR.strings.completed
|
||||
ON_HOLD -> MR.strings.on_hold
|
||||
DROPPED -> MR.strings.dropped
|
||||
REREADING -> MR.strings.repeating
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package eu.kanade.tachiyomi.data.track.bangumi
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.StringRes
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||
@@ -10,6 +10,7 @@ import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class Bangumi(id: Long) : BaseTracker(id, "Bangumi") {
|
||||
@@ -89,13 +90,12 @@ class Bangumi(id: Long) : BaseTracker(id, "Bangumi") {
|
||||
return listOf(READING, COMPLETED, ON_HOLD, DROPPED, PLAN_TO_READ)
|
||||
}
|
||||
|
||||
@StringRes
|
||||
override fun getStatus(status: Int): Int? = when (status) {
|
||||
READING -> R.string.reading
|
||||
PLAN_TO_READ -> R.string.plan_to_read
|
||||
COMPLETED -> R.string.completed
|
||||
ON_HOLD -> R.string.on_hold
|
||||
DROPPED -> R.string.dropped
|
||||
override fun getStatus(status: Int): StringResource? = when (status) {
|
||||
READING -> MR.strings.reading
|
||||
PLAN_TO_READ -> MR.strings.plan_to_read
|
||||
COMPLETED -> MR.strings.completed
|
||||
ON_HOLD -> MR.strings.on_hold
|
||||
DROPPED -> MR.strings.dropped
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package eu.kanade.tachiyomi.data.track.kavita
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.StringRes
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||
@@ -14,6 +14,7 @@ import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.security.MessageDigest
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
@@ -39,11 +40,10 @@ class Kavita(id: Long) : BaseTracker(id, "Kavita"), EnhancedTracker {
|
||||
|
||||
override fun getStatusList() = listOf(UNREAD, READING, COMPLETED)
|
||||
|
||||
@StringRes
|
||||
override fun getStatus(status: Int): Int? = when (status) {
|
||||
UNREAD -> R.string.unread
|
||||
READING -> R.string.reading
|
||||
COMPLETED -> R.string.completed
|
||||
override fun getStatus(status: Int): StringResource? = when (status) {
|
||||
UNREAD -> MR.strings.unread
|
||||
READING -> MR.strings.reading
|
||||
COMPLETED -> MR.strings.completed
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package eu.kanade.tachiyomi.data.track.kitsu
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.StringRes
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||
@@ -11,6 +11,7 @@ import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DecimalFormat
|
||||
|
||||
@@ -40,13 +41,12 @@ class Kitsu(id: Long) : BaseTracker(id, "Kitsu"), DeletableTracker {
|
||||
return listOf(READING, COMPLETED, ON_HOLD, DROPPED, PLAN_TO_READ)
|
||||
}
|
||||
|
||||
@StringRes
|
||||
override fun getStatus(status: Int): Int? = when (status) {
|
||||
READING -> R.string.reading
|
||||
PLAN_TO_READ -> R.string.plan_to_read
|
||||
COMPLETED -> R.string.completed
|
||||
ON_HOLD -> R.string.on_hold
|
||||
DROPPED -> R.string.dropped
|
||||
override fun getStatus(status: Int): StringResource? = when (status) {
|
||||
READING -> MR.strings.reading
|
||||
PLAN_TO_READ -> MR.strings.plan_to_read
|
||||
COMPLETED -> MR.strings.completed
|
||||
ON_HOLD -> MR.strings.on_hold
|
||||
DROPPED -> MR.strings.dropped
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package eu.kanade.tachiyomi.data.track.komga
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.StringRes
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||
@@ -13,6 +13,7 @@ import kotlinx.collections.immutable.persistentListOf
|
||||
import okhttp3.Dns
|
||||
import okhttp3.OkHttpClient
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
class Komga(id: Long) : BaseTracker(id, "Komga"), EnhancedTracker {
|
||||
@@ -36,11 +37,10 @@ class Komga(id: Long) : BaseTracker(id, "Komga"), EnhancedTracker {
|
||||
|
||||
override fun getStatusList() = listOf(UNREAD, READING, COMPLETED)
|
||||
|
||||
@StringRes
|
||||
override fun getStatus(status: Int): Int? = when (status) {
|
||||
UNREAD -> R.string.unread
|
||||
READING -> R.string.reading
|
||||
COMPLETED -> R.string.completed
|
||||
override fun getStatus(status: Int): StringResource? = when (status) {
|
||||
UNREAD -> MR.strings.unread
|
||||
READING -> MR.strings.reading
|
||||
COMPLETED -> MR.strings.completed
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package eu.kanade.tachiyomi.data.track.mangaupdates
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.StringRes
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||
@@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.data.track.mangaupdates.dto.toTrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker {
|
||||
|
||||
@@ -40,13 +41,12 @@ class MangaUpdates(id: Long) : BaseTracker(id, "MangaUpdates"), DeletableTracker
|
||||
return listOf(READING_LIST, COMPLETE_LIST, ON_HOLD_LIST, UNFINISHED_LIST, WISH_LIST)
|
||||
}
|
||||
|
||||
@StringRes
|
||||
override fun getStatus(status: Int): Int? = when (status) {
|
||||
READING_LIST -> R.string.reading_list
|
||||
WISH_LIST -> R.string.wish_list
|
||||
COMPLETE_LIST -> R.string.complete_list
|
||||
ON_HOLD_LIST -> R.string.on_hold_list
|
||||
UNFINISHED_LIST -> R.string.unfinished_list
|
||||
override fun getStatus(status: Int): StringResource? = when (status) {
|
||||
READING_LIST -> MR.strings.reading_list
|
||||
WISH_LIST -> MR.strings.wish_list
|
||||
COMPLETE_LIST -> MR.strings.complete_list
|
||||
ON_HOLD_LIST -> MR.strings.on_hold_list
|
||||
UNFINISHED_LIST -> MR.strings.unfinished_list
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package eu.kanade.tachiyomi.data.track.myanimelist
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.StringRes
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||
@@ -11,6 +11,7 @@ import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker {
|
||||
@@ -46,14 +47,13 @@ class MyAnimeList(id: Long) : BaseTracker(id, "MyAnimeList"), DeletableTracker {
|
||||
return listOf(READING, COMPLETED, ON_HOLD, DROPPED, PLAN_TO_READ, REREADING)
|
||||
}
|
||||
|
||||
@StringRes
|
||||
override fun getStatus(status: Int): Int? = when (status) {
|
||||
READING -> R.string.reading
|
||||
PLAN_TO_READ -> R.string.plan_to_read
|
||||
COMPLETED -> R.string.completed
|
||||
ON_HOLD -> R.string.on_hold
|
||||
DROPPED -> R.string.dropped
|
||||
REREADING -> R.string.repeating
|
||||
override fun getStatus(status: Int): StringResource? = when (status) {
|
||||
READING -> MR.strings.reading
|
||||
PLAN_TO_READ -> MR.strings.plan_to_read
|
||||
COMPLETED -> MR.strings.completed
|
||||
ON_HOLD -> MR.strings.on_hold
|
||||
DROPPED -> MR.strings.dropped
|
||||
REREADING -> MR.strings.repeating
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package eu.kanade.tachiyomi.data.track.shikimori
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.StringRes
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||
@@ -11,6 +11,7 @@ import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker {
|
||||
@@ -103,14 +104,13 @@ class Shikimori(id: Long) : BaseTracker(id, "Shikimori"), DeletableTracker {
|
||||
return listOf(READING, COMPLETED, ON_HOLD, DROPPED, PLAN_TO_READ, REREADING)
|
||||
}
|
||||
|
||||
@StringRes
|
||||
override fun getStatus(status: Int): Int? = when (status) {
|
||||
READING -> R.string.reading
|
||||
PLAN_TO_READ -> R.string.plan_to_read
|
||||
COMPLETED -> R.string.completed
|
||||
ON_HOLD -> R.string.on_hold
|
||||
DROPPED -> R.string.dropped
|
||||
REREADING -> R.string.repeating
|
||||
override fun getStatus(status: Int): StringResource? = when (status) {
|
||||
READING -> MR.strings.reading
|
||||
PLAN_TO_READ -> MR.strings.plan_to_read
|
||||
COMPLETED -> MR.strings.completed
|
||||
ON_HOLD -> MR.strings.on_hold
|
||||
DROPPED -> MR.strings.dropped
|
||||
REREADING -> MR.strings.repeating
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package eu.kanade.tachiyomi.data.track.suwayomi
|
||||
|
||||
import android.graphics.Color
|
||||
import androidx.annotation.StringRes
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.BaseTracker
|
||||
@@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.domain.manga.model.Manga as DomainManga
|
||||
import tachiyomi.domain.track.model.Track as DomainTrack
|
||||
|
||||
@@ -29,11 +30,10 @@ class Suwayomi(id: Long) : BaseTracker(id, "Suwayomi"), EnhancedTracker {
|
||||
|
||||
override fun getStatusList() = listOf(UNREAD, READING, COMPLETED)
|
||||
|
||||
@StringRes
|
||||
override fun getStatus(status: Int): Int? = when (status) {
|
||||
UNREAD -> R.string.unread
|
||||
READING -> R.string.reading
|
||||
COMPLETED -> R.string.completed
|
||||
override fun getStatus(status: Int): StringResource? = when (status) {
|
||||
UNREAD -> MR.strings.unread
|
||||
READING -> MR.strings.reading
|
||||
COMPLETED -> MR.strings.completed
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import androidx.work.NetworkType
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.WorkerParameters
|
||||
import androidx.work.workDataOf
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
@@ -22,8 +21,10 @@ import eu.kanade.tachiyomi.util.system.workManager
|
||||
import logcat.LogPriority
|
||||
import okhttp3.internal.http2.ErrorCode
|
||||
import okhttp3.internal.http2.StreamResetException
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.lang.withIOContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
@@ -36,7 +37,7 @@ class AppUpdateDownloadJob(private val context: Context, workerParams: WorkerPar
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
val url = inputData.getString(EXTRA_DOWNLOAD_URL)
|
||||
val title = inputData.getString(EXTRA_DOWNLOAD_TITLE) ?: context.getString(R.string.app_name)
|
||||
val title = inputData.getString(EXTRA_DOWNLOAD_TITLE) ?: context.localize(MR.strings.app_name)
|
||||
|
||||
if (url.isNullOrEmpty()) {
|
||||
return Result.failure()
|
||||
|
||||
@@ -13,7 +13,9 @@ import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||
import eu.kanade.tachiyomi.util.system.notify
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.domain.release.model.Release
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
internal class AppUpdateNotifier(private val context: Context) {
|
||||
|
||||
@@ -51,7 +53,7 @@ internal class AppUpdateNotifier(private val context: Context) {
|
||||
}
|
||||
|
||||
with(notificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.update_check_notification_update_available))
|
||||
setContentTitle(context.localize(MR.strings.update_check_notification_update_available))
|
||||
setContentText(release.version)
|
||||
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
setContentIntent(updateIntent)
|
||||
@@ -59,12 +61,12 @@ internal class AppUpdateNotifier(private val context: Context) {
|
||||
clearActions()
|
||||
addAction(
|
||||
android.R.drawable.stat_sys_download_done,
|
||||
context.getString(R.string.action_download),
|
||||
context.localize(MR.strings.action_download),
|
||||
updateIntent,
|
||||
)
|
||||
addAction(
|
||||
R.drawable.ic_info_24dp,
|
||||
context.getString(R.string.whats_new),
|
||||
context.localize(MR.strings.whats_new),
|
||||
releaseIntent,
|
||||
)
|
||||
}
|
||||
@@ -79,14 +81,14 @@ internal class AppUpdateNotifier(private val context: Context) {
|
||||
fun onDownloadStarted(title: String? = null): NotificationCompat.Builder {
|
||||
with(notificationBuilder) {
|
||||
title?.let { setContentTitle(title) }
|
||||
setContentText(context.getString(R.string.update_check_notification_download_in_progress))
|
||||
setContentText(context.localize(MR.strings.update_check_notification_download_in_progress))
|
||||
setSmallIcon(android.R.drawable.stat_sys_download)
|
||||
setOngoing(true)
|
||||
|
||||
clearActions()
|
||||
addAction(
|
||||
R.drawable.ic_close_24dp,
|
||||
context.getString(R.string.action_cancel),
|
||||
context.localize(MR.strings.action_cancel),
|
||||
NotificationReceiver.cancelDownloadAppUpdatePendingBroadcast(context),
|
||||
)
|
||||
}
|
||||
@@ -115,7 +117,7 @@ internal class AppUpdateNotifier(private val context: Context) {
|
||||
fun promptInstall(uri: Uri) {
|
||||
val installIntent = NotificationHandler.installApkPendingActivity(context, uri)
|
||||
with(notificationBuilder) {
|
||||
setContentText(context.getString(R.string.update_check_notification_download_complete))
|
||||
setContentText(context.localize(MR.strings.update_check_notification_download_complete))
|
||||
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
setOnlyAlertOnce(false)
|
||||
setProgress(0, 0, false)
|
||||
@@ -125,12 +127,12 @@ internal class AppUpdateNotifier(private val context: Context) {
|
||||
clearActions()
|
||||
addAction(
|
||||
R.drawable.ic_system_update_alt_white_24dp,
|
||||
context.getString(R.string.action_install),
|
||||
context.localize(MR.strings.action_install),
|
||||
installIntent,
|
||||
)
|
||||
addAction(
|
||||
R.drawable.ic_close_24dp,
|
||||
context.getString(R.string.action_cancel),
|
||||
context.localize(MR.strings.action_cancel),
|
||||
NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_APP_UPDATE_PROMPT),
|
||||
)
|
||||
}
|
||||
@@ -145,8 +147,8 @@ internal class AppUpdateNotifier(private val context: Context) {
|
||||
*/
|
||||
fun promptFdroidUpdate() {
|
||||
with(notificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.update_check_notification_update_available))
|
||||
setContentText(context.getString(R.string.update_check_fdroid_migration_info))
|
||||
setContentTitle(context.localize(MR.strings.update_check_notification_update_available))
|
||||
setContentText(context.localize(MR.strings.update_check_fdroid_migration_info))
|
||||
setSmallIcon(R.drawable.ic_tachi)
|
||||
setContentIntent(
|
||||
NotificationHandler.openUrl(
|
||||
@@ -165,7 +167,7 @@ internal class AppUpdateNotifier(private val context: Context) {
|
||||
*/
|
||||
fun onDownloadError(url: String) {
|
||||
with(notificationBuilder) {
|
||||
setContentText(context.getString(R.string.update_check_notification_download_error))
|
||||
setContentText(context.localize(MR.strings.update_check_notification_download_error))
|
||||
setSmallIcon(R.drawable.ic_warning_white_24dp)
|
||||
setOnlyAlertOnce(false)
|
||||
setProgress(0, 0, false)
|
||||
@@ -173,12 +175,12 @@ internal class AppUpdateNotifier(private val context: Context) {
|
||||
clearActions()
|
||||
addAction(
|
||||
R.drawable.ic_refresh_24dp,
|
||||
context.getString(R.string.action_retry),
|
||||
context.localize(MR.strings.action_retry),
|
||||
NotificationReceiver.downloadAppUpdatePendingBroadcast(context, url),
|
||||
)
|
||||
addAction(
|
||||
R.drawable.ic_close_24dp,
|
||||
context.getString(R.string.action_cancel),
|
||||
context.localize(MR.strings.action_cancel),
|
||||
NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_APP_UPDATER),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
|
||||
import eu.kanade.tachiyomi.extension.api.ExtensionUpdateNotifier
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
@@ -24,6 +23,7 @@ import tachiyomi.core.util.lang.launchNow
|
||||
import tachiyomi.core.util.lang.withUIContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.source.model.StubSource
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.util.Locale
|
||||
@@ -121,7 +121,7 @@ class ExtensionManager(
|
||||
api.findExtensions()
|
||||
} catch (e: Exception) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
withUIContext { context.toast(R.string.extension_api_error) }
|
||||
withUIContext { context.toast(MR.strings.extension_api_error) }
|
||||
emptyList()
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||
import eu.kanade.tachiyomi.util.system.cancelNotification
|
||||
import eu.kanade.tachiyomi.util.system.notify
|
||||
import tachiyomi.core.i18n.localizePlural
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
class ExtensionUpdateNotifier(private val context: Context) {
|
||||
|
||||
@@ -16,8 +18,8 @@ class ExtensionUpdateNotifier(private val context: Context) {
|
||||
Notifications.CHANNEL_EXTENSIONS_UPDATE,
|
||||
) {
|
||||
setContentTitle(
|
||||
context.resources.getQuantityString(
|
||||
R.plurals.update_check_notification_ext_updates,
|
||||
context.localizePlural(
|
||||
MR.plurals.update_check_notification_ext_updates,
|
||||
names.size,
|
||||
names.size,
|
||||
),
|
||||
|
||||
@@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.extension.installer
|
||||
import android.app.Service
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||
import eu.kanade.tachiyomi.util.system.getUriSize
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
@@ -15,6 +14,7 @@ import kotlinx.coroutines.launch
|
||||
import logcat.LogPriority
|
||||
import rikka.shizuku.Shizuku
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.i18n.MR
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStream
|
||||
|
||||
@@ -116,7 +116,7 @@ class ShizukuInstaller(private val service: Service) : Installer(service) {
|
||||
}
|
||||
} else {
|
||||
logcat(LogPriority.ERROR) { "Shizuku is not ready to use" }
|
||||
service.toast(R.string.ext_installer_shizuku_stopped)
|
||||
service.toast(MR.strings.ext_installer_shizuku_stopped)
|
||||
service.stopSelf()
|
||||
false
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@ import eu.kanade.tachiyomi.extension.util.ExtensionInstaller.Companion.EXTRA_DOW
|
||||
import eu.kanade.tachiyomi.util.system.getSerializableExtraCompat
|
||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
class ExtensionInstallService : Service() {
|
||||
|
||||
@@ -27,7 +29,7 @@ class ExtensionInstallService : Service() {
|
||||
setAutoCancel(false)
|
||||
setOngoing(true)
|
||||
setShowWhen(false)
|
||||
setContentTitle(getString(R.string.ext_install_service_notif))
|
||||
setContentTitle(localize(MR.strings.ext_install_service_notif))
|
||||
setProgress(100, 100, true)
|
||||
}.build()
|
||||
startForeground(Notifications.ID_EXTENSION_INSTALLER, notification)
|
||||
|
||||
@@ -8,7 +8,6 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.navigator.tab.LocalTabNavigator
|
||||
@@ -24,6 +23,8 @@ import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.source.sourcesTab
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
|
||||
data class BrowseTab(
|
||||
private val toExtensions: Boolean = false,
|
||||
@@ -36,7 +37,7 @@ data class BrowseTab(
|
||||
val image = AnimatedImageVector.animatedVectorResource(R.drawable.anim_browse_enter)
|
||||
return TabOptions(
|
||||
index = 3u,
|
||||
title = stringResource(R.string.browse),
|
||||
title = localize(MR.strings.browse),
|
||||
icon = rememberAnimatedVectorPainter(image, isSelected),
|
||||
)
|
||||
}
|
||||
@@ -54,7 +55,7 @@ data class BrowseTab(
|
||||
val extensionsState by extensionsScreenModel.state.collectAsState()
|
||||
|
||||
TabbedScreen(
|
||||
titleRes = R.string.browse,
|
||||
titleRes = MR.strings.browse,
|
||||
tabs = persistentListOf(
|
||||
sourcesTab(),
|
||||
extensionsTab(extensionsScreenModel),
|
||||
|
||||
@@ -10,9 +10,9 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.browse.ExtensionFilterScreen
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
||||
class ExtensionFilterScreen : Screen() {
|
||||
@@ -41,7 +41,7 @@ class ExtensionFilterScreen : Screen() {
|
||||
screenModel.events.collectLatest {
|
||||
when (it) {
|
||||
ExtensionFilterEvent.FailedFetchingLanguages -> {
|
||||
context.toast(R.string.internal_error)
|
||||
context.localize(MR.strings.internal_error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package eu.kanade.tachiyomi.ui.browse.extension
|
||||
|
||||
import android.app.Application
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.runtime.Immutable
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.domain.extension.interactor.GetExtensionsByType
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.presentation.components.SEARCH_DEBOUNCE_MILLIS
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.extension.model.InstallStep
|
||||
@@ -28,6 +27,7 @@ import kotlinx.coroutines.flow.onCompletion
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.update
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
@@ -86,13 +86,13 @@ class ExtensionsScreenModel(
|
||||
|
||||
val updates = _updates.filter(queryFilter(searchQuery)).map(extensionMapper(downloads))
|
||||
if (updates.isNotEmpty()) {
|
||||
itemsGroups[ExtensionUiModel.Header.Resource(R.string.ext_updates_pending)] = updates
|
||||
itemsGroups[ExtensionUiModel.Header.Resource(MR.strings.ext_updates_pending)] = updates
|
||||
}
|
||||
|
||||
val installed = _installed.filter(queryFilter(searchQuery)).map(extensionMapper(downloads))
|
||||
val untrusted = _untrusted.filter(queryFilter(searchQuery)).map(extensionMapper(downloads))
|
||||
if (installed.isNotEmpty() || untrusted.isNotEmpty()) {
|
||||
itemsGroups[ExtensionUiModel.Header.Resource(R.string.ext_installed)] = installed + untrusted
|
||||
itemsGroups[ExtensionUiModel.Header.Resource(MR.strings.ext_installed)] = installed + untrusted
|
||||
}
|
||||
|
||||
val languagesWithExtensions = _available
|
||||
@@ -209,7 +209,7 @@ typealias ItemGroups = MutableMap<ExtensionUiModel.Header, List<ExtensionUiModel
|
||||
|
||||
object ExtensionUiModel {
|
||||
sealed interface Header {
|
||||
data class Resource(@StringRes val textRes: Int) : Header
|
||||
data class Resource(val textRes: StringResource) : Header
|
||||
data class Text(val text: String) : Header
|
||||
}
|
||||
|
||||
|
||||
@@ -5,16 +5,16 @@ import androidx.compose.material.icons.outlined.Translate
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.browse.ExtensionScreen
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.TabContent
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.extension.model.Extension
|
||||
import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsScreen
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
|
||||
@Composable
|
||||
fun extensionsTab(
|
||||
@@ -24,12 +24,12 @@ fun extensionsTab(
|
||||
val state by extensionsScreenModel.state.collectAsState()
|
||||
|
||||
return TabContent(
|
||||
titleRes = R.string.label_extensions,
|
||||
titleRes = MR.strings.label_extensions,
|
||||
badgeNumber = state.updates.takeIf { it > 0 },
|
||||
searchEnabled = true,
|
||||
actions = persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_filter),
|
||||
title = localize(MR.strings.action_filter),
|
||||
icon = Icons.Outlined.Translate,
|
||||
onClick = { navigator.push(ExtensionFilterScreen()) },
|
||||
),
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
package eu.kanade.tachiyomi.ui.browse.migration
|
||||
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.domain.manga.model.hasCustomCover
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.download.DownloadCache
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
data class MigrationFlag(
|
||||
val flag: Int,
|
||||
val isDefaultSelected: Boolean,
|
||||
val titleId: Int,
|
||||
val titleId: StringResource,
|
||||
) {
|
||||
companion object {
|
||||
fun create(flag: Int, defaultSelectionMap: Int, titleId: Int): MigrationFlag {
|
||||
fun create(flag: Int, defaultSelectionMap: Int, titleId: StringResource): MigrationFlag {
|
||||
return MigrationFlag(
|
||||
flag = flag,
|
||||
isDefaultSelected = defaultSelectionMap and flag != 0,
|
||||
@@ -53,15 +54,15 @@ object MigrationFlags {
|
||||
/** Returns information about applicable flags with default selections. */
|
||||
fun getFlags(manga: Manga?, defaultSelectedBitMap: Int): List<MigrationFlag> {
|
||||
val flags = mutableListOf<MigrationFlag>()
|
||||
flags += MigrationFlag.create(CHAPTERS, defaultSelectedBitMap, R.string.chapters)
|
||||
flags += MigrationFlag.create(CATEGORIES, defaultSelectedBitMap, R.string.categories)
|
||||
flags += MigrationFlag.create(CHAPTERS, defaultSelectedBitMap, MR.strings.chapters)
|
||||
flags += MigrationFlag.create(CATEGORIES, defaultSelectedBitMap, MR.strings.categories)
|
||||
|
||||
if (manga != null) {
|
||||
if (manga.hasCustomCover(coverCache)) {
|
||||
flags += MigrationFlag.create(CUSTOM_COVER, defaultSelectedBitMap, R.string.custom_cover)
|
||||
flags += MigrationFlag.create(CUSTOM_COVER, defaultSelectedBitMap, MR.strings.custom_cover)
|
||||
}
|
||||
if (downloadCache.getDownloadCount(manga) > 0) {
|
||||
flags += MigrationFlag.create(DELETE_DOWNLOADED, defaultSelectedBitMap, R.string.delete_downloaded)
|
||||
flags += MigrationFlag.create(DELETE_DOWNLOADED, defaultSelectedBitMap, MR.strings.delete_downloaded)
|
||||
}
|
||||
}
|
||||
return flags
|
||||
|
||||
+2
-2
@@ -10,11 +10,11 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.browse.MigrateMangaScreen
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateSearchScreen
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
||||
data class MigrateMangaScreen(
|
||||
@@ -46,7 +46,7 @@ data class MigrateMangaScreen(
|
||||
screenModel.events.collectLatest { event ->
|
||||
when (event) {
|
||||
MigrationMangaEvent.FailedFetchingFavorites -> {
|
||||
context.toast(R.string.internal_error)
|
||||
context.toast(MR.strings.internal_error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,12 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.domain.manga.model.hasCustomCover
|
||||
import eu.kanade.domain.manga.model.toSManga
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
||||
@@ -49,7 +47,9 @@ import tachiyomi.domain.manga.model.MangaUpdate
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
import tachiyomi.domain.track.interactor.InsertTrack
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@@ -79,7 +79,7 @@ internal fun MigrateDialog(
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = {
|
||||
Text(text = stringResource(R.string.migration_dialog_what_to_include))
|
||||
Text(text = localize(MR.strings.migration_dialog_what_to_include))
|
||||
},
|
||||
text = {
|
||||
Column(
|
||||
@@ -87,7 +87,7 @@ internal fun MigrateDialog(
|
||||
) {
|
||||
flags.forEachIndexed { index, flag ->
|
||||
LabeledCheckbox(
|
||||
label = stringResource(flag.titleId),
|
||||
label = localize(flag.titleId),
|
||||
checked = selectedFlags[index],
|
||||
onCheckedChange = { selectedFlags[index] = it },
|
||||
)
|
||||
@@ -104,7 +104,7 @@ internal fun MigrateDialog(
|
||||
onClickTitle()
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_show_manga))
|
||||
Text(text = localize(MR.strings.action_show_manga))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
@@ -122,7 +122,7 @@ internal fun MigrateDialog(
|
||||
}
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.copy))
|
||||
Text(text = localize(MR.strings.copy))
|
||||
}
|
||||
TextButton(
|
||||
onClick = {
|
||||
@@ -138,7 +138,7 @@ internal fun MigrateDialog(
|
||||
}
|
||||
},
|
||||
) {
|
||||
Text(text = stringResource(R.string.migrate))
|
||||
Text(text = localize(MR.strings.migrate))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
+3
-3
@@ -14,7 +14,6 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
@@ -22,7 +21,6 @@ import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.browse.BrowseSourceContent
|
||||
import eu.kanade.presentation.components.SearchToolbar
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.SourceFilterDialog
|
||||
@@ -32,8 +30,10 @@ import eu.kanade.tachiyomi.ui.webview.WebViewScreen
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.core.Constants
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
import tachiyomi.source.local.LocalSource
|
||||
|
||||
data class SourceSearchScreen(
|
||||
@@ -66,7 +66,7 @@ data class SourceSearchScreen(
|
||||
floatingActionButton = {
|
||||
AnimatedVisibility(visible = state.filters.isNotEmpty()) {
|
||||
ExtendedFloatingActionButton(
|
||||
text = { Text(text = stringResource(R.string.action_filter)) },
|
||||
text = { Text(text = localize(MR.strings.action_filter)) },
|
||||
icon = { Icon(Icons.Outlined.FilterList, contentDescription = null) },
|
||||
onClick = screenModel::openFilterSheet,
|
||||
)
|
||||
|
||||
+4
-5
@@ -2,12 +2,10 @@ package eu.kanade.tachiyomi.ui.browse.migration.sources
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.HelpOutline
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
@@ -15,9 +13,10 @@ import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.browse.MigrateSourceScreen
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.TabContent
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrateMangaScreen
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
|
||||
@Composable
|
||||
fun Screen.migrateSourceTab(): TabContent {
|
||||
@@ -27,10 +26,10 @@ fun Screen.migrateSourceTab(): TabContent {
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
return TabContent(
|
||||
titleRes = R.string.label_migration,
|
||||
titleRes = MR.strings.label_migration,
|
||||
actions = persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.migration_help_guide),
|
||||
title = localize(MR.strings.migration_help_guide),
|
||||
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
onClick = {
|
||||
uriHandler.openUri("https://tachiyomi.org/docs/guides/source-migration")
|
||||
|
||||
@@ -10,8 +10,8 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import eu.kanade.presentation.browse.SourcesFilterScreen
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
||||
class SourcesFilterScreen : Screen() {
|
||||
@@ -30,7 +30,7 @@ class SourcesFilterScreen : Screen() {
|
||||
if (state is SourcesFilterScreenModel.State.Error) {
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(Unit) {
|
||||
context.toast(R.string.internal_error)
|
||||
context.toast(MR.strings.internal_error)
|
||||
navigator.pop()
|
||||
}
|
||||
return
|
||||
|
||||
@@ -7,7 +7,6 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
@@ -16,12 +15,13 @@ import eu.kanade.presentation.browse.SourceOptionsDialog
|
||||
import eu.kanade.presentation.browse.SourcesScreen
|
||||
import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.components.TabContent
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreen
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
|
||||
@Composable
|
||||
fun Screen.sourcesTab(): TabContent {
|
||||
@@ -30,15 +30,15 @@ fun Screen.sourcesTab(): TabContent {
|
||||
val state by screenModel.state.collectAsState()
|
||||
|
||||
return TabContent(
|
||||
titleRes = R.string.label_sources,
|
||||
titleRes = MR.strings.label_sources,
|
||||
actions = persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_global_search),
|
||||
title = localize(MR.strings.action_global_search),
|
||||
icon = Icons.Outlined.TravelExplore,
|
||||
onClick = { navigator.push(GlobalSearchScreen()) },
|
||||
),
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_filter),
|
||||
title = localize(MR.strings.action_filter),
|
||||
icon = Icons.Outlined.FilterList,
|
||||
onClick = { navigator.push(SourcesFilterScreen()) },
|
||||
),
|
||||
@@ -70,7 +70,7 @@ fun Screen.sourcesTab(): TabContent {
|
||||
)
|
||||
}
|
||||
|
||||
val internalErrString = stringResource(R.string.internal_error)
|
||||
val internalErrString = localize(MR.strings.internal_error)
|
||||
LaunchedEffect(Unit) {
|
||||
screenModel.events.collectLatest { event ->
|
||||
when (event) {
|
||||
|
||||
@@ -31,7 +31,6 @@ import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
@@ -44,7 +43,6 @@ import eu.kanade.presentation.category.components.ChangeCategoryDialog
|
||||
import eu.kanade.presentation.manga.DuplicateMangaDialog
|
||||
import eu.kanade.presentation.util.AssistContentScreen
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.browse.extension.details.SourcePreferencesScreen
|
||||
@@ -58,8 +56,10 @@ import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import tachiyomi.core.Constants
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
import tachiyomi.domain.source.model.StubSource
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
import tachiyomi.source.local.LocalSource
|
||||
|
||||
data class BrowseSourceScreen(
|
||||
@@ -150,7 +150,7 @@ data class BrowseSourceScreen(
|
||||
)
|
||||
},
|
||||
label = {
|
||||
Text(text = stringResource(R.string.popular))
|
||||
Text(text = localize(MR.strings.popular))
|
||||
},
|
||||
)
|
||||
if ((screenModel.source as CatalogueSource).supportsLatest) {
|
||||
@@ -169,7 +169,7 @@ data class BrowseSourceScreen(
|
||||
)
|
||||
},
|
||||
label = {
|
||||
Text(text = stringResource(R.string.latest))
|
||||
Text(text = localize(MR.strings.latest))
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -186,7 +186,7 @@ data class BrowseSourceScreen(
|
||||
)
|
||||
},
|
||||
label = {
|
||||
Text(text = stringResource(R.string.action_filter))
|
||||
Text(text = localize(MR.strings.action_filter))
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,13 +14,12 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import eu.kanade.presentation.components.AdaptiveSheet
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import tachiyomi.core.preference.TriState
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.CheckboxItem
|
||||
import tachiyomi.presentation.core.components.CollapsibleBox
|
||||
import tachiyomi.presentation.core.components.HeadingItem
|
||||
@@ -29,6 +28,7 @@ import tachiyomi.presentation.core.components.SortItem
|
||||
import tachiyomi.presentation.core.components.TextItem
|
||||
import tachiyomi.presentation.core.components.TriStateItem
|
||||
import tachiyomi.presentation.core.components.material.Button
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
|
||||
@Composable
|
||||
fun SourceFilterDialog(
|
||||
@@ -52,7 +52,7 @@ fun SourceFilterDialog(
|
||||
) {
|
||||
TextButton(onClick = onReset) {
|
||||
Text(
|
||||
text = stringResource(R.string.action_reset),
|
||||
text = localize(MR.strings.action_reset),
|
||||
style = LocalTextStyle.current.copy(
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
),
|
||||
@@ -65,7 +65,7 @@ fun SourceFilterDialog(
|
||||
onFilter()
|
||||
onDismissRequest()
|
||||
}) {
|
||||
Text(stringResource(R.string.action_filter))
|
||||
Text(localize(MR.strings.action_filter))
|
||||
}
|
||||
}
|
||||
HorizontalDivider()
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
package eu.kanade.tachiyomi.ui.category
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.runtime.Immutable
|
||||
import cafe.adriel.voyager.core.model.StateScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import eu.kanade.tachiyomi.R
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
@@ -18,6 +17,7 @@ import tachiyomi.domain.category.interactor.GetCategories
|
||||
import tachiyomi.domain.category.interactor.RenameCategory
|
||||
import tachiyomi.domain.category.interactor.ReorderCategory
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@@ -128,8 +128,8 @@ sealed interface CategoryDialog {
|
||||
}
|
||||
|
||||
sealed interface CategoryEvent {
|
||||
sealed class LocalizedMessage(@StringRes val stringRes: Int) : CategoryEvent
|
||||
data object InternalError : LocalizedMessage(R.string.internal_error)
|
||||
sealed class LocalizedMessage(val stringRes: StringResource) : CategoryEvent
|
||||
data object InternalError : LocalizedMessage(MR.strings.internal_error)
|
||||
}
|
||||
|
||||
sealed interface CategoryScreenState {
|
||||
|
||||
@@ -6,17 +6,17 @@ import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
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.R
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreen
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
||||
class DeepLinkScreen(
|
||||
@@ -35,7 +35,7 @@ class DeepLinkScreen(
|
||||
Scaffold(
|
||||
topBar = { scrollBehavior ->
|
||||
AppBar(
|
||||
title = stringResource(R.string.action_search_hint),
|
||||
title = localize(MR.strings.action_search_hint),
|
||||
navigateUp = navigator::pop,
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
|
||||
@@ -13,7 +13,6 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.Sort
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material.icons.outlined.Pause
|
||||
import androidx.compose.material.icons.outlined.Sort
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -36,7 +35,6 @@ import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Velocity
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -53,13 +51,14 @@ import eu.kanade.presentation.components.AppBarActions
|
||||
import eu.kanade.presentation.components.DropdownMenu
|
||||
import eu.kanade.presentation.components.NestedMenuItem
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.databinding.DownloadListBinding
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import tachiyomi.core.util.lang.launchUI
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.Pill
|
||||
import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@@ -105,7 +104,7 @@ object DownloadQueueScreen : Screen() {
|
||||
titleContent = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = stringResource(R.string.label_download_queue),
|
||||
text = localize(MR.strings.label_download_queue),
|
||||
maxLines = 1,
|
||||
modifier = Modifier.weight(1f, false),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
@@ -132,10 +131,10 @@ object DownloadQueueScreen : Screen() {
|
||||
onDismissRequest = onDismissRequest,
|
||||
) {
|
||||
NestedMenuItem(
|
||||
text = { Text(text = stringResource(R.string.action_order_by_upload_date)) },
|
||||
text = { Text(text = localize(MR.strings.action_order_by_upload_date)) },
|
||||
children = { closeMenu ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(R.string.action_newest)) },
|
||||
text = { Text(text = localize(MR.strings.action_newest)) },
|
||||
onClick = {
|
||||
screenModel.reorderQueue(
|
||||
{ it.download.chapter.dateUpload },
|
||||
@@ -145,7 +144,7 @@ object DownloadQueueScreen : Screen() {
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(R.string.action_oldest)) },
|
||||
text = { Text(text = localize(MR.strings.action_oldest)) },
|
||||
onClick = {
|
||||
screenModel.reorderQueue(
|
||||
{ it.download.chapter.dateUpload },
|
||||
@@ -157,10 +156,10 @@ object DownloadQueueScreen : Screen() {
|
||||
},
|
||||
)
|
||||
NestedMenuItem(
|
||||
text = { Text(text = stringResource(R.string.action_order_by_chapter_number)) },
|
||||
text = { Text(text = localize(MR.strings.action_order_by_chapter_number)) },
|
||||
children = { closeMenu ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(R.string.action_asc)) },
|
||||
text = { Text(text = localize(MR.strings.action_asc)) },
|
||||
onClick = {
|
||||
screenModel.reorderQueue(
|
||||
{ it.download.chapter.chapterNumber },
|
||||
@@ -170,7 +169,7 @@ object DownloadQueueScreen : Screen() {
|
||||
},
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(text = stringResource(R.string.action_desc)) },
|
||||
text = { Text(text = localize(MR.strings.action_desc)) },
|
||||
onClick = {
|
||||
screenModel.reorderQueue(
|
||||
{ it.download.chapter.chapterNumber },
|
||||
@@ -186,12 +185,12 @@ object DownloadQueueScreen : Screen() {
|
||||
AppBarActions(
|
||||
persistentListOf(
|
||||
AppBar.Action(
|
||||
title = stringResource(R.string.action_sort),
|
||||
title = localize(MR.strings.action_sort),
|
||||
icon = Icons.AutoMirrored.Outlined.Sort,
|
||||
onClick = { sortExpanded = true },
|
||||
),
|
||||
AppBar.OverflowAction(
|
||||
title = stringResource(R.string.action_cancel_all),
|
||||
title = localize(MR.strings.action_cancel_all),
|
||||
onClick = { screenModel.clearQueue() },
|
||||
),
|
||||
),
|
||||
@@ -211,11 +210,11 @@ object DownloadQueueScreen : Screen() {
|
||||
ExtendedFloatingActionButton(
|
||||
text = {
|
||||
val id = if (isRunning) {
|
||||
R.string.action_pause
|
||||
MR.strings.action_pause
|
||||
} else {
|
||||
R.string.action_resume
|
||||
MR.strings.action_resume
|
||||
}
|
||||
Text(text = stringResource(id))
|
||||
Text(text = localize(id))
|
||||
},
|
||||
icon = {
|
||||
val icon = if (isRunning) {
|
||||
@@ -239,7 +238,7 @@ object DownloadQueueScreen : Screen() {
|
||||
) { contentPadding ->
|
||||
if (downloadList.isEmpty()) {
|
||||
EmptyScreen(
|
||||
textResource = R.string.information_no_downloads,
|
||||
stringRes = MR.strings.information_no_downloads,
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
)
|
||||
return@Scaffold
|
||||
|
||||
@@ -10,7 +10,6 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
@@ -28,7 +27,10 @@ import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.domain.chapter.model.Chapter
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
|
||||
object HistoryTab : Tab {
|
||||
|
||||
@@ -43,7 +45,7 @@ object HistoryTab : Tab {
|
||||
val image = AnimatedImageVector.animatedVectorResource(R.drawable.anim_history_enter)
|
||||
return TabOptions(
|
||||
index = 2u,
|
||||
title = stringResource(R.string.label_recent_manga),
|
||||
title = localize(MR.strings.label_recent_manga),
|
||||
icon = rememberAnimatedVectorPainter(image, isSelected),
|
||||
)
|
||||
}
|
||||
@@ -101,9 +103,9 @@ object HistoryTab : Tab {
|
||||
screenModel.events.collectLatest { e ->
|
||||
when (e) {
|
||||
HistoryScreenModel.Event.InternalError ->
|
||||
snackbarHostState.showSnackbar(context.getString(R.string.internal_error))
|
||||
snackbarHostState.showSnackbar(context.localize(MR.strings.internal_error))
|
||||
HistoryScreenModel.Event.HistoryCleared ->
|
||||
snackbarHostState.showSnackbar(context.getString(R.string.clear_history_completed))
|
||||
snackbarHostState.showSnackbar(context.localize(MR.strings.clear_history_completed))
|
||||
is HistoryScreenModel.Event.OpenChapter -> openChapter(context, e.chapter)
|
||||
}
|
||||
}
|
||||
@@ -121,7 +123,7 @@ object HistoryTab : Tab {
|
||||
val intent = ReaderActivity.newIntent(context, chapter.mangaId, chapter.id)
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
snackbarHostState.showSnackbar(context.getString(R.string.no_next_chapter))
|
||||
snackbarHostState.showSnackbar(context.localize(MR.strings.no_next_chapter))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
@@ -37,7 +36,6 @@ import cafe.adriel.voyager.navigator.tab.TabNavigator
|
||||
import eu.kanade.domain.source.service.SourcePreferences
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.presentation.util.isTabletUi
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.BrowseTab
|
||||
import eu.kanade.tachiyomi.ui.download.DownloadQueueScreen
|
||||
import eu.kanade.tachiyomi.ui.history.HistoryTab
|
||||
@@ -53,9 +51,11 @@ import kotlinx.coroutines.launch
|
||||
import soup.compose.material.motion.animation.materialFadeThroughIn
|
||||
import soup.compose.material.motion.animation.materialFadeThroughOut
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.NavigationBar
|
||||
import tachiyomi.presentation.core.components.material.NavigationRail
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.i18n.localizePlural
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@@ -241,8 +241,8 @@ object HomeScreen : Screen() {
|
||||
}
|
||||
if (count > 0) {
|
||||
Badge {
|
||||
val desc = pluralStringResource(
|
||||
id = R.plurals.notification_chapters_generic,
|
||||
val desc = localizePlural(
|
||||
MR.plurals.notification_chapters_generic,
|
||||
count = count,
|
||||
count,
|
||||
)
|
||||
@@ -260,8 +260,8 @@ object HomeScreen : Screen() {
|
||||
}
|
||||
if (count > 0) {
|
||||
Badge {
|
||||
val desc = pluralStringResource(
|
||||
id = R.plurals.update_check_notification_ext_updates,
|
||||
val desc = localizePlural(
|
||||
MR.plurals.update_check_notification_ext_updates,
|
||||
count = count,
|
||||
count,
|
||||
)
|
||||
|
||||
@@ -7,7 +7,6 @@ import androidx.compose.animation.graphics.vector.AnimatedImageVector
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
||||
import androidx.compose.material.icons.outlined.HelpOutline
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -21,7 +20,6 @@ import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.util.fastAll
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
@@ -49,11 +47,14 @@ import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
import tachiyomi.domain.category.model.Category
|
||||
import tachiyomi.domain.library.model.LibraryManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
import tachiyomi.presentation.core.screens.EmptyScreen
|
||||
import tachiyomi.presentation.core.screens.EmptyScreenAction
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
@@ -68,7 +69,7 @@ object LibraryTab : Tab {
|
||||
val image = AnimatedImageVector.animatedVectorResource(R.drawable.anim_library_enter)
|
||||
return TabOptions(
|
||||
index = 0u,
|
||||
title = stringResource(R.string.label_library),
|
||||
title = localize(MR.strings.label_library),
|
||||
icon = rememberAnimatedVectorPainter(image, isSelected),
|
||||
)
|
||||
}
|
||||
@@ -94,11 +95,11 @@ object LibraryTab : Tab {
|
||||
val started = LibraryUpdateJob.startNow(context, category)
|
||||
scope.launch {
|
||||
val msgRes = when {
|
||||
!started -> R.string.update_already_running
|
||||
category != null -> R.string.updating_category
|
||||
else -> R.string.updating_library
|
||||
!started -> MR.strings.update_already_running
|
||||
category != null -> MR.strings.updating_category
|
||||
else -> MR.strings.updating_library
|
||||
}
|
||||
snackbarHostState.showSnackbar(context.getString(msgRes))
|
||||
snackbarHostState.showSnackbar(context.localize(msgRes))
|
||||
}
|
||||
started
|
||||
}
|
||||
@@ -106,8 +107,8 @@ object LibraryTab : Tab {
|
||||
Scaffold(
|
||||
topBar = { scrollBehavior ->
|
||||
val title = state.getToolbarTitle(
|
||||
defaultTitle = stringResource(R.string.label_library),
|
||||
defaultCategoryTitle = stringResource(R.string.label_default),
|
||||
defaultTitle = localize(MR.strings.label_library),
|
||||
defaultCategoryTitle = localize(MR.strings.label_default),
|
||||
page = screenModel.activeCategoryIndex,
|
||||
)
|
||||
val tabVisible = state.showCategoryTabs && state.categories.size > 1
|
||||
@@ -127,7 +128,9 @@ object LibraryTab : Tab {
|
||||
if (randomItem != null) {
|
||||
navigator.push(MangaScreen(randomItem.libraryManga.manga.id))
|
||||
} else {
|
||||
snackbarHostState.showSnackbar(context.getString(R.string.information_no_entries_found))
|
||||
snackbarHostState.showSnackbar(
|
||||
context.localize(MR.strings.information_no_entries_found),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -154,11 +157,11 @@ object LibraryTab : Tab {
|
||||
state.searchQuery.isNullOrEmpty() && !state.hasActiveFilters && state.isLibraryEmpty -> {
|
||||
val handler = LocalUriHandler.current
|
||||
EmptyScreen(
|
||||
textResource = R.string.information_empty_library,
|
||||
stringRes = MR.strings.information_empty_library,
|
||||
modifier = Modifier.padding(contentPadding),
|
||||
actions = persistentListOf(
|
||||
EmptyScreenAction(
|
||||
stringResId = R.string.getting_started_guide,
|
||||
stringRes = MR.strings.getting_started_guide,
|
||||
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
onClick = { handler.openUri("https://tachiyomi.org/docs/guides/getting-started") },
|
||||
),
|
||||
@@ -184,7 +187,7 @@ object LibraryTab : Tab {
|
||||
ReaderActivity.newIntent(context, chapter.mangaId, chapter.id),
|
||||
)
|
||||
} else {
|
||||
snackbarHostState.showSnackbar(context.getString(R.string.no_next_chapter))
|
||||
snackbarHostState.showSnackbar(context.localize(MR.strings.no_next_chapter))
|
||||
}
|
||||
}
|
||||
Unit
|
||||
|
||||
@@ -34,7 +34,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.luminance
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.animation.doOnEnd
|
||||
import androidx.core.net.toUri
|
||||
@@ -61,7 +60,6 @@ import eu.kanade.presentation.util.AssistContentScreen
|
||||
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.Migrations
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||
import eu.kanade.tachiyomi.data.download.DownloadCache
|
||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||
@@ -93,7 +91,9 @@ import tachiyomi.core.util.lang.launchIO
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.library.service.LibraryPreferences
|
||||
import tachiyomi.domain.release.interactor.GetApplicationRelease
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@@ -257,15 +257,15 @@ class MainActivity : BaseActivity() {
|
||||
if (showChangelog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showChangelog = false },
|
||||
title = { Text(text = stringResource(R.string.updated_version, BuildConfig.VERSION_NAME)) },
|
||||
title = { Text(text = localize(MR.strings.updated_version, BuildConfig.VERSION_NAME)) },
|
||||
dismissButton = {
|
||||
TextButton(onClick = { openInBrowser(RELEASE_URL) }) {
|
||||
Text(text = stringResource(R.string.whats_new))
|
||||
Text(text = localize(MR.strings.whats_new))
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = { showChangelog = false }) {
|
||||
Text(text = stringResource(R.string.action_ok))
|
||||
Text(text = localize(MR.strings.action_ok))
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@@ -9,7 +9,6 @@ import coil.imageLoader
|
||||
import coil.request.ImageRequest
|
||||
import coil.size.Size
|
||||
import eu.kanade.domain.manga.interactor.UpdateManga
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.saver.Image
|
||||
import eu.kanade.tachiyomi.data.saver.ImageSaver
|
||||
@@ -20,12 +19,14 @@ import eu.kanade.tachiyomi.util.system.toShareIntent
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
import tachiyomi.core.util.lang.withIOContext
|
||||
import tachiyomi.core.util.lang.withUIContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.manga.interactor.GetManga
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@@ -51,13 +52,13 @@ class MangaCoverScreenModel(
|
||||
try {
|
||||
saveCoverInternal(context, temp = false)
|
||||
snackbarHostState.showSnackbar(
|
||||
context.getString(R.string.cover_saved),
|
||||
context.localize(MR.strings.cover_saved),
|
||||
withDismissAction = true,
|
||||
)
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
snackbarHostState.showSnackbar(
|
||||
context.getString(R.string.error_saving_cover),
|
||||
context.localize(MR.strings.error_saving_cover),
|
||||
withDismissAction = true,
|
||||
)
|
||||
}
|
||||
@@ -74,7 +75,7 @@ class MangaCoverScreenModel(
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
snackbarHostState.showSnackbar(
|
||||
context.getString(R.string.error_sharing_cover),
|
||||
context.localize(MR.strings.error_sharing_cover),
|
||||
withDismissAction = true,
|
||||
)
|
||||
}
|
||||
@@ -145,7 +146,7 @@ class MangaCoverScreenModel(
|
||||
private fun notifyCoverUpdated(context: Context) {
|
||||
screenModelScope.launch {
|
||||
snackbarHostState.showSnackbar(
|
||||
context.getString(R.string.cover_updated),
|
||||
context.localize(MR.strings.cover_updated),
|
||||
withDismissAction = true,
|
||||
)
|
||||
}
|
||||
@@ -154,7 +155,7 @@ class MangaCoverScreenModel(
|
||||
private fun notifyFailedCoverUpdate(context: Context, e: Throwable) {
|
||||
screenModelScope.launch {
|
||||
snackbarHostState.showSnackbar(
|
||||
context.getString(R.string.notification_cover_update_failed),
|
||||
context.localize(MR.strings.notification_cover_update_failed),
|
||||
withDismissAction = true,
|
||||
)
|
||||
logcat(LogPriority.ERROR, e)
|
||||
|
||||
@@ -37,7 +37,6 @@ import eu.kanade.presentation.manga.components.SetIntervalDialog
|
||||
import eu.kanade.presentation.util.AssistContentScreen
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.presentation.util.isTabletUi
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.isLocalOrStub
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
@@ -54,10 +53,12 @@ import eu.kanade.tachiyomi.util.system.toShareIntent
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import kotlinx.coroutines.launch
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.lang.withIOContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.chapter.model.Chapter
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
||||
class MangaScreen(
|
||||
@@ -291,7 +292,7 @@ class MangaScreen(
|
||||
context.startActivity(
|
||||
Intent.createChooser(
|
||||
intent,
|
||||
context.getString(R.string.action_share),
|
||||
context.localize(MR.strings.action_share),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import eu.kanade.domain.ui.UiPreferences
|
||||
import eu.kanade.presentation.manga.DownloadAction
|
||||
import eu.kanade.presentation.manga.components.ChapterDownloadAction
|
||||
import eu.kanade.presentation.util.formattedMessage
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.DownloadCache
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
@@ -50,6 +49,7 @@ import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.preference.CheckboxState
|
||||
import tachiyomi.core.preference.TriState
|
||||
import tachiyomi.core.preference.mapAsCheckboxState
|
||||
@@ -78,6 +78,7 @@ import tachiyomi.domain.manga.model.applyFilter
|
||||
import tachiyomi.domain.manga.repository.MangaRepository
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.source.local.isLocal
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@@ -281,8 +282,8 @@ class MangaScreenModel(
|
||||
screenModelScope.launch {
|
||||
if (!hasDownloads()) return@launch
|
||||
val result = snackbarHostState.showSnackbar(
|
||||
message = context.getString(R.string.delete_downloads_for_manga),
|
||||
actionLabel = context.getString(R.string.action_delete),
|
||||
message = context.localize(MR.strings.delete_downloads_for_manga),
|
||||
actionLabel = context.localize(MR.strings.action_delete),
|
||||
withDismissAction = true,
|
||||
)
|
||||
if (result == SnackbarResult.ActionPerformed) {
|
||||
@@ -550,7 +551,7 @@ class MangaScreenModel(
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
val message = if (e is NoChaptersException) {
|
||||
context.getString(R.string.no_chapters_error)
|
||||
context.localize(MR.strings.no_chapters_error)
|
||||
} else {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
with(context) { e.formattedMessage }
|
||||
@@ -647,8 +648,8 @@ class MangaScreenModel(
|
||||
}
|
||||
screenModelScope.launch {
|
||||
val result = snackbarHostState.showSnackbar(
|
||||
message = context.getString(R.string.snack_add_to_library),
|
||||
actionLabel = context.getString(R.string.action_add),
|
||||
message = context.localize(MR.strings.snack_add_to_library),
|
||||
actionLabel = context.localize(MR.strings.action_add),
|
||||
withDismissAction = true,
|
||||
)
|
||||
if (result == SnackbarResult.ActionPerformed && !isFavorited) {
|
||||
@@ -869,7 +870,7 @@ class MangaScreenModel(
|
||||
if (applyToExisting) {
|
||||
setMangaDefaultChapterFlags.awaitAll()
|
||||
}
|
||||
snackbarHostState.showSnackbar(message = context.getString(R.string.chapter_settings_updated))
|
||||
snackbarHostState.showSnackbar(message = context.localize(MR.strings.chapter_settings_updated))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -39,6 +38,7 @@ import cafe.adriel.voyager.core.model.screenModelScope
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.domain.track.interactor.RefreshTracks
|
||||
import eu.kanade.domain.track.model.toDbTrack
|
||||
import eu.kanade.domain.ui.UiPreferences
|
||||
@@ -49,7 +49,6 @@ import eu.kanade.presentation.track.TrackScoreSelector
|
||||
import eu.kanade.presentation.track.TrackStatusSelector
|
||||
import eu.kanade.presentation.track.TrackerSearch
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.track.DeletableTracker
|
||||
import eu.kanade.tachiyomi.data.track.EnhancedTracker
|
||||
import eu.kanade.tachiyomi.data.track.Tracker
|
||||
@@ -66,6 +65,7 @@ import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.lang.launchNonCancellable
|
||||
import tachiyomi.core.util.lang.withIOContext
|
||||
import tachiyomi.core.util.lang.withUIContext
|
||||
@@ -75,9 +75,11 @@ import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.domain.track.interactor.DeleteTrack
|
||||
import tachiyomi.domain.track.interactor.GetTracks
|
||||
import tachiyomi.domain.track.model.Track
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.LabeledCheckbox
|
||||
import tachiyomi.presentation.core.components.material.AlertDialogContent
|
||||
import tachiyomi.presentation.core.components.material.padding
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.Instant
|
||||
@@ -210,7 +212,7 @@ data class TrackInfoDialogHomeScreen(
|
||||
val matchResult = item.tracker.match(manga) ?: throw Exception()
|
||||
item.tracker.register(matchResult, mangaId)
|
||||
} catch (e: Exception) {
|
||||
withUIContext { Injekt.get<Application>().toast(R.string.error_no_match) }
|
||||
withUIContext { Injekt.get<Application>().toast(MR.strings.error_no_match) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -227,10 +229,10 @@ data class TrackInfoDialogHomeScreen(
|
||||
}
|
||||
withUIContext {
|
||||
context.toast(
|
||||
context.getString(
|
||||
R.string.track_error,
|
||||
context.localize(
|
||||
MR.strings.track_error,
|
||||
track!!.name,
|
||||
e.message,
|
||||
e.message ?: "",
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -286,7 +288,7 @@ private data class TrackStatusSelectorScreen(
|
||||
private val tracker: Tracker,
|
||||
) : StateScreenModel<Model.State>(State(track.status.toInt())) {
|
||||
|
||||
fun getSelections(): Map<Int, Int?> {
|
||||
fun getSelections(): Map<Int, StringResource?> {
|
||||
return tracker.getStatusList().associateWith { tracker.getStatus(it) }
|
||||
}
|
||||
|
||||
@@ -500,9 +502,9 @@ private data class TrackDateSelectorScreen(
|
||||
}
|
||||
TrackDateSelector(
|
||||
title = if (start) {
|
||||
stringResource(R.string.track_started_reading_date)
|
||||
localize(MR.strings.track_started_reading_date)
|
||||
} else {
|
||||
stringResource(R.string.track_finished_reading_date)
|
||||
localize(MR.strings.track_finished_reading_date)
|
||||
},
|
||||
initialSelectedDateMillis = screenModel.initialSelection,
|
||||
selectableDates = selectableDates,
|
||||
@@ -575,7 +577,7 @@ private data class TrackDateRemoverScreen(
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(R.string.track_remove_date_conf_title),
|
||||
text = localize(MR.strings.track_remove_date_conf_title),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
},
|
||||
@@ -583,9 +585,9 @@ private data class TrackDateRemoverScreen(
|
||||
val serviceName = screenModel.getServiceName()
|
||||
Text(
|
||||
text = if (start) {
|
||||
stringResource(R.string.track_remove_start_date_conf_text, serviceName)
|
||||
localize(MR.strings.track_remove_start_date_conf_text, serviceName)
|
||||
} else {
|
||||
stringResource(R.string.track_remove_finish_date_conf_text, serviceName)
|
||||
localize(MR.strings.track_remove_finish_date_conf_text, serviceName)
|
||||
},
|
||||
)
|
||||
},
|
||||
@@ -595,7 +597,7 @@ private data class TrackDateRemoverScreen(
|
||||
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small, Alignment.End),
|
||||
) {
|
||||
TextButton(onClick = navigator::pop) {
|
||||
Text(text = stringResource(R.string.action_cancel))
|
||||
Text(text = localize(MR.strings.action_cancel))
|
||||
}
|
||||
FilledTonalButton(
|
||||
onClick = {
|
||||
@@ -607,7 +609,7 @@ private data class TrackDateRemoverScreen(
|
||||
contentColor = MaterialTheme.colorScheme.onErrorContainer,
|
||||
),
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_remove))
|
||||
Text(text = localize(MR.strings.action_remove))
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -751,7 +753,7 @@ private data class TrackerRemoveScreen(
|
||||
},
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(R.string.track_delete_title, serviceName),
|
||||
text = localize(MR.strings.track_delete_title, serviceName),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
},
|
||||
@@ -760,12 +762,12 @@ private data class TrackerRemoveScreen(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.track_delete_text, serviceName),
|
||||
text = localize(MR.strings.track_delete_text, serviceName),
|
||||
)
|
||||
|
||||
if (screenModel.isDeletable()) {
|
||||
LabeledCheckbox(
|
||||
label = stringResource(R.string.track_delete_remote_text, serviceName),
|
||||
label = localize(MR.strings.track_delete_remote_text, serviceName),
|
||||
checked = removeRemoteTrack,
|
||||
onCheckedChange = { removeRemoteTrack = it },
|
||||
)
|
||||
@@ -781,7 +783,7 @@ private data class TrackerRemoveScreen(
|
||||
),
|
||||
) {
|
||||
TextButton(onClick = navigator::pop) {
|
||||
Text(text = stringResource(R.string.action_cancel))
|
||||
Text(text = localize(MR.strings.action_cancel))
|
||||
}
|
||||
FilledTonalButton(
|
||||
onClick = {
|
||||
@@ -794,7 +796,7 @@ private data class TrackerRemoveScreen(
|
||||
contentColor = MaterialTheme.colorScheme.onErrorContainer,
|
||||
),
|
||||
) {
|
||||
Text(text = stringResource(R.string.action_ok))
|
||||
Text(text = localize(MR.strings.action_ok))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -8,7 +8,6 @@ import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.core.model.screenModelScope
|
||||
@@ -34,6 +33,8 @@ import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
@@ -46,7 +47,7 @@ object MoreTab : Tab {
|
||||
val image = AnimatedImageVector.animatedVectorResource(R.drawable.anim_more_enter)
|
||||
return TabOptions(
|
||||
index = 4u,
|
||||
title = stringResource(R.string.label_more),
|
||||
title = localize(MR.strings.label_more),
|
||||
icon = rememberAnimatedVectorPainter(image, isSelected),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.net.toUri
|
||||
@@ -85,11 +84,13 @@ import kotlinx.coroutines.flow.sample
|
||||
import kotlinx.coroutines.launch
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.Constants
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.lang.launchIO
|
||||
import tachiyomi.core.util.lang.launchNonCancellable
|
||||
import tachiyomi.core.util.lang.withUIContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.util.collectAsState
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
@@ -372,7 +373,7 @@ class ReaderActivity : BaseActivity() {
|
||||
onClickCropBorder = {
|
||||
val enabled = viewModel.toggleCropBorders()
|
||||
menuToggleToast?.cancel()
|
||||
menuToggleToast = toast(if (enabled) R.string.on else R.string.off)
|
||||
menuToggleToast = toast(if (enabled) MR.strings.on else MR.strings.off)
|
||||
},
|
||||
onClickSettings = viewModel::openSettingsDialog,
|
||||
)
|
||||
@@ -399,7 +400,7 @@ class ReaderActivity : BaseActivity() {
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
CircularProgressIndicator()
|
||||
Text(stringResource(R.string.loading))
|
||||
Text(localize(MR.strings.loading))
|
||||
}
|
||||
},
|
||||
)
|
||||
@@ -536,7 +537,7 @@ class ReaderActivity : BaseActivity() {
|
||||
private fun shareChapter() {
|
||||
assistUrl?.let {
|
||||
val intent = it.toUri().toShareIntent(this, type = "text/plain")
|
||||
startActivity(Intent.createChooser(intent, getString(R.string.action_share)))
|
||||
startActivity(Intent.createChooser(intent, localize(MR.strings.action_share)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,9 +684,9 @@ class ReaderActivity : BaseActivity() {
|
||||
|
||||
val intent = uri.toShareIntent(
|
||||
context = applicationContext,
|
||||
message = getString(R.string.share_page_info, manga.title, chapter.name, page.number),
|
||||
message = localize(MR.strings.share_page_info, manga.title, chapter.name, page.number),
|
||||
)
|
||||
startActivity(Intent.createChooser(intent, getString(R.string.action_share)))
|
||||
startActivity(Intent.createChooser(intent, localize(MR.strings.action_share)))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -695,7 +696,7 @@ class ReaderActivity : BaseActivity() {
|
||||
private fun onSaveImageResult(result: ReaderViewModel.SaveImageResult) {
|
||||
when (result) {
|
||||
is ReaderViewModel.SaveImageResult.Success -> {
|
||||
toast(R.string.picture_saved)
|
||||
toast(MR.strings.picture_saved)
|
||||
}
|
||||
is ReaderViewModel.SaveImageResult.Error -> {
|
||||
logcat(LogPriority.ERROR, result.error)
|
||||
@@ -710,9 +711,9 @@ class ReaderActivity : BaseActivity() {
|
||||
private fun onSetAsCoverResult(result: ReaderViewModel.SetAsCoverResult) {
|
||||
toast(
|
||||
when (result) {
|
||||
Success -> R.string.cover_updated
|
||||
AddToLibraryFirst -> R.string.notification_first_add_to_library
|
||||
Error -> R.string.notification_cover_update_failed
|
||||
Success -> MR.strings.cover_updated
|
||||
AddToLibraryFirst -> MR.strings.notification_first_add_to_library
|
||||
Error -> MR.strings.notification_cover_update_failed
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.core.graphics.withTranslation
|
||||
import androidx.core.view.isVisible
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.DisabledNavigation
|
||||
import tachiyomi.core.i18n.localize
|
||||
import kotlin.math.abs
|
||||
|
||||
class ReaderNavigationOverlayView(context: Context, attributeSet: AttributeSet) : View(context, attributeSet) {
|
||||
@@ -79,8 +80,8 @@ class ReaderNavigationOverlayView(context: Context, attributeSet: AttributeSet)
|
||||
// Calculate center of rect height on screen
|
||||
val y = height * (abs(rect.top - rect.bottom) / 2)
|
||||
|
||||
drawText(context.getString(region.type.nameRes), x, y, textBorderPaint)
|
||||
drawText(context.getString(region.type.nameRes), x, y, textPaint)
|
||||
drawText(context.localize(region.type.nameRes), x, y, textBorderPaint)
|
||||
drawText(context.localize(region.type.nameRes), x, y, textPaint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ import eu.kanade.tachiyomi.util.system.cancelNotification
|
||||
import eu.kanade.tachiyomi.util.system.getBitmapOrNull
|
||||
import eu.kanade.tachiyomi.util.system.notificationBuilder
|
||||
import eu.kanade.tachiyomi.util.system.notify
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
/**
|
||||
* Class used to show BigPictureStyle notifications
|
||||
@@ -56,8 +58,8 @@ class SaveImageNotifier(private val context: Context) {
|
||||
fun onError(error: String?) {
|
||||
// Create notification
|
||||
with(notificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.download_notifier_title_error))
|
||||
setContentText(error ?: context.getString(R.string.unknown_error))
|
||||
setContentTitle(context.localize(MR.strings.download_notifier_title_error))
|
||||
setContentText(error ?: context.localize(MR.strings.unknown_error))
|
||||
setSmallIcon(android.R.drawable.ic_menu_report_image)
|
||||
}
|
||||
updateNotification()
|
||||
@@ -65,7 +67,7 @@ class SaveImageNotifier(private val context: Context) {
|
||||
|
||||
private fun showCompleteNotification(uri: Uri, image: Bitmap?) {
|
||||
with(notificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.picture_saved))
|
||||
setContentTitle(context.localize(MR.strings.picture_saved))
|
||||
setSmallIcon(R.drawable.ic_photo_24dp)
|
||||
image?.let { setStyle(NotificationCompat.BigPictureStyle().bigPicture(it)) }
|
||||
setLargeIcon(image)
|
||||
@@ -78,13 +80,13 @@ class SaveImageNotifier(private val context: Context) {
|
||||
// Share action
|
||||
addAction(
|
||||
R.drawable.ic_share_24dp,
|
||||
context.getString(R.string.action_share),
|
||||
context.localize(MR.strings.action_share),
|
||||
NotificationReceiver.shareImagePendingBroadcast(context, uri.path!!, notificationId),
|
||||
)
|
||||
// Delete action
|
||||
addAction(
|
||||
R.drawable.ic_delete_24dp,
|
||||
context.getString(R.string.action_delete),
|
||||
context.localize(MR.strings.action_delete),
|
||||
NotificationReceiver.deleteImagePendingBroadcast(context, uri.path!!, notificationId),
|
||||
)
|
||||
|
||||
|
||||
@@ -2,16 +2,17 @@ package eu.kanade.tachiyomi.ui.reader.loader
|
||||
|
||||
import android.content.Context
|
||||
import com.github.junrar.exception.UnsupportedRarV5Exception
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.DownloadProvider
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.lang.withIOContext
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.manga.model.Manga
|
||||
import tachiyomi.domain.source.model.StubSource
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.source.local.LocalSource
|
||||
import tachiyomi.source.local.io.Format
|
||||
|
||||
@@ -46,7 +47,7 @@ class ChapterLoader(
|
||||
.onEach { it.chapter = chapter }
|
||||
|
||||
if (pages.isEmpty()) {
|
||||
throw Exception(context.getString(R.string.page_list_empty_error))
|
||||
throw Exception(context.localize(MR.strings.page_list_empty_error))
|
||||
}
|
||||
|
||||
// If the chapter is partially read, set the starting page to the last the user read
|
||||
@@ -91,14 +92,14 @@ class ChapterLoader(
|
||||
is Format.Rar -> try {
|
||||
RarPageLoader(format.file)
|
||||
} catch (e: UnsupportedRarV5Exception) {
|
||||
error(context.getString(R.string.loader_rar5_error))
|
||||
error(context.localize(MR.strings.loader_rar5_error))
|
||||
}
|
||||
is Format.Epub -> EpubPageLoader(format.file)
|
||||
}
|
||||
}
|
||||
source is HttpSource -> HttpPageLoader(chapter, source)
|
||||
source is StubSource -> error(context.getString(R.string.source_not_installed, source.toString()))
|
||||
else -> error(context.getString(R.string.loader_not_implemented_error))
|
||||
source is StubSource -> error(context.localize(MR.strings.source_not_installed, source.toString()))
|
||||
else -> error(context.localize(MR.strings.loader_not_implemented_error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,54 +2,55 @@ package eu.kanade.tachiyomi.ui.reader.setting
|
||||
|
||||
import android.content.pm.ActivityInfo
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
enum class ReaderOrientation(
|
||||
val flag: Int,
|
||||
@StringRes val stringRes: Int,
|
||||
val stringRes: StringResource,
|
||||
@DrawableRes val iconRes: Int,
|
||||
val flagValue: Int,
|
||||
) {
|
||||
DEFAULT(
|
||||
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
|
||||
R.string.label_default,
|
||||
MR.strings.label_default,
|
||||
R.drawable.ic_screen_rotation_24dp,
|
||||
0x00000000,
|
||||
),
|
||||
FREE(
|
||||
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED,
|
||||
R.string.rotation_free,
|
||||
MR.strings.rotation_free,
|
||||
R.drawable.ic_screen_rotation_24dp,
|
||||
0x00000008,
|
||||
),
|
||||
PORTRAIT(
|
||||
ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT,
|
||||
R.string.rotation_portrait,
|
||||
MR.strings.rotation_portrait,
|
||||
R.drawable.ic_stay_current_portrait_24dp,
|
||||
0x00000010,
|
||||
),
|
||||
LANDSCAPE(
|
||||
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE,
|
||||
R.string.rotation_landscape,
|
||||
MR.strings.rotation_landscape,
|
||||
R.drawable.ic_stay_current_landscape_24dp,
|
||||
0x00000018,
|
||||
),
|
||||
LOCKED_PORTRAIT(
|
||||
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
|
||||
R.string.rotation_force_portrait,
|
||||
MR.strings.rotation_force_portrait,
|
||||
R.drawable.ic_screen_lock_portrait_24dp,
|
||||
0x00000020,
|
||||
),
|
||||
LOCKED_LANDSCAPE(
|
||||
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
|
||||
R.string.rotation_force_landscape,
|
||||
MR.strings.rotation_force_landscape,
|
||||
R.drawable.ic_screen_lock_landscape_24dp,
|
||||
0x00000028,
|
||||
),
|
||||
REVERSE_PORTRAIT(
|
||||
ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT,
|
||||
R.string.rotation_reverse_portrait,
|
||||
MR.strings.rotation_reverse_portrait,
|
||||
R.drawable.ic_stay_current_portrait_24dp,
|
||||
0x00000030,
|
||||
),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.setting
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import eu.kanade.tachiyomi.R
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import tachiyomi.core.preference.PreferenceStore
|
||||
import tachiyomi.core.preference.getEnum
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
class ReaderPreferences(
|
||||
private val preferenceStore: PreferenceStore,
|
||||
@@ -129,14 +129,14 @@ class ReaderPreferences(
|
||||
// endregion
|
||||
|
||||
enum class TappingInvertMode(
|
||||
@StringRes val titleResId: Int,
|
||||
val titleRes: StringResource,
|
||||
val shouldInvertHorizontal: Boolean = false,
|
||||
val shouldInvertVertical: Boolean = false,
|
||||
) {
|
||||
NONE(R.string.tapping_inverted_none),
|
||||
HORIZONTAL(R.string.tapping_inverted_horizontal, shouldInvertHorizontal = true),
|
||||
VERTICAL(R.string.tapping_inverted_vertical, shouldInvertVertical = true),
|
||||
BOTH(R.string.tapping_inverted_both, shouldInvertHorizontal = true, shouldInvertVertical = true),
|
||||
NONE(MR.strings.tapping_inverted_none),
|
||||
HORIZONTAL(MR.strings.tapping_inverted_horizontal, shouldInvertHorizontal = true),
|
||||
VERTICAL(MR.strings.tapping_inverted_vertical, shouldInvertVertical = true),
|
||||
BOTH(MR.strings.tapping_inverted_both, shouldInvertHorizontal = true, shouldInvertVertical = true),
|
||||
}
|
||||
|
||||
enum class ReaderHideThreshold(val threshold: Int) {
|
||||
@@ -151,28 +151,28 @@ class ReaderPreferences(
|
||||
const val WEBTOON_PADDING_MAX = 25
|
||||
|
||||
val TapZones = listOf(
|
||||
R.string.label_default,
|
||||
R.string.l_nav,
|
||||
R.string.kindlish_nav,
|
||||
R.string.edge_nav,
|
||||
R.string.right_and_left_nav,
|
||||
R.string.disabled_nav,
|
||||
MR.strings.label_default,
|
||||
MR.strings.l_nav,
|
||||
MR.strings.kindlish_nav,
|
||||
MR.strings.edge_nav,
|
||||
MR.strings.right_and_left_nav,
|
||||
MR.strings.disabled_nav,
|
||||
)
|
||||
|
||||
val ImageScaleType = listOf(
|
||||
R.string.scale_type_fit_screen,
|
||||
R.string.scale_type_stretch,
|
||||
R.string.scale_type_fit_width,
|
||||
R.string.scale_type_fit_height,
|
||||
R.string.scale_type_original_size,
|
||||
R.string.scale_type_smart_fit,
|
||||
MR.strings.scale_type_fit_screen,
|
||||
MR.strings.scale_type_stretch,
|
||||
MR.strings.scale_type_fit_width,
|
||||
MR.strings.scale_type_fit_height,
|
||||
MR.strings.scale_type_original_size,
|
||||
MR.strings.scale_type_smart_fit,
|
||||
)
|
||||
|
||||
val ZoomStart = listOf(
|
||||
R.string.zoom_start_automatic,
|
||||
R.string.zoom_start_left,
|
||||
R.string.zoom_start_right,
|
||||
R.string.zoom_start_center,
|
||||
MR.strings.zoom_start_automatic,
|
||||
MR.strings.zoom_start_left,
|
||||
MR.strings.zoom_start_right,
|
||||
MR.strings.zoom_start_center,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.setting
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.Viewer
|
||||
@@ -9,45 +9,46 @@ import eu.kanade.tachiyomi.ui.reader.viewer.pager.L2RPagerViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.R2LPagerViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.VerticalPagerViewer
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
enum class ReadingMode(
|
||||
@StringRes val stringRes: Int,
|
||||
val stringRes: StringResource,
|
||||
@DrawableRes val iconRes: Int,
|
||||
val flagValue: Int,
|
||||
val direction: Direction? = null,
|
||||
val type: ViewerType? = null,
|
||||
) {
|
||||
DEFAULT(R.string.label_default, R.drawable.ic_reader_default_24dp, 0x00000000),
|
||||
DEFAULT(MR.strings.label_default, R.drawable.ic_reader_default_24dp, 0x00000000),
|
||||
LEFT_TO_RIGHT(
|
||||
R.string.left_to_right_viewer,
|
||||
MR.strings.left_to_right_viewer,
|
||||
R.drawable.ic_reader_ltr_24dp,
|
||||
0x00000001,
|
||||
Direction.Horizontal,
|
||||
ViewerType.Pager,
|
||||
),
|
||||
RIGHT_TO_LEFT(
|
||||
R.string.right_to_left_viewer,
|
||||
MR.strings.right_to_left_viewer,
|
||||
R.drawable.ic_reader_rtl_24dp,
|
||||
0x00000002,
|
||||
Direction.Horizontal,
|
||||
ViewerType.Pager,
|
||||
),
|
||||
VERTICAL(
|
||||
R.string.vertical_viewer,
|
||||
MR.strings.vertical_viewer,
|
||||
R.drawable.ic_reader_vertical_24dp,
|
||||
0x00000003,
|
||||
Direction.Vertical,
|
||||
ViewerType.Pager,
|
||||
),
|
||||
WEBTOON(
|
||||
R.string.webtoon_viewer,
|
||||
MR.strings.webtoon_viewer,
|
||||
R.drawable.ic_reader_webtoon_24dp,
|
||||
0x00000004,
|
||||
Direction.Vertical,
|
||||
ViewerType.Webtoon,
|
||||
),
|
||||
CONTINUOUS_VERTICAL(
|
||||
R.string.vertical_plus_viewer,
|
||||
MR.strings.vertical_plus_viewer,
|
||||
R.drawable.ic_reader_continuous_vertical_24dp,
|
||||
0x00000005,
|
||||
Direction.Vertical,
|
||||
|
||||
@@ -3,19 +3,19 @@ package eu.kanade.tachiyomi.ui.reader.viewer
|
||||
import android.graphics.Color
|
||||
import android.graphics.PointF
|
||||
import android.graphics.RectF
|
||||
import androidx.annotation.StringRes
|
||||
import eu.kanade.tachiyomi.R
|
||||
import dev.icerock.moko.resources.StringResource
|
||||
import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import eu.kanade.tachiyomi.util.lang.invert
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
abstract class ViewerNavigation {
|
||||
|
||||
sealed class NavigationRegion(@StringRes val nameRes: Int, val color: Int) {
|
||||
data object MENU : NavigationRegion(R.string.action_menu, Color.argb(0xCC, 0x95, 0x81, 0x8D))
|
||||
data object PREV : NavigationRegion(R.string.nav_zone_prev, Color.argb(0xCC, 0xFF, 0x77, 0x33))
|
||||
data object NEXT : NavigationRegion(R.string.nav_zone_next, Color.argb(0xCC, 0x84, 0xE2, 0x96))
|
||||
data object LEFT : NavigationRegion(R.string.nav_zone_left, Color.argb(0xCC, 0x7D, 0x11, 0x28))
|
||||
data object RIGHT : NavigationRegion(R.string.nav_zone_right, Color.argb(0xCC, 0xA6, 0xCF, 0xD5))
|
||||
sealed class NavigationRegion(val nameRes: StringResource, val color: Int) {
|
||||
data object MENU : NavigationRegion(MR.strings.action_menu, Color.argb(0xCC, 0x95, 0x81, 0x8D))
|
||||
data object PREV : NavigationRegion(MR.strings.nav_zone_prev, Color.argb(0xCC, 0xFF, 0x77, 0x33))
|
||||
data object NEXT : NavigationRegion(MR.strings.nav_zone_next, Color.argb(0xCC, 0x84, 0xE2, 0x96))
|
||||
data object LEFT : NavigationRegion(MR.strings.nav_zone_left, Color.argb(0xCC, 0x7D, 0x11, 0x28))
|
||||
data object RIGHT : NavigationRegion(MR.strings.nav_zone_right, Color.argb(0xCC, 0xA6, 0xCF, 0xD5))
|
||||
}
|
||||
|
||||
data class Region(
|
||||
|
||||
+5
-4
@@ -10,7 +10,6 @@ import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderButton
|
||||
@@ -21,6 +20,8 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
/**
|
||||
* View of the ViewPager that contains a chapter transition.
|
||||
@@ -104,7 +105,7 @@ class PagerTransitionHolder(
|
||||
|
||||
val textView = AppCompatTextView(context).apply {
|
||||
wrapContent()
|
||||
setText(R.string.transition_pages_loading)
|
||||
text = context.localize(MR.strings.transition_pages_loading)
|
||||
}
|
||||
|
||||
pagesContainer.addView(progress)
|
||||
@@ -117,13 +118,13 @@ class PagerTransitionHolder(
|
||||
private fun setError(error: Throwable) {
|
||||
val textView = AppCompatTextView(context).apply {
|
||||
wrapContent()
|
||||
text = context.getString(R.string.transition_pages_error, error.message)
|
||||
text = context.localize(MR.strings.transition_pages_error, error.message ?: "")
|
||||
}
|
||||
|
||||
val retryBtn = ReaderButton(context).apply {
|
||||
viewer = this@PagerTransitionHolder.viewer
|
||||
wrapContent()
|
||||
setText(R.string.action_retry)
|
||||
text = context.localize(MR.strings.action_retry)
|
||||
setOnClickListener {
|
||||
val toChapter = transition.to
|
||||
if (toChapter != null) {
|
||||
|
||||
+5
-4
@@ -9,7 +9,6 @@ import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.core.view.isNotEmpty
|
||||
import androidx.core.view.isVisible
|
||||
import com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ReaderTransitionView
|
||||
@@ -18,6 +17,8 @@ import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.launch
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
/**
|
||||
* Holder of the webtoon viewer that contains a chapter transition.
|
||||
@@ -106,7 +107,7 @@ class WebtoonTransitionHolder(
|
||||
|
||||
val textView = AppCompatTextView(context).apply {
|
||||
wrapContent()
|
||||
setText(R.string.transition_pages_loading)
|
||||
text = context.localize(MR.strings.transition_pages_loading)
|
||||
}
|
||||
|
||||
pagesContainer.addView(progress)
|
||||
@@ -119,12 +120,12 @@ class WebtoonTransitionHolder(
|
||||
private fun setError(error: Throwable, transition: ChapterTransition) {
|
||||
val textView = AppCompatTextView(context).apply {
|
||||
wrapContent()
|
||||
text = context.getString(R.string.transition_pages_error, error.message)
|
||||
text = context.localize(MR.strings.transition_pages_error, error.message ?: "")
|
||||
}
|
||||
|
||||
val retryBtn = AppCompatButton(context).apply {
|
||||
wrapContent()
|
||||
setText(R.string.action_retry)
|
||||
text = context.localize(MR.strings.action_retry)
|
||||
setOnClickListener {
|
||||
val toChapter = transition.to
|
||||
if (toChapter != null) {
|
||||
|
||||
@@ -3,13 +3,14 @@ package eu.kanade.tachiyomi.ui.security
|
||||
import android.os.Bundle
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
||||
import eu.kanade.tachiyomi.ui.base.delegate.SecureActivityDelegate
|
||||
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil
|
||||
import eu.kanade.tachiyomi.util.system.AuthenticatorUtil.startAuthentication
|
||||
import logcat.LogPriority
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.i18n.MR
|
||||
|
||||
/**
|
||||
* Blank activity with a BiometricPrompt.
|
||||
@@ -19,7 +20,7 @@ class UnlockActivity : BaseActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
startAuthentication(
|
||||
getString(R.string.unlock_app_title, getString(R.string.app_name)),
|
||||
localize(MR.strings.unlock_app_title, localize(MR.strings.app_name)),
|
||||
confirmationRequired = false,
|
||||
callback = object : AuthenticatorUtil.AuthenticationCallback() {
|
||||
override fun onAuthenticationError(
|
||||
|
||||
@@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.stats
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
@@ -11,8 +10,9 @@ import eu.kanade.presentation.components.AppBar
|
||||
import eu.kanade.presentation.more.stats.StatsScreenContent
|
||||
import eu.kanade.presentation.more.stats.StatsScreenState
|
||||
import eu.kanade.presentation.util.Screen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.components.material.Scaffold
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
import tachiyomi.presentation.core.screens.LoadingScreen
|
||||
|
||||
class StatsScreen : Screen() {
|
||||
@@ -27,7 +27,7 @@ class StatsScreen : Screen() {
|
||||
Scaffold(
|
||||
topBar = { scrollBehavior ->
|
||||
AppBar(
|
||||
title = stringResource(R.string.label_stats),
|
||||
title = localize(MR.strings.label_stats),
|
||||
navigateUp = navigator::pop,
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
|
||||
@@ -9,7 +9,6 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.core.model.rememberScreenModel
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
@@ -27,6 +26,9 @@ import eu.kanade.tachiyomi.ui.manga.MangaScreen
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.ui.updates.UpdatesScreenModel.Event
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.i18n.MR
|
||||
import tachiyomi.presentation.core.i18n.localize
|
||||
|
||||
object UpdatesTab : Tab {
|
||||
|
||||
@@ -37,7 +39,7 @@ object UpdatesTab : Tab {
|
||||
val image = AnimatedImageVector.animatedVectorResource(R.drawable.anim_updates_enter)
|
||||
return TabOptions(
|
||||
index = 1u,
|
||||
title = stringResource(R.string.label_recent_updates),
|
||||
title = localize(MR.strings.label_recent_updates),
|
||||
icon = rememberAnimatedVectorPainter(image, isSelected),
|
||||
)
|
||||
}
|
||||
@@ -88,15 +90,15 @@ object UpdatesTab : Tab {
|
||||
screenModel.events.collectLatest { event ->
|
||||
when (event) {
|
||||
Event.InternalError -> screenModel.snackbarHostState.showSnackbar(
|
||||
context.getString(R.string.internal_error),
|
||||
context.localize(MR.strings.internal_error),
|
||||
)
|
||||
is Event.LibraryUpdateTriggered -> {
|
||||
val msg = if (event.started) {
|
||||
R.string.updating_library
|
||||
MR.strings.updating_library
|
||||
} else {
|
||||
R.string.update_already_running
|
||||
MR.strings.update_already_running
|
||||
}
|
||||
screenModel.snackbarHostState.showSnackbar(context.getString(msg))
|
||||
screenModel.snackbarHostState.showSnackbar(context.localize(msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import logcat.LogPriority
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.domain.source.service.SourceManager
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
class WebViewActivity : BaseActivity() {
|
||||
@@ -38,7 +39,7 @@ class WebViewActivity : BaseActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (!WebViewUtil.supportsWebView(this)) {
|
||||
toast(R.string.information_webview_required, Toast.LENGTH_LONG)
|
||||
toast(MR.strings.information_webview_required, Toast.LENGTH_LONG)
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package eu.kanade.tachiyomi.util.lang
|
||||
|
||||
import android.content.Context
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.i18n.localizePlural
|
||||
import tachiyomi.i18n.MR
|
||||
import java.text.DateFormat
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
@@ -61,9 +63,9 @@ fun Date.toRelativeString(
|
||||
val days = difference.floorDiv(MILLISECONDS_IN_DAY).toInt()
|
||||
return when {
|
||||
difference < 0 -> dateFormat.format(this)
|
||||
difference < MILLISECONDS_IN_DAY -> context.getString(R.string.relative_time_today)
|
||||
difference < MILLISECONDS_IN_DAY.times(7) -> context.resources.getQuantityString(
|
||||
R.plurals.relative_time,
|
||||
difference < MILLISECONDS_IN_DAY -> context.localize(MR.strings.relative_time_today)
|
||||
difference < MILLISECONDS_IN_DAY.times(7) -> context.localizePlural(
|
||||
MR.plurals.relative_time,
|
||||
days,
|
||||
days,
|
||||
)
|
||||
|
||||
@@ -10,8 +10,9 @@ import androidx.biometric.auth.AuthPromptCallback
|
||||
import androidx.biometric.auth.startClass2BiometricOrCredentialAuthentication
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import eu.kanade.tachiyomi.R
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.i18n.MR
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
object AuthenticatorUtil {
|
||||
@@ -48,7 +49,7 @@ object AuthenticatorUtil {
|
||||
|
||||
suspend fun FragmentActivity.authenticate(
|
||||
title: String,
|
||||
subtitle: String? = getString(R.string.confirm_lock_change),
|
||||
subtitle: String? = localize(MR.strings.confirm_lock_change),
|
||||
): Boolean = suspendCancellableCoroutine { cont ->
|
||||
if (!isAuthenticationSupported()) {
|
||||
cont.resume(true)
|
||||
|
||||
@@ -24,7 +24,9 @@ import eu.kanade.tachiyomi.ui.reader.setting.ReaderPreferences
|
||||
import eu.kanade.tachiyomi.util.lang.truncateCenter
|
||||
import logcat.LogPriority
|
||||
import rikka.sui.Sui
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.core.util.system.logcat
|
||||
import tachiyomi.i18n.MR
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.File
|
||||
@@ -45,11 +47,11 @@ fun Context.copyToClipboard(label: String, content: String) {
|
||||
// Android 13 and higher shows a visual confirmation of copied contents
|
||||
// https://developer.android.com/about/versions/13/features/copy-paste
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
|
||||
toast(getString(R.string.copied_to_clipboard, content.truncateCenter(50)))
|
||||
toast(localize(MR.strings.copied_to_clipboard, content.truncateCenter(50)))
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
logcat(LogPriority.ERROR, e)
|
||||
toast(R.string.clipboard_copy_error)
|
||||
toast(MR.strings.clipboard_copy_error)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@ import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.content.IntentCompat
|
||||
import eu.kanade.tachiyomi.R
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.i18n.MR
|
||||
import java.io.Serializable
|
||||
|
||||
fun Uri.toShareIntent(context: Context, type: String = "image/*", message: String? = null): Intent {
|
||||
@@ -27,7 +28,7 @@ fun Uri.toShareIntent(context: Context, type: String = "image/*", message: Strin
|
||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||
}
|
||||
|
||||
return Intent.createChooser(shareIntent, context.getString(R.string.action_share)).apply {
|
||||
return Intent.createChooser(shareIntent, context.localize(MR.strings.action_share)).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import android.content.Context
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourcesScreenModel
|
||||
import tachiyomi.core.i18n.localize
|
||||
import tachiyomi.i18n.MR
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
@@ -29,10 +30,10 @@ object LocaleHelper {
|
||||
*/
|
||||
fun getSourceDisplayName(lang: String?, context: Context): String {
|
||||
return when (lang) {
|
||||
SourcesScreenModel.LAST_USED_KEY -> context.getString(R.string.last_used_source)
|
||||
SourcesScreenModel.PINNED_KEY -> context.getString(R.string.pinned_sources)
|
||||
"other" -> context.getString(R.string.other_source)
|
||||
"all" -> context.getString(R.string.multi_lang)
|
||||
SourcesScreenModel.LAST_USED_KEY -> context.localize(MR.strings.last_used_source)
|
||||
SourcesScreenModel.PINNED_KEY -> context.localize(MR.strings.pinned_sources)
|
||||
"other" -> context.localize(MR.strings.other_source)
|
||||
"all" -> context.localize(MR.strings.multi_lang)
|
||||
else -> getDisplayName(lang)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user