mirror of
https://github.com/mihonapp/mihon.git
synced 2025-02-12 10:08:55 +01:00
Compare commits
4 Commits
d70aa37419
...
2bf426008b
Author | SHA1 | Date | |
---|---|---|---|
|
2bf426008b | ||
|
bde81f67f2 | ||
|
dd1a9a7216 | ||
|
2d44f57e7b |
@ -24,6 +24,7 @@ import cafe.adriel.voyager.navigator.LocalNavigator
|
|||||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.domain.extension.interactor.TrustExtension
|
import eu.kanade.domain.extension.interactor.TrustExtension
|
||||||
|
import eu.kanade.domain.sync.SyncPreferences
|
||||||
import eu.kanade.presentation.more.settings.Preference
|
import eu.kanade.presentation.more.settings.Preference
|
||||||
import eu.kanade.presentation.more.settings.screen.advanced.ClearDatabaseScreen
|
import eu.kanade.presentation.more.settings.screen.advanced.ClearDatabaseScreen
|
||||||
import eu.kanade.presentation.more.settings.screen.debug.DebugInfoScreen
|
import eu.kanade.presentation.more.settings.screen.debug.DebugInfoScreen
|
||||||
@ -124,6 +125,7 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
getNetworkGroup(networkPreferences = networkPreferences),
|
getNetworkGroup(networkPreferences = networkPreferences),
|
||||||
getLibraryGroup(),
|
getLibraryGroup(),
|
||||||
getExtensionsGroup(basePreferences = basePreferences),
|
getExtensionsGroup(basePreferences = basePreferences),
|
||||||
|
getSyncGroup(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,4 +386,23 @@ object SettingsAdvancedScreen : SearchableSettings {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun getSyncGroup(): Preference.PreferenceGroup {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val syncPreferences = remember { Injekt.get<SyncPreferences>() }
|
||||||
|
return Preference.PreferenceGroup(
|
||||||
|
title = stringResource(MR.strings.label_sync),
|
||||||
|
preferenceItems = persistentListOf(
|
||||||
|
Preference.PreferenceItem.TextPreference(
|
||||||
|
title = stringResource(MR.strings.pref_reset_sync_timestamp),
|
||||||
|
subtitle = stringResource(MR.strings.pref_reset_sync_timestamp_subtitle),
|
||||||
|
onClick = {
|
||||||
|
syncPreferences.lastSyncTimestamp().set(0)
|
||||||
|
context.toast(MR.strings.success_reset_sync_timestamp)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
package eu.kanade.presentation.more.settings.screen.data
|
package eu.kanade.presentation.more.settings.screen.data
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -9,6 +9,7 @@ import androidx.core.net.toUri
|
|||||||
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreJob
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||||
|
import eu.kanade.tachiyomi.data.sync.SyncDataJob
|
||||||
import eu.kanade.tachiyomi.data.updater.AppUpdateDownloadJob
|
import eu.kanade.tachiyomi.data.updater.AppUpdateDownloadJob
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
@ -70,6 +71,8 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
"application/x-protobuf+gzip",
|
"application/x-protobuf+gzip",
|
||||||
)
|
)
|
||||||
ACTION_CANCEL_RESTORE -> cancelRestore(context)
|
ACTION_CANCEL_RESTORE -> cancelRestore(context)
|
||||||
|
|
||||||
|
ACTION_CANCEL_SYNC -> cancelSync(context)
|
||||||
// Cancel library update and dismiss notification
|
// Cancel library update and dismiss notification
|
||||||
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context)
|
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context)
|
||||||
// Start downloading app update
|
// Start downloading app update
|
||||||
@ -187,6 +190,15 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
AppUpdateDownloadJob.stop(context)
|
AppUpdateDownloadJob.stop(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called when user wants to stop a backup restore job.
|
||||||
|
*
|
||||||
|
* @param context context of application
|
||||||
|
*/
|
||||||
|
private fun cancelSync(context: Context) {
|
||||||
|
SyncDataJob.stop(context)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method called when user wants to mark manga chapters as read
|
* Method called when user wants to mark manga chapters as read
|
||||||
*
|
*
|
||||||
@ -239,6 +251,8 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
|
|
||||||
private const val ACTION_CANCEL_RESTORE = "$ID.$NAME.CANCEL_RESTORE"
|
private const val ACTION_CANCEL_RESTORE = "$ID.$NAME.CANCEL_RESTORE"
|
||||||
|
|
||||||
|
private const val ACTION_CANCEL_SYNC = "$ID.$NAME.CANCEL_SYNC"
|
||||||
|
|
||||||
private const val ACTION_CANCEL_LIBRARY_UPDATE = "$ID.$NAME.CANCEL_LIBRARY_UPDATE"
|
private const val ACTION_CANCEL_LIBRARY_UPDATE = "$ID.$NAME.CANCEL_LIBRARY_UPDATE"
|
||||||
|
|
||||||
private const val ACTION_START_APP_UPDATE = "$ID.$NAME.ACTION_START_APP_UPDATE"
|
private const val ACTION_START_APP_UPDATE = "$ID.$NAME.ACTION_START_APP_UPDATE"
|
||||||
@ -615,5 +629,25 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [PendingIntent] that cancels a sync restore job.
|
||||||
|
*
|
||||||
|
* @param context context of application
|
||||||
|
* @param notificationId id of notification
|
||||||
|
* @return [PendingIntent]
|
||||||
|
*/
|
||||||
|
internal fun cancelSyncPendingBroadcast(context: Context, notificationId: Int): PendingIntent {
|
||||||
|
val intent = Intent(context, NotificationReceiver::class.java).apply {
|
||||||
|
action = ACTION_CANCEL_SYNC
|
||||||
|
putExtra(EXTRA_NOTIFICATION_ID, notificationId)
|
||||||
|
}
|
||||||
|
return PendingIntent.getBroadcast(
|
||||||
|
context,
|
||||||
|
0,
|
||||||
|
intent,
|
||||||
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
103
app/src/main/java/eu/kanade/tachiyomi/data/sync/SyncDataJob.kt
Normal file
103
app/src/main/java/eu/kanade/tachiyomi/data/sync/SyncDataJob.kt
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.sync
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.ServiceInfo
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.work.CoroutineWorker
|
||||||
|
import androidx.work.ExistingPeriodicWorkPolicy
|
||||||
|
import androidx.work.ExistingWorkPolicy
|
||||||
|
import androidx.work.ForegroundInfo
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.PeriodicWorkRequestBuilder
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import eu.kanade.domain.sync.SyncPreferences
|
||||||
|
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 logcat.LogPriority
|
||||||
|
import tachiyomi.core.util.system.logcat
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class SyncDataJob(private val context: Context, workerParams: WorkerParameters) :
|
||||||
|
CoroutineWorker(context, workerParams) {
|
||||||
|
|
||||||
|
private val notifier = SyncNotifier(context)
|
||||||
|
|
||||||
|
override suspend fun doWork(): Result {
|
||||||
|
try {
|
||||||
|
setForeground(getForegroundInfo())
|
||||||
|
} catch (e: IllegalStateException) {
|
||||||
|
logcat(LogPriority.ERROR, e) { "Not allowed to run on foreground service" }
|
||||||
|
}
|
||||||
|
|
||||||
|
return try {
|
||||||
|
// TODO: Uncomment this when the rest of sync PR is merged.
|
||||||
|
// SyncManager(context).syncData()
|
||||||
|
Result.success()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
logcat(LogPriority.ERROR, e)
|
||||||
|
notifier.showSyncError(e.message)
|
||||||
|
Result.failure()
|
||||||
|
} finally {
|
||||||
|
context.cancelNotification(Notifications.ID_RESTORE_PROGRESS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getForegroundInfo(): ForegroundInfo {
|
||||||
|
return ForegroundInfo(
|
||||||
|
Notifications.ID_RESTORE_PROGRESS,
|
||||||
|
notifier.showSyncProgress().build(),
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG_JOB = "SyncDataJob"
|
||||||
|
private const val TAG_AUTO = "$TAG_JOB:auto"
|
||||||
|
const val TAG_MANUAL = "$TAG_JOB:manual"
|
||||||
|
|
||||||
|
private val jobTagList = listOf(TAG_AUTO, TAG_MANUAL)
|
||||||
|
|
||||||
|
fun isAnyJobRunning(context: Context): Boolean {
|
||||||
|
return jobTagList.any { context.workManager.isRunning(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setupTask(context: Context, prefInterval: Int? = null) {
|
||||||
|
val syncPreferences = Injekt.get<SyncPreferences>()
|
||||||
|
val interval = prefInterval ?: syncPreferences.syncInterval().get()
|
||||||
|
|
||||||
|
if (interval > 0) {
|
||||||
|
val request = PeriodicWorkRequestBuilder<SyncDataJob>(
|
||||||
|
interval.toLong(),
|
||||||
|
TimeUnit.MINUTES,
|
||||||
|
10,
|
||||||
|
TimeUnit.MINUTES,
|
||||||
|
)
|
||||||
|
.addTag(TAG_AUTO)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
context.workManager.enqueueUniquePeriodicWork(TAG_AUTO, ExistingPeriodicWorkPolicy.UPDATE, request)
|
||||||
|
} else {
|
||||||
|
context.workManager.cancelUniqueWork(TAG_AUTO)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startNow(context: Context) {
|
||||||
|
val request = OneTimeWorkRequestBuilder<SyncDataJob>()
|
||||||
|
.addTag(TAG_MANUAL)
|
||||||
|
.build()
|
||||||
|
context.workManager.enqueueUniqueWork(TAG_MANUAL, ExistingWorkPolicy.KEEP, request)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun stop(context: Context) {
|
||||||
|
context.workManager.cancelUniqueWork(TAG_MANUAL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,86 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.sync
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.core.security.SecurityPreferences
|
||||||
|
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.notificationBuilder
|
||||||
|
import eu.kanade.tachiyomi.util.system.notify
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
class SyncNotifier(private val context: Context) {
|
||||||
|
|
||||||
|
private val preferences: SecurityPreferences by injectLazy()
|
||||||
|
|
||||||
|
private val progressNotificationBuilder = context.notificationBuilder(
|
||||||
|
Notifications.CHANNEL_BACKUP_RESTORE_PROGRESS,
|
||||||
|
) {
|
||||||
|
setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher))
|
||||||
|
setSmallIcon(R.drawable.ic_mihon)
|
||||||
|
setAutoCancel(false)
|
||||||
|
setOngoing(true)
|
||||||
|
setOnlyAlertOnce(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val completeNotificationBuilder = context.notificationBuilder(
|
||||||
|
Notifications.CHANNEL_BACKUP_RESTORE_PROGRESS,
|
||||||
|
) {
|
||||||
|
setLargeIcon(BitmapFactory.decodeResource(context.resources, R.mipmap.ic_launcher))
|
||||||
|
setSmallIcon(R.drawable.ic_mihon)
|
||||||
|
setAutoCancel(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun NotificationCompat.Builder.show(id: Int) {
|
||||||
|
context.notify(id, build())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showSyncProgress(content: String = "", progress: Int = 0, maxAmount: Int = 100): NotificationCompat.Builder {
|
||||||
|
val builder = with(progressNotificationBuilder) {
|
||||||
|
setContentTitle(context.getString(R.string.syncing_library))
|
||||||
|
|
||||||
|
if (!preferences.hideNotificationContent().get()) {
|
||||||
|
setContentText(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
setProgress(maxAmount, progress, true)
|
||||||
|
setOnlyAlertOnce(true)
|
||||||
|
|
||||||
|
clearActions()
|
||||||
|
addAction(
|
||||||
|
R.drawable.ic_close_24dp,
|
||||||
|
context.getString(R.string.action_cancel),
|
||||||
|
NotificationReceiver.cancelSyncPendingBroadcast(context, Notifications.ID_RESTORE_PROGRESS),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.show(Notifications.ID_RESTORE_PROGRESS)
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showSyncError(error: String?) {
|
||||||
|
context.cancelNotification(Notifications.ID_RESTORE_PROGRESS)
|
||||||
|
|
||||||
|
with(completeNotificationBuilder) {
|
||||||
|
setContentTitle(context.getString(R.string.sync_error))
|
||||||
|
setContentText(error)
|
||||||
|
|
||||||
|
show(Notifications.ID_RESTORE_COMPLETE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun showSyncSuccess(message: String?) {
|
||||||
|
context.cancelNotification(Notifications.ID_RESTORE_PROGRESS)
|
||||||
|
|
||||||
|
with(completeNotificationBuilder) {
|
||||||
|
setContentTitle(context.getString(R.string.sync_complete))
|
||||||
|
setContentText(message)
|
||||||
|
|
||||||
|
show(Notifications.ID_RESTORE_COMPLETE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,8 +28,10 @@
|
|||||||
<string name="label_recent_updates">Updates</string>
|
<string name="label_recent_updates">Updates</string>
|
||||||
<string name="label_recent_manga">History</string>
|
<string name="label_recent_manga">History</string>
|
||||||
<string name="label_sources">Sources</string>
|
<string name="label_sources">Sources</string>
|
||||||
<string name="label_backup">Backup and restore</string>
|
|
||||||
<string name="label_data_storage">Data and storage</string>
|
<string name="label_data_storage">Data and storage</string>
|
||||||
|
<string name="label_backup">Backup</string>
|
||||||
|
<string name="label_sync">Sync</string>
|
||||||
|
<string name="label_triggers">Triggers</string>
|
||||||
<string name="label_stats">Statistics</string>
|
<string name="label_stats">Statistics</string>
|
||||||
<string name="label_migration">Migrate</string>
|
<string name="label_migration">Migrate</string>
|
||||||
<string name="label_extensions">Extensions</string>
|
<string name="label_extensions">Extensions</string>
|
||||||
@ -208,6 +210,7 @@
|
|||||||
<string name="pref_tracking_summary">One-way progress sync, enhanced sync</string>
|
<string name="pref_tracking_summary">One-way progress sync, enhanced sync</string>
|
||||||
<string name="pref_browse_summary">Sources, extensions, global search</string>
|
<string name="pref_browse_summary">Sources, extensions, global search</string>
|
||||||
<string name="pref_backup_summary">Manual & automatic backups, storage space</string>
|
<string name="pref_backup_summary">Manual & automatic backups, storage space</string>
|
||||||
|
<string name="pref_backup_and_sync_summary">Manual & automatic backups and sync</string>
|
||||||
<string name="pref_security_summary">App lock, secure screen</string>
|
<string name="pref_security_summary">App lock, secure screen</string>
|
||||||
<string name="pref_advanced_summary">Dump crash logs, battery optimizations</string>
|
<string name="pref_advanced_summary">Dump crash logs, battery optimizations</string>
|
||||||
|
|
||||||
@ -262,6 +265,9 @@
|
|||||||
<string name="pref_category_library_update">Global update</string>
|
<string name="pref_category_library_update">Global update</string>
|
||||||
<string name="pref_library_update_interval">Automatic updates</string>
|
<string name="pref_library_update_interval">Automatic updates</string>
|
||||||
<string name="update_never">Off</string>
|
<string name="update_never">Off</string>
|
||||||
|
<string name="update_30min">Every 30 minutes</string>
|
||||||
|
<string name="update_1hour">Every hour</string>
|
||||||
|
<string name="update_3hour">Every 3 hours</string>
|
||||||
<string name="update_6hour">Every 6 hours</string>
|
<string name="update_6hour">Every 6 hours</string>
|
||||||
<string name="update_12hour">Every 12 hours</string>
|
<string name="update_12hour">Every 12 hours</string>
|
||||||
<string name="update_24hour">Daily</string>
|
<string name="update_24hour">Daily</string>
|
||||||
@ -539,6 +545,53 @@
|
|||||||
<!-- Sync section -->
|
<!-- Sync section -->
|
||||||
<string name="syncing_library">Syncing library</string>
|
<string name="syncing_library">Syncing library</string>
|
||||||
<string name="library_sync_complete">Library sync complete</string>
|
<string name="library_sync_complete">Library sync complete</string>
|
||||||
|
<string name="sync_error">Syncing library failed</string>
|
||||||
|
<string name="sync_complete">Syncing library complete</string>
|
||||||
|
<string name="sync_in_progress">Sync is already in progress</string>
|
||||||
|
<string name="pref_sync_host">Host</string>
|
||||||
|
<string name="pref_sync_host_summ">Enter the host address for synchronizing your library</string>
|
||||||
|
<string name="pref_sync_api_key">API key</string>
|
||||||
|
<string name="pref_sync_api_key_summ">Enter the API key to synchronize your library</string>
|
||||||
|
<string name="pref_sync_now_group_title">Sync Actions</string>
|
||||||
|
<string name="pref_sync_now">Sync now</string>
|
||||||
|
<string name="pref_sync_confirmation_title">Sync confirmation</string>
|
||||||
|
<string name="pref_sync_now_subtitle">Initiate immediate synchronization of your data</string>
|
||||||
|
<string name="pref_sync_confirmation_message">Syncing will overwrite your local library with the remote library. Are you sure you want to continue?</string>
|
||||||
|
<string name="pref_sync_service">Service</string>
|
||||||
|
<string name="pref_sync_service_summ">Select the service to sync your library with</string>
|
||||||
|
<string name="pref_sync_service_category">Sync</string>
|
||||||
|
<string name="pref_sync_automatic_category">Automatic Synchronization</string>
|
||||||
|
<string name="pref_sync_interval">Synchronization frequency</string>
|
||||||
|
<string name="pref_reset_sync_timestamp">Reset last sync timestamp</string>
|
||||||
|
<string name="pref_reset_sync_timestamp_subtitle">Reset the last sync timestamp to force a full sync</string>
|
||||||
|
<string name="pref_choose_what_to_sync">Choose what to sync</string>
|
||||||
|
<string name="success_reset_sync_timestamp">Last sync timestamp reset</string>
|
||||||
|
<string name="syncyomi">SyncYomi</string>
|
||||||
|
<string name="sync_completed_message">Done in %1$s</string>
|
||||||
|
<string name="last_synchronization">Last Synchronization: %1$s</string>
|
||||||
|
<string name="google_drive">Google Drive</string>
|
||||||
|
<string name="pref_google_drive_sign_in">Sign in</string>
|
||||||
|
<string name="google_drive_sign_in_success">Signed in successfully</string>
|
||||||
|
<string name="google_drive_sign_in_failed">Sign in failed</string>
|
||||||
|
<string name="authentication">Authentication</string>
|
||||||
|
<string name="pref_google_drive_purge_sync_data">Clear Sync Data from Google Drive</string>
|
||||||
|
<string name="google_drive_sync_data_purged">Sync data purged from Google Drive</string>
|
||||||
|
<string name="google_drive_sync_data_not_found">No sync data found in Google Drive</string>
|
||||||
|
<string name="google_drive_login_success">Logged in to Google Drive</string>
|
||||||
|
<string name="google_drive_login_failed">Failed to log in to Google Drive: %s</string>
|
||||||
|
<string name="google_drive_not_signed_in">Not signed in to Google Drive</string>
|
||||||
|
<string name="error_uploading_sync_data">Error uploading sync data to Google Drive</string>
|
||||||
|
<string name="error_deleting_google_drive_lock_file">Error Deleting Google Drive Lock File</string>
|
||||||
|
<string name="pref_purge_confirmation_title">Purge confirmation</string>
|
||||||
|
<string name="pref_purge_confirmation_message">Purging sync data will delete all your sync data from Google Drive. Are you sure you want to continue?</string>
|
||||||
|
<string name="pref_sync_options">Create sync triggers</string>
|
||||||
|
<string name="pref_sync_options_summ">Can be used to set sync triggers</string>
|
||||||
|
<string name="sync_on_chapter_read">Sync on Chapter Read</string>
|
||||||
|
<string name="sync_on_chapter_open">Sync on Chapter Open</string>
|
||||||
|
<string name="sync_on_app_start">Sync on App Start</string>
|
||||||
|
<string name="sync_on_app_resume">Sync on App Resume</string>
|
||||||
|
<string name="sync_on_library_update">Sync on Library Update</string>
|
||||||
|
<string name="sync_library">Sync library</string>
|
||||||
|
|
||||||
<!-- Advanced section -->
|
<!-- Advanced section -->
|
||||||
<string name="label_network">Networking</string>
|
<string name="label_network">Networking</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user