Preferences with conductor (#792)
* Settings with conductor WIP * Add downloads preference controller. Implement source/track login * Improve settings controllers * Backup settings controller * Delete preferences xml * Remove keys from xml * PreferenceKeys is now an object * Remove now unused dependency
This commit is contained in:
parent
29fd5747eb
commit
ff190e02d4
@ -101,6 +101,7 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
compile "com.bluelinelabs:conductor:2.1.3"
|
compile "com.bluelinelabs:conductor:2.1.3"
|
||||||
|
compile 'com.github.inorichi:conductor-support-preference:master-SNAPSHOT'
|
||||||
|
|
||||||
final rxbindings_version = '1.0.1'
|
final rxbindings_version = '1.0.1'
|
||||||
compile "com.jakewharton.rxbinding:rxbinding-kotlin:$rxbindings_version"
|
compile "com.jakewharton.rxbinding:rxbinding-kotlin:$rxbindings_version"
|
||||||
@ -204,7 +205,6 @@ dependencies {
|
|||||||
compile 'com.nononsenseapps:filepicker:2.5.2'
|
compile 'com.nononsenseapps:filepicker:2.5.2'
|
||||||
compile 'com.github.amulyakhare:TextDrawable:558677e'
|
compile 'com.github.amulyakhare:TextDrawable:558677e'
|
||||||
compile 'com.afollestad.material-dialogs:core:0.9.4.2'
|
compile 'com.afollestad.material-dialogs:core:0.9.4.2'
|
||||||
compile 'net.xpece.android:support-preference:1.2.5'
|
|
||||||
compile 'me.zhanghai.android.systemuihelper:library:1.0.0'
|
compile 'me.zhanghai.android.systemuihelper:library:1.0.0'
|
||||||
compile 'de.hdodenhof:circleimageview:2.1.0'
|
compile 'de.hdodenhof:circleimageview:2.1.0'
|
||||||
|
|
||||||
|
@ -35,10 +35,6 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".ui.reader.ReaderActivity"
|
android:name=".ui.reader.ReaderActivity"
|
||||||
android:theme="@style/Theme.Reader" />
|
android:theme="@style/Theme.Reader" />
|
||||||
<activity
|
|
||||||
android:name=".ui.setting.SettingsActivity"
|
|
||||||
android:label="@string/label_settings"
|
|
||||||
android:parentActivityName=".ui.main.MainActivity" />
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".widget.CustomLayoutPickerActivity"
|
android:name=".widget.CustomLayoutPickerActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.backup
|
||||||
|
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
||||||
|
|
||||||
|
|
||||||
|
object BackupConst {
|
||||||
|
|
||||||
|
const val INTENT_FILTER = "SettingsBackupFragment"
|
||||||
|
const val ACTION_BACKUP_COMPLETED_DIALOG = "$ID.$INTENT_FILTER.ACTION_BACKUP_COMPLETED_DIALOG"
|
||||||
|
const val ACTION_SET_PROGRESS_DIALOG = "$ID.$INTENT_FILTER.ACTION_SET_PROGRESS_DIALOG"
|
||||||
|
const val ACTION_ERROR_BACKUP_DIALOG = "$ID.$INTENT_FILTER.ACTION_ERROR_BACKUP_DIALOG"
|
||||||
|
const val ACTION_ERROR_RESTORE_DIALOG = "$ID.$INTENT_FILTER.ACTION_ERROR_RESTORE_DIALOG"
|
||||||
|
const val ACTION_RESTORE_COMPLETED_DIALOG = "$ID.$INTENT_FILTER.ACTION_RESTORE_COMPLETED_DIALOG"
|
||||||
|
const val ACTION = "$ID.$INTENT_FILTER.ACTION"
|
||||||
|
const val EXTRA_PROGRESS = "$ID.$INTENT_FILTER.EXTRA_PROGRESS"
|
||||||
|
const val EXTRA_AMOUNT = "$ID.$INTENT_FILTER.EXTRA_AMOUNT"
|
||||||
|
const val EXTRA_ERRORS = "$ID.$INTENT_FILTER.EXTRA_ERRORS"
|
||||||
|
const val EXTRA_CONTENT = "$ID.$INTENT_FILTER.EXTRA_CONTENT"
|
||||||
|
const val EXTRA_ERROR_MESSAGE = "$ID.$INTENT_FILTER.EXTRA_ERROR_MESSAGE"
|
||||||
|
const val EXTRA_URI = "$ID.$INTENT_FILTER.EXTRA_URI"
|
||||||
|
const val EXTRA_TIME = "$ID.$INTENT_FILTER.EXTRA_TIME"
|
||||||
|
const val EXTRA_ERROR_FILE_PATH = "$ID.$INTENT_FILTER.EXTRA_ERROR_FILE_PATH"
|
||||||
|
const val EXTRA_ERROR_FILE = "$ID.$INTENT_FILTER.EXTRA_ERROR_FILE"
|
||||||
|
}
|
@ -13,7 +13,6 @@ import eu.kanade.tachiyomi.data.backup.models.Backup.CATEGORIES
|
|||||||
import eu.kanade.tachiyomi.data.backup.models.Backup.MANGAS
|
import eu.kanade.tachiyomi.data.backup.models.Backup.MANGAS
|
||||||
import eu.kanade.tachiyomi.data.backup.models.Backup.VERSION
|
import eu.kanade.tachiyomi.data.backup.models.Backup.VERSION
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsBackupFragment
|
|
||||||
import eu.kanade.tachiyomi.util.AndroidComponentUtil
|
import eu.kanade.tachiyomi.util.AndroidComponentUtil
|
||||||
import eu.kanade.tachiyomi.util.sendLocalBroadcast
|
import eu.kanade.tachiyomi.util.sendLocalBroadcast
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -28,8 +27,6 @@ class BackupCreateService : IntentService(NAME) {
|
|||||||
// Name of class
|
// Name of class
|
||||||
private const val NAME = "BackupCreateService"
|
private const val NAME = "BackupCreateService"
|
||||||
|
|
||||||
// Uri as string
|
|
||||||
private const val EXTRA_URI = "$ID.$NAME.EXTRA_URI"
|
|
||||||
// Backup called from job
|
// Backup called from job
|
||||||
private const val EXTRA_IS_JOB = "$ID.$NAME.EXTRA_IS_JOB"
|
private const val EXTRA_IS_JOB = "$ID.$NAME.EXTRA_IS_JOB"
|
||||||
// Options for backup
|
// Options for backup
|
||||||
@ -56,7 +53,7 @@ class BackupCreateService : IntentService(NAME) {
|
|||||||
*/
|
*/
|
||||||
fun makeBackup(context: Context, path: String, flags: Int, isJob: Boolean = false) {
|
fun makeBackup(context: Context, path: String, flags: Int, isJob: Boolean = false) {
|
||||||
val intent = Intent(context, BackupCreateService::class.java).apply {
|
val intent = Intent(context, BackupCreateService::class.java).apply {
|
||||||
putExtra(EXTRA_URI, path)
|
putExtra(BackupConst.EXTRA_URI, path)
|
||||||
putExtra(EXTRA_IS_JOB, isJob)
|
putExtra(EXTRA_IS_JOB, isJob)
|
||||||
putExtra(EXTRA_FLAGS, flags)
|
putExtra(EXTRA_FLAGS, flags)
|
||||||
}
|
}
|
||||||
@ -74,7 +71,7 @@ class BackupCreateService : IntentService(NAME) {
|
|||||||
if (intent == null) return
|
if (intent == null) return
|
||||||
|
|
||||||
// Get values
|
// Get values
|
||||||
val uri = intent.getStringExtra(EXTRA_URI)
|
val uri = intent.getStringExtra(BackupConst.EXTRA_URI)
|
||||||
val isJob = intent.getBooleanExtra(EXTRA_IS_JOB, false)
|
val isJob = intent.getBooleanExtra(EXTRA_IS_JOB, false)
|
||||||
val flags = intent.getIntExtra(EXTRA_FLAGS, 0)
|
val flags = intent.getIntExtra(EXTRA_FLAGS, 0)
|
||||||
// Create backup
|
// Create backup
|
||||||
@ -150,9 +147,9 @@ class BackupCreateService : IntentService(NAME) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Show completed dialog
|
// Show completed dialog
|
||||||
val intent = Intent(SettingsBackupFragment.INTENT_FILTER).apply {
|
val intent = Intent(BackupConst.INTENT_FILTER).apply {
|
||||||
putExtra(SettingsBackupFragment.ACTION, SettingsBackupFragment.ACTION_BACKUP_COMPLETED_DIALOG)
|
putExtra(BackupConst.ACTION, BackupConst.ACTION_BACKUP_COMPLETED_DIALOG)
|
||||||
putExtra(SettingsBackupFragment.EXTRA_URI, file.uri.toString())
|
putExtra(BackupConst.EXTRA_URI, file.uri.toString())
|
||||||
}
|
}
|
||||||
sendLocalBroadcast(intent)
|
sendLocalBroadcast(intent)
|
||||||
}
|
}
|
||||||
@ -160,9 +157,9 @@ class BackupCreateService : IntentService(NAME) {
|
|||||||
Timber.e(e)
|
Timber.e(e)
|
||||||
if (!isJob) {
|
if (!isJob) {
|
||||||
// Show error dialog
|
// Show error dialog
|
||||||
val intent = Intent(SettingsBackupFragment.INTENT_FILTER).apply {
|
val intent = Intent(BackupConst.INTENT_FILTER).apply {
|
||||||
putExtra(SettingsBackupFragment.ACTION, SettingsBackupFragment.ACTION_ERROR_BACKUP_DIALOG)
|
putExtra(BackupConst.ACTION, BackupConst.ACTION_ERROR_BACKUP_DIALOG)
|
||||||
putExtra(SettingsBackupFragment.EXTRA_ERROR_MESSAGE, e.message)
|
putExtra(BackupConst.EXTRA_ERROR_MESSAGE, e.message)
|
||||||
}
|
}
|
||||||
sendLocalBroadcast(intent)
|
sendLocalBroadcast(intent)
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ class BackupCreatorJob : Job() {
|
|||||||
val preferences = Injekt.get<PreferencesHelper>()
|
val preferences = Injekt.get<PreferencesHelper>()
|
||||||
val path = preferences.backupsDirectory().getOrDefault()
|
val path = preferences.backupsDirectory().getOrDefault()
|
||||||
val flags = BackupCreateService.BACKUP_ALL
|
val flags = BackupCreateService.BACKUP_ALL
|
||||||
BackupCreateService.makeBackup(context,path,flags,true)
|
BackupCreateService.makeBackup(context, path, flags, true)
|
||||||
return Result.SUCCESS
|
return Result.SUCCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,6 @@ import eu.kanade.tachiyomi.source.SourceManager
|
|||||||
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ import eu.kanade.tachiyomi.data.backup.models.DHistory
|
|||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.*
|
import eu.kanade.tachiyomi.data.database.models.*
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsBackupFragment
|
|
||||||
import eu.kanade.tachiyomi.util.AndroidComponentUtil
|
import eu.kanade.tachiyomi.util.AndroidComponentUtil
|
||||||
import eu.kanade.tachiyomi.util.chop
|
import eu.kanade.tachiyomi.util.chop
|
||||||
import eu.kanade.tachiyomi.util.sendLocalBroadcast
|
import eu.kanade.tachiyomi.util.sendLocalBroadcast
|
||||||
@ -36,7 +35,6 @@ import java.text.SimpleDateFormat
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.ExecutorService
|
import java.util.concurrent.ExecutorService
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restores backup from json file
|
* Restores backup from json file
|
||||||
@ -44,11 +42,6 @@ import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
|||||||
class BackupRestoreService : Service() {
|
class BackupRestoreService : Service() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// Name of service
|
|
||||||
private const val NAME = "BackupRestoreService"
|
|
||||||
|
|
||||||
// Uri as string
|
|
||||||
private const val EXTRA_URI = "$ID.$NAME.EXTRA_URI"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the status of the service.
|
* Returns the status of the service.
|
||||||
@ -69,7 +62,7 @@ class BackupRestoreService : Service() {
|
|||||||
fun start(context: Context, uri: Uri) {
|
fun start(context: Context, uri: Uri) {
|
||||||
if (!isRunning(context)) {
|
if (!isRunning(context)) {
|
||||||
val intent = Intent(context, BackupRestoreService::class.java).apply {
|
val intent = Intent(context, BackupRestoreService::class.java).apply {
|
||||||
putExtra(EXTRA_URI, uri)
|
putExtra(BackupConst.EXTRA_URI, uri)
|
||||||
}
|
}
|
||||||
context.startService(intent)
|
context.startService(intent)
|
||||||
}
|
}
|
||||||
@ -164,7 +157,7 @@ class BackupRestoreService : Service() {
|
|||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
if (intent == null) return Service.START_NOT_STICKY
|
if (intent == null) return Service.START_NOT_STICKY
|
||||||
|
|
||||||
val uri = intent.getParcelableExtra<Uri>(EXTRA_URI)
|
val uri = intent.getParcelableExtra<Uri>(BackupConst.EXTRA_URI)
|
||||||
|
|
||||||
// Unsubscribe from any previous subscription if needed.
|
// Unsubscribe from any previous subscription if needed.
|
||||||
subscription?.unsubscribe()
|
subscription?.unsubscribe()
|
||||||
@ -236,12 +229,12 @@ class BackupRestoreService : Service() {
|
|||||||
val endTime = System.currentTimeMillis()
|
val endTime = System.currentTimeMillis()
|
||||||
val time = endTime - startTime
|
val time = endTime - startTime
|
||||||
val logFile = writeErrorLog()
|
val logFile = writeErrorLog()
|
||||||
val completeIntent = Intent(SettingsBackupFragment.INTENT_FILTER).apply {
|
val completeIntent = Intent(BackupConst.INTENT_FILTER).apply {
|
||||||
putExtra(SettingsBackupFragment.EXTRA_TIME, time)
|
putExtra(BackupConst.EXTRA_TIME, time)
|
||||||
putExtra(SettingsBackupFragment.EXTRA_ERRORS, errors.size)
|
putExtra(BackupConst.EXTRA_ERRORS, errors.size)
|
||||||
putExtra(SettingsBackupFragment.EXTRA_ERROR_FILE_PATH, logFile.parent)
|
putExtra(BackupConst.EXTRA_ERROR_FILE_PATH, logFile.parent)
|
||||||
putExtra(SettingsBackupFragment.EXTRA_ERROR_FILE, logFile.name)
|
putExtra(BackupConst.EXTRA_ERROR_FILE, logFile.name)
|
||||||
putExtra(SettingsBackupFragment.ACTION, SettingsBackupFragment.ACTION_RESTORE_COMPLETED_DIALOG)
|
putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_COMPLETED_DIALOG)
|
||||||
}
|
}
|
||||||
sendLocalBroadcast(completeIntent)
|
sendLocalBroadcast(completeIntent)
|
||||||
|
|
||||||
@ -249,9 +242,9 @@ class BackupRestoreService : Service() {
|
|||||||
.doOnError { error ->
|
.doOnError { error ->
|
||||||
Timber.e(error)
|
Timber.e(error)
|
||||||
writeErrorLog()
|
writeErrorLog()
|
||||||
val errorIntent = Intent(SettingsBackupFragment.INTENT_FILTER).apply {
|
val errorIntent = Intent(BackupConst.INTENT_FILTER).apply {
|
||||||
putExtra(SettingsBackupFragment.ACTION, SettingsBackupFragment.ACTION_ERROR_RESTORE_DIALOG)
|
putExtra(BackupConst.ACTION, BackupConst.ACTION_ERROR_RESTORE_DIALOG)
|
||||||
putExtra(SettingsBackupFragment.EXTRA_ERROR_MESSAGE, error.message)
|
putExtra(BackupConst.EXTRA_ERROR_MESSAGE, error.message)
|
||||||
}
|
}
|
||||||
sendLocalBroadcast(errorIntent)
|
sendLocalBroadcast(errorIntent)
|
||||||
}
|
}
|
||||||
@ -392,7 +385,7 @@ class BackupRestoreService : Service() {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to update dialog in [SettingsBackupFragment]
|
* Called to update dialog in [BackupConst]
|
||||||
*
|
*
|
||||||
* @param progress restore progress
|
* @param progress restore progress
|
||||||
* @param amount total restoreAmount of manga
|
* @param amount total restoreAmount of manga
|
||||||
@ -400,12 +393,12 @@ class BackupRestoreService : Service() {
|
|||||||
*/
|
*/
|
||||||
private fun showRestoreProgress(progress: Int, amount: Int, title: String, errors: Int,
|
private fun showRestoreProgress(progress: Int, amount: Int, title: String, errors: Int,
|
||||||
content: String = getString(R.string.dialog_restoring_backup, title.chop(15))) {
|
content: String = getString(R.string.dialog_restoring_backup, title.chop(15))) {
|
||||||
val intent = Intent(SettingsBackupFragment.INTENT_FILTER).apply {
|
val intent = Intent(BackupConst.INTENT_FILTER).apply {
|
||||||
putExtra(SettingsBackupFragment.EXTRA_PROGRESS, progress)
|
putExtra(BackupConst.EXTRA_PROGRESS, progress)
|
||||||
putExtra(SettingsBackupFragment.EXTRA_AMOUNT, amount)
|
putExtra(BackupConst.EXTRA_AMOUNT, amount)
|
||||||
putExtra(SettingsBackupFragment.EXTRA_CONTENT, content)
|
putExtra(BackupConst.EXTRA_CONTENT, content)
|
||||||
putExtra(SettingsBackupFragment.EXTRA_ERRORS, errors)
|
putExtra(BackupConst.EXTRA_ERRORS, errors)
|
||||||
putExtra(SettingsBackupFragment.ACTION, SettingsBackupFragment.ACTION_SET_PROGRESS_DIALOG)
|
putExtra(BackupConst.ACTION, BackupConst.ACTION_SET_PROGRESS_DIALOG)
|
||||||
}
|
}
|
||||||
sendLocalBroadcast(intent)
|
sendLocalBroadcast(intent)
|
||||||
}
|
}
|
||||||
|
@ -1,105 +1,105 @@
|
|||||||
package eu.kanade.tachiyomi.data.preference
|
package eu.kanade.tachiyomi.data.preference
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class stores the keys for the preferences in the application. Most of them are defined
|
* This class stores the keys for the preferences in the application.
|
||||||
* in the file "keys.xml". By using this class we can define preferences in one place and get them
|
|
||||||
* referenced here.
|
|
||||||
*/
|
*/
|
||||||
@Suppress("HasPlatformType")
|
object PreferenceKeys {
|
||||||
class PreferenceKeys(context: Context) {
|
|
||||||
|
|
||||||
val theme = context.getString(R.string.pref_theme_key)
|
const val theme = "pref_theme_key"
|
||||||
|
|
||||||
val rotation = context.getString(R.string.pref_rotation_type_key)
|
const val rotation = "pref_rotation_type_key"
|
||||||
|
|
||||||
val enableTransitions = context.getString(R.string.pref_enable_transitions_key)
|
const val enableTransitions = "pref_enable_transitions_key"
|
||||||
|
|
||||||
val showPageNumber = context.getString(R.string.pref_show_page_number_key)
|
const val showPageNumber = "pref_show_page_number_key"
|
||||||
|
|
||||||
val fullscreen = context.getString(R.string.pref_fullscreen_key)
|
const val fullscreen = "fullscreen"
|
||||||
|
|
||||||
val keepScreenOn = context.getString(R.string.pref_keep_screen_on_key)
|
const val keepScreenOn = "pref_keep_screen_on_key"
|
||||||
|
|
||||||
val customBrightness = context.getString(R.string.pref_custom_brightness_key)
|
const val customBrightness = "pref_custom_brightness_key"
|
||||||
|
|
||||||
val customBrightnessValue = context.getString(R.string.pref_custom_brightness_value_key)
|
const val customBrightnessValue = "custom_brightness_value"
|
||||||
|
|
||||||
val colorFilter = context.getString(R.string.pref_color_filter_key)
|
const val colorFilter = "pref_color_filter_key"
|
||||||
|
|
||||||
val colorFilterValue = context.getString(R.string.pref_color_filter_value_key)
|
const val colorFilterValue = "color_filter_value"
|
||||||
|
|
||||||
val defaultViewer = context.getString(R.string.pref_default_viewer_key)
|
const val defaultViewer = "pref_default_viewer_key"
|
||||||
|
|
||||||
val imageScaleType = context.getString(R.string.pref_image_scale_type_key)
|
const val imageScaleType = "pref_image_scale_type_key"
|
||||||
|
|
||||||
val imageDecoder = context.getString(R.string.pref_image_decoder_key)
|
const val imageDecoder = "image_decoder"
|
||||||
|
|
||||||
val zoomStart = context.getString(R.string.pref_zoom_start_key)
|
const val zoomStart = "pref_zoom_start_key"
|
||||||
|
|
||||||
val readerTheme = context.getString(R.string.pref_reader_theme_key)
|
const val readerTheme = "pref_reader_theme_key"
|
||||||
|
|
||||||
val cropBorders = context.getString(R.string.pref_crop_borders_key)
|
const val cropBorders = "crop_borders"
|
||||||
|
|
||||||
val readWithTapping = context.getString(R.string.pref_read_with_tapping_key)
|
const val readWithTapping = "reader_tap"
|
||||||
|
|
||||||
val readWithVolumeKeys = context.getString(R.string.pref_read_with_volume_keys_key)
|
const val readWithVolumeKeys = "reader_volume_keys"
|
||||||
|
|
||||||
val portraitColumns = context.getString(R.string.pref_library_columns_portrait_key)
|
const val portraitColumns = "pref_library_columns_portrait_key"
|
||||||
|
|
||||||
val landscapeColumns = context.getString(R.string.pref_library_columns_landscape_key)
|
const val landscapeColumns = "pref_library_columns_landscape_key"
|
||||||
|
|
||||||
val updateOnlyNonCompleted = context.getString(R.string.pref_update_only_non_completed_key)
|
const val updateOnlyNonCompleted = "pref_update_only_non_completed_key"
|
||||||
|
|
||||||
val autoUpdateTrack = context.getString(R.string.pref_auto_update_manga_sync_key)
|
const val autoUpdateTrack = "pref_auto_update_manga_sync_key"
|
||||||
|
|
||||||
val askUpdateTrack = context.getString(R.string.pref_ask_update_manga_sync_key)
|
const val askUpdateTrack = "pref_ask_update_manga_sync_key"
|
||||||
|
|
||||||
val lastUsedCatalogueSource = context.getString(R.string.pref_last_catalogue_source_key)
|
const val lastUsedCatalogueSource = "last_catalogue_source"
|
||||||
|
|
||||||
val lastUsedCategory = context.getString(R.string.pref_last_used_category_key)
|
const val lastUsedCategory = "last_used_category"
|
||||||
|
|
||||||
val catalogueAsList = context.getString(R.string.pref_display_catalogue_as_list)
|
const val catalogueAsList = "pref_display_catalogue_as_list"
|
||||||
|
|
||||||
val enabledLanguages = context.getString(R.string.pref_source_languages)
|
const val enabledLanguages = "source_languages"
|
||||||
|
|
||||||
val backupDirectory = context.getString(R.string.pref_backup_directory_key)
|
const val backupDirectory = "backup_directory"
|
||||||
|
|
||||||
val downloadsDirectory = context.getString(R.string.pref_download_directory_key)
|
const val downloadsDirectory = "download_directory"
|
||||||
|
|
||||||
val downloadThreads = context.getString(R.string.pref_download_slots_key)
|
const val downloadThreads = "pref_download_slots_key"
|
||||||
|
|
||||||
val downloadOnlyOverWifi = context.getString(R.string.pref_download_only_over_wifi_key)
|
const val downloadOnlyOverWifi = "pref_download_only_over_wifi_key"
|
||||||
|
|
||||||
val numberOfBackups = context.getString(R.string.pref_backup_slots_key)
|
const val numberOfBackups = "backup_slots"
|
||||||
|
|
||||||
val backupInterval = context.getString(R.string.pref_backup_interval_key)
|
const val backupInterval = "backup_interval"
|
||||||
|
|
||||||
val removeAfterReadSlots = context.getString(R.string.pref_remove_after_read_slots_key)
|
const val removeAfterReadSlots = "remove_after_read_slots"
|
||||||
|
|
||||||
val removeAfterMarkedAsRead = context.getString(R.string.pref_remove_after_marked_as_read_key)
|
const val removeAfterMarkedAsRead = "pref_remove_after_marked_as_read_key"
|
||||||
|
|
||||||
val libraryUpdateInterval = context.getString(R.string.pref_library_update_interval_key)
|
const val libraryUpdateInterval = "pref_library_update_interval_key"
|
||||||
|
|
||||||
val libraryUpdateRestriction = context.getString(R.string.pref_library_update_restriction_key)
|
const val libraryUpdateRestriction = "library_update_restriction"
|
||||||
|
|
||||||
val libraryUpdateCategories = context.getString(R.string.pref_library_update_categories_key)
|
const val libraryUpdateCategories = "library_update_categories"
|
||||||
|
|
||||||
val filterDownloaded = context.getString(R.string.pref_filter_downloaded_key)
|
const val filterDownloaded = "pref_filter_downloaded_key"
|
||||||
|
|
||||||
val filterUnread = context.getString(R.string.pref_filter_unread_key)
|
const val filterUnread = "pref_filter_unread_key"
|
||||||
|
|
||||||
val librarySortingMode = context.getString(R.string.pref_library_sorting_mode_key)
|
const val librarySortingMode = "library_sorting_mode"
|
||||||
|
|
||||||
val automaticUpdates = context.getString(R.string.pref_enable_automatic_updates_key)
|
const val automaticUpdates = "automatic_updates"
|
||||||
|
|
||||||
val startScreen = context.getString(R.string.pref_start_screen_key)
|
const val startScreen = "start_screen"
|
||||||
|
|
||||||
val downloadNew = context.getString(R.string.pref_download_new_key)
|
const val downloadNew = "download_new"
|
||||||
|
|
||||||
val downloadNewCategories = context.getString(R.string.pref_download_new_categories_key)
|
const val downloadNewCategories = "download_new_categories"
|
||||||
|
|
||||||
|
const val libraryAsList = "pref_display_library_as_list"
|
||||||
|
|
||||||
|
const val lang = "app_language"
|
||||||
|
|
||||||
|
const val defaultCategory = "default_category"
|
||||||
|
|
||||||
fun sourceUsername(sourceId: Long) = "pref_source_username_$sourceId"
|
fun sourceUsername(sourceId: Long) = "pref_source_username_$sourceId"
|
||||||
|
|
||||||
@ -111,10 +111,4 @@ class PreferenceKeys(context: Context) {
|
|||||||
|
|
||||||
fun trackToken(syncId: Int) = "track_token_$syncId"
|
fun trackToken(syncId: Int) = "track_token_$syncId"
|
||||||
|
|
||||||
val libraryAsList = context.getString(R.string.pref_display_library_as_list)
|
|
||||||
|
|
||||||
val lang = context.getString(R.string.pref_language_key)
|
|
||||||
|
|
||||||
val defaultCategory = context.getString(R.string.default_category_key)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||||
|
|
||||||
fun <T> Preference<T>.getOrDefault(): T = get() ?: defaultValue()!!
|
fun <T> Preference<T>.getOrDefault(): T = get() ?: defaultValue()!!
|
||||||
|
|
||||||
@ -17,8 +18,6 @@ fun Preference<Boolean>.invert(): Boolean = getOrDefault().let { set(!it); !it }
|
|||||||
|
|
||||||
class PreferencesHelper(val context: Context) {
|
class PreferencesHelper(val context: Context) {
|
||||||
|
|
||||||
val keys = PreferenceKeys(context)
|
|
||||||
|
|
||||||
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
private val rxPrefs = RxSharedPreferences.create(prefs)
|
private val rxPrefs = RxSharedPreferences.create(prefs)
|
||||||
|
|
||||||
@ -30,134 +29,134 @@ class PreferencesHelper(val context: Context) {
|
|||||||
File(Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
File(Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
||||||
context.getString(R.string.app_name), "backup"))
|
context.getString(R.string.app_name), "backup"))
|
||||||
|
|
||||||
fun startScreen() = prefs.getInt(keys.startScreen, 1)
|
fun startScreen() = prefs.getInt(Keys.startScreen, 1)
|
||||||
|
|
||||||
fun clear() = prefs.edit().clear().apply()
|
fun clear() = prefs.edit().clear().apply()
|
||||||
|
|
||||||
fun theme() = prefs.getInt(keys.theme, 1)
|
fun theme() = prefs.getInt(Keys.theme, 1)
|
||||||
|
|
||||||
fun rotation() = rxPrefs.getInteger(keys.rotation, 1)
|
fun rotation() = rxPrefs.getInteger(Keys.rotation, 1)
|
||||||
|
|
||||||
fun pageTransitions() = rxPrefs.getBoolean(keys.enableTransitions, true)
|
fun pageTransitions() = rxPrefs.getBoolean(Keys.enableTransitions, true)
|
||||||
|
|
||||||
fun showPageNumber() = rxPrefs.getBoolean(keys.showPageNumber, true)
|
fun showPageNumber() = rxPrefs.getBoolean(Keys.showPageNumber, true)
|
||||||
|
|
||||||
fun fullscreen() = rxPrefs.getBoolean(keys.fullscreen, true)
|
fun fullscreen() = rxPrefs.getBoolean(Keys.fullscreen, true)
|
||||||
|
|
||||||
fun keepScreenOn() = rxPrefs.getBoolean(keys.keepScreenOn, true)
|
fun keepScreenOn() = rxPrefs.getBoolean(Keys.keepScreenOn, true)
|
||||||
|
|
||||||
fun customBrightness() = rxPrefs.getBoolean(keys.customBrightness, false)
|
fun customBrightness() = rxPrefs.getBoolean(Keys.customBrightness, false)
|
||||||
|
|
||||||
fun customBrightnessValue() = rxPrefs.getInteger(keys.customBrightnessValue, 0)
|
fun customBrightnessValue() = rxPrefs.getInteger(Keys.customBrightnessValue, 0)
|
||||||
|
|
||||||
fun colorFilter() = rxPrefs.getBoolean(keys.colorFilter, false)
|
fun colorFilter() = rxPrefs.getBoolean(Keys.colorFilter, false)
|
||||||
|
|
||||||
fun colorFilterValue() = rxPrefs.getInteger(keys.colorFilterValue, 0)
|
fun colorFilterValue() = rxPrefs.getInteger(Keys.colorFilterValue, 0)
|
||||||
|
|
||||||
fun defaultViewer() = prefs.getInt(keys.defaultViewer, 1)
|
fun defaultViewer() = prefs.getInt(Keys.defaultViewer, 1)
|
||||||
|
|
||||||
fun imageScaleType() = rxPrefs.getInteger(keys.imageScaleType, 1)
|
fun imageScaleType() = rxPrefs.getInteger(Keys.imageScaleType, 1)
|
||||||
|
|
||||||
fun imageDecoder() = rxPrefs.getInteger(keys.imageDecoder, 0)
|
fun imageDecoder() = rxPrefs.getInteger(Keys.imageDecoder, 0)
|
||||||
|
|
||||||
fun zoomStart() = rxPrefs.getInteger(keys.zoomStart, 1)
|
fun zoomStart() = rxPrefs.getInteger(Keys.zoomStart, 1)
|
||||||
|
|
||||||
fun readerTheme() = rxPrefs.getInteger(keys.readerTheme, 0)
|
fun readerTheme() = rxPrefs.getInteger(Keys.readerTheme, 0)
|
||||||
|
|
||||||
fun cropBorders() = rxPrefs.getBoolean(keys.cropBorders, false)
|
fun cropBorders() = rxPrefs.getBoolean(Keys.cropBorders, false)
|
||||||
|
|
||||||
fun readWithTapping() = rxPrefs.getBoolean(keys.readWithTapping, true)
|
fun readWithTapping() = rxPrefs.getBoolean(Keys.readWithTapping, true)
|
||||||
|
|
||||||
fun readWithVolumeKeys() = rxPrefs.getBoolean(keys.readWithVolumeKeys, false)
|
fun readWithVolumeKeys() = rxPrefs.getBoolean(Keys.readWithVolumeKeys, false)
|
||||||
|
|
||||||
fun portraitColumns() = rxPrefs.getInteger(keys.portraitColumns, 0)
|
fun portraitColumns() = rxPrefs.getInteger(Keys.portraitColumns, 0)
|
||||||
|
|
||||||
fun landscapeColumns() = rxPrefs.getInteger(keys.landscapeColumns, 0)
|
fun landscapeColumns() = rxPrefs.getInteger(Keys.landscapeColumns, 0)
|
||||||
|
|
||||||
fun updateOnlyNonCompleted() = prefs.getBoolean(keys.updateOnlyNonCompleted, false)
|
fun updateOnlyNonCompleted() = prefs.getBoolean(Keys.updateOnlyNonCompleted, false)
|
||||||
|
|
||||||
fun autoUpdateTrack() = prefs.getBoolean(keys.autoUpdateTrack, true)
|
fun autoUpdateTrack() = prefs.getBoolean(Keys.autoUpdateTrack, true)
|
||||||
|
|
||||||
fun askUpdateTrack() = prefs.getBoolean(keys.askUpdateTrack, false)
|
fun askUpdateTrack() = prefs.getBoolean(Keys.askUpdateTrack, false)
|
||||||
|
|
||||||
fun lastUsedCatalogueSource() = rxPrefs.getLong(keys.lastUsedCatalogueSource, -1)
|
fun lastUsedCatalogueSource() = rxPrefs.getLong(Keys.lastUsedCatalogueSource, -1)
|
||||||
|
|
||||||
fun lastUsedCategory() = rxPrefs.getInteger(keys.lastUsedCategory, 0)
|
fun lastUsedCategory() = rxPrefs.getInteger(Keys.lastUsedCategory, 0)
|
||||||
|
|
||||||
fun lastVersionCode() = rxPrefs.getInteger("last_version_code", 0)
|
fun lastVersionCode() = rxPrefs.getInteger("last_version_code", 0)
|
||||||
|
|
||||||
fun catalogueAsList() = rxPrefs.getBoolean(keys.catalogueAsList, false)
|
fun catalogueAsList() = rxPrefs.getBoolean(Keys.catalogueAsList, false)
|
||||||
|
|
||||||
fun enabledLanguages() = rxPrefs.getStringSet(keys.enabledLanguages, setOf("en"))
|
fun enabledLanguages() = rxPrefs.getStringSet(Keys.enabledLanguages, setOf("en"))
|
||||||
|
|
||||||
fun sourceUsername(source: Source) = prefs.getString(keys.sourceUsername(source.id), "")
|
fun sourceUsername(source: Source) = prefs.getString(Keys.sourceUsername(source.id), "")
|
||||||
|
|
||||||
fun sourcePassword(source: Source) = prefs.getString(keys.sourcePassword(source.id), "")
|
fun sourcePassword(source: Source) = prefs.getString(Keys.sourcePassword(source.id), "")
|
||||||
|
|
||||||
fun setSourceCredentials(source: Source, username: String, password: String) {
|
fun setSourceCredentials(source: Source, username: String, password: String) {
|
||||||
prefs.edit()
|
prefs.edit()
|
||||||
.putString(keys.sourceUsername(source.id), username)
|
.putString(Keys.sourceUsername(source.id), username)
|
||||||
.putString(keys.sourcePassword(source.id), password)
|
.putString(Keys.sourcePassword(source.id), password)
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun trackUsername(sync: TrackService) = prefs.getString(keys.trackUsername(sync.id), "")
|
fun trackUsername(sync: TrackService) = prefs.getString(Keys.trackUsername(sync.id), "")
|
||||||
|
|
||||||
fun trackPassword(sync: TrackService) = prefs.getString(keys.trackPassword(sync.id), "")
|
fun trackPassword(sync: TrackService) = prefs.getString(Keys.trackPassword(sync.id), "")
|
||||||
|
|
||||||
fun setTrackCredentials(sync: TrackService, username: String, password: String) {
|
fun setTrackCredentials(sync: TrackService, username: String, password: String) {
|
||||||
prefs.edit()
|
prefs.edit()
|
||||||
.putString(keys.trackUsername(sync.id), username)
|
.putString(Keys.trackUsername(sync.id), username)
|
||||||
.putString(keys.trackPassword(sync.id), password)
|
.putString(Keys.trackPassword(sync.id), password)
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun trackToken(sync: TrackService) = rxPrefs.getString(keys.trackToken(sync.id), "")
|
fun trackToken(sync: TrackService) = rxPrefs.getString(Keys.trackToken(sync.id), "")
|
||||||
|
|
||||||
fun anilistScoreType() = rxPrefs.getInteger("anilist_score_type", 0)
|
fun anilistScoreType() = rxPrefs.getInteger("anilist_score_type", 0)
|
||||||
|
|
||||||
fun backupsDirectory() = rxPrefs.getString(keys.backupDirectory, defaultBackupDir.toString())
|
fun backupsDirectory() = rxPrefs.getString(Keys.backupDirectory, defaultBackupDir.toString())
|
||||||
|
|
||||||
fun downloadsDirectory() = rxPrefs.getString(keys.downloadsDirectory, defaultDownloadsDir.toString())
|
fun downloadsDirectory() = rxPrefs.getString(Keys.downloadsDirectory, defaultDownloadsDir.toString())
|
||||||
|
|
||||||
fun downloadThreads() = rxPrefs.getInteger(keys.downloadThreads, 1)
|
fun downloadThreads() = rxPrefs.getInteger(Keys.downloadThreads, 1)
|
||||||
|
|
||||||
fun downloadOnlyOverWifi() = prefs.getBoolean(keys.downloadOnlyOverWifi, true)
|
fun downloadOnlyOverWifi() = prefs.getBoolean(Keys.downloadOnlyOverWifi, true)
|
||||||
|
|
||||||
fun numberOfBackups() = rxPrefs.getInteger(keys.numberOfBackups, 1)
|
fun numberOfBackups() = rxPrefs.getInteger(Keys.numberOfBackups, 1)
|
||||||
|
|
||||||
fun backupInterval() = rxPrefs.getInteger(keys.backupInterval, 0)
|
fun backupInterval() = rxPrefs.getInteger(Keys.backupInterval, 0)
|
||||||
|
|
||||||
fun removeAfterReadSlots() = prefs.getInt(keys.removeAfterReadSlots, -1)
|
fun removeAfterReadSlots() = prefs.getInt(Keys.removeAfterReadSlots, -1)
|
||||||
|
|
||||||
fun removeAfterMarkedAsRead() = prefs.getBoolean(keys.removeAfterMarkedAsRead, false)
|
fun removeAfterMarkedAsRead() = prefs.getBoolean(Keys.removeAfterMarkedAsRead, false)
|
||||||
|
|
||||||
fun libraryUpdateInterval() = rxPrefs.getInteger(keys.libraryUpdateInterval, 0)
|
fun libraryUpdateInterval() = rxPrefs.getInteger(Keys.libraryUpdateInterval, 0)
|
||||||
|
|
||||||
fun libraryUpdateRestriction() = prefs.getStringSet(keys.libraryUpdateRestriction, emptySet())
|
fun libraryUpdateRestriction() = prefs.getStringSet(Keys.libraryUpdateRestriction, emptySet())
|
||||||
|
|
||||||
fun libraryUpdateCategories() = rxPrefs.getStringSet(keys.libraryUpdateCategories, emptySet())
|
fun libraryUpdateCategories() = rxPrefs.getStringSet(Keys.libraryUpdateCategories, emptySet())
|
||||||
|
|
||||||
fun libraryAsList() = rxPrefs.getBoolean(keys.libraryAsList, false)
|
fun libraryAsList() = rxPrefs.getBoolean(Keys.libraryAsList, false)
|
||||||
|
|
||||||
fun filterDownloaded() = rxPrefs.getBoolean(keys.filterDownloaded, false)
|
fun filterDownloaded() = rxPrefs.getBoolean(Keys.filterDownloaded, false)
|
||||||
|
|
||||||
fun filterUnread() = rxPrefs.getBoolean(keys.filterUnread, false)
|
fun filterUnread() = rxPrefs.getBoolean(Keys.filterUnread, false)
|
||||||
|
|
||||||
fun librarySortingMode() = rxPrefs.getInteger(keys.librarySortingMode, 0)
|
fun librarySortingMode() = rxPrefs.getInteger(Keys.librarySortingMode, 0)
|
||||||
|
|
||||||
fun librarySortingAscending() = rxPrefs.getBoolean("library_sorting_ascending", true)
|
fun librarySortingAscending() = rxPrefs.getBoolean("library_sorting_ascending", true)
|
||||||
|
|
||||||
fun automaticUpdates() = prefs.getBoolean(keys.automaticUpdates, false)
|
fun automaticUpdates() = prefs.getBoolean(Keys.automaticUpdates, false)
|
||||||
|
|
||||||
fun hiddenCatalogues() = rxPrefs.getStringSet("hidden_catalogues", emptySet())
|
fun hiddenCatalogues() = rxPrefs.getStringSet("hidden_catalogues", emptySet())
|
||||||
|
|
||||||
fun downloadNew() = rxPrefs.getBoolean(keys.downloadNew, false)
|
fun downloadNew() = rxPrefs.getBoolean(Keys.downloadNew, false)
|
||||||
|
|
||||||
fun downloadNewCategories() = rxPrefs.getStringSet(keys.downloadNewCategories, emptySet())
|
fun downloadNewCategories() = rxPrefs.getStringSet(Keys.downloadNewCategories, emptySet())
|
||||||
|
|
||||||
fun lang() = prefs.getString(keys.lang, "")
|
fun lang() = prefs.getString(Keys.lang, "")
|
||||||
|
|
||||||
fun defaultCategory() = prefs.getInt(keys.defaultCategory, -1)
|
fun defaultCategory() = prefs.getInt(Keys.defaultCategory, -1)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import android.view.ViewGroup
|
|||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
import com.bluelinelabs.conductor.ControllerChangeType
|
import com.bluelinelabs.conductor.ControllerChangeType
|
||||||
import com.bluelinelabs.conductor.RestoreViewOnCreateController
|
import com.bluelinelabs.conductor.RestoreViewOnCreateController
|
||||||
import com.bluelinelabs.conductor.Router
|
|
||||||
|
|
||||||
abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateController(bundle) {
|
abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateController(bundle) {
|
||||||
|
|
||||||
@ -45,13 +44,4 @@ abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateContr
|
|||||||
(activity as? AppCompatActivity)?.supportActionBar?.title = getTitle()
|
(activity as? AppCompatActivity)?.supportActionBar?.title = getTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Router.popControllerWithTag(tag: String): Boolean {
|
|
||||||
val controller = getControllerWithTag(tag)
|
|
||||||
if (controller != null) {
|
|
||||||
popController(controller)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.base.controller
|
||||||
|
|
||||||
|
import com.bluelinelabs.conductor.Router
|
||||||
|
|
||||||
|
fun Router.popControllerWithTag(tag: String): Boolean {
|
||||||
|
val controller = getControllerWithTag(tag)
|
||||||
|
if (controller != null) {
|
||||||
|
popController(controller)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.main
|
package eu.kanade.tachiyomi.ui.main
|
||||||
|
|
||||||
import android.animation.ObjectAnimator
|
import android.animation.ObjectAnimator
|
||||||
import android.app.TaskStackBuilder
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@ -25,7 +24,7 @@ import eu.kanade.tachiyomi.ui.library.LibraryController
|
|||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController
|
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController
|
||||||
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController
|
import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController
|
||||||
import eu.kanade.tachiyomi.ui.setting.SettingsActivity
|
import eu.kanade.tachiyomi.ui.setting.SettingsMainController
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
import kotlinx.android.synthetic.main.toolbar.*
|
import kotlinx.android.synthetic.main.toolbar.*
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -85,10 +84,10 @@ class MainActivity : BaseActivity() {
|
|||||||
R.id.nav_drawer_downloads -> {
|
R.id.nav_drawer_downloads -> {
|
||||||
startActivity(Intent(this, DownloadActivity::class.java))
|
startActivity(Intent(this, DownloadActivity::class.java))
|
||||||
}
|
}
|
||||||
R.id.nav_drawer_settings -> {
|
R.id.nav_drawer_settings ->
|
||||||
val intent = Intent(this, SettingsActivity::class.java)
|
router.pushController(RouterTransaction.with(SettingsMainController())
|
||||||
startActivityForResult(intent, REQUEST_OPEN_SETTINGS)
|
.pushChangeHandler(FadeChangeHandler())
|
||||||
}
|
.popChangeHandler(FadeChangeHandler()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drawer.closeDrawer(GravityCompat.START)
|
drawer.closeDrawer(GravityCompat.START)
|
||||||
@ -216,26 +215,7 @@ class MainActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
if (requestCode == REQUEST_OPEN_SETTINGS && resultCode != 0) {
|
|
||||||
if (resultCode and SettingsActivity.FLAG_DATABASE_CLEARED != 0) {
|
|
||||||
// If database is cleared avoid undefined behavior by recreating the stack.
|
|
||||||
TaskStackBuilder.create(this)
|
|
||||||
.addNextIntent(Intent(this, MainActivity::class.java))
|
|
||||||
.startActivities()
|
|
||||||
} else if (resultCode and SettingsActivity.FLAG_THEME_CHANGED != 0) {
|
|
||||||
// Delay activity recreation to avoid fragment leaks.
|
|
||||||
nav_view.post { recreate() }
|
|
||||||
} else if (resultCode and SettingsActivity.FLAG_LANG_CHANGED != 0) {
|
|
||||||
nav_view.post { recreate() }
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val REQUEST_OPEN_SETTINGS = 200
|
|
||||||
// Shortcut actions
|
// Shortcut actions
|
||||||
private const val SHORTCUT_LIBRARY = "eu.kanade.tachiyomi.SHOW_LIBRARY"
|
private const val SHORTCUT_LIBRARY = "eu.kanade.tachiyomi.SHOW_LIBRARY"
|
||||||
private const val SHORTCUT_RECENTLY_UPDATED = "eu.kanade.tachiyomi.SHOW_RECENTLY_UPDATED"
|
private const val SHORTCUT_RECENTLY_UPDATED = "eu.kanade.tachiyomi.SHOW_RECENTLY_UPDATED"
|
||||||
|
@ -19,6 +19,7 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.popControllerWithTag
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.util.getCoordinates
|
import eu.kanade.tachiyomi.util.getCoordinates
|
||||||
|
@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.data.download.model.Download
|
|||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
|
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.popControllerWithTag
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.util.toast
|
import eu.kanade.tachiyomi.util.toast
|
||||||
|
@ -8,6 +8,7 @@ import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
|||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.ProgressBar
|
import android.widget.ProgressBar
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -41,7 +42,7 @@ class AnilistLoginActivity : AppCompatActivity() {
|
|||||||
private fun returnToSettings() {
|
private fun returnToSettings() {
|
||||||
finish()
|
finish()
|
||||||
|
|
||||||
val intent = Intent(this, SettingsActivity::class.java)
|
val intent = Intent(this, MainActivity::class.java)
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,102 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.support.v4.graphics.drawable.DrawableCompat
|
||||||
|
import android.support.v7.preference.*
|
||||||
|
import eu.kanade.tachiyomi.widget.preference.IntListPreference
|
||||||
|
|
||||||
|
@DslMarker
|
||||||
|
@Target(AnnotationTarget.TYPE)
|
||||||
|
annotation class DSL
|
||||||
|
|
||||||
|
inline fun PreferenceManager.newScreen(context: Context, block: (@DSL PreferenceScreen).() -> Unit): PreferenceScreen {
|
||||||
|
return createPreferenceScreen(context).also { it.block() }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun PreferenceGroup.preference(block: (@DSL Preference).() -> Unit): Preference {
|
||||||
|
return initThenAdd(Preference(context), block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun PreferenceGroup.switchPreference(block: (@DSL SwitchPreferenceCompat).() -> Unit): SwitchPreferenceCompat {
|
||||||
|
return initThenAdd(SwitchPreferenceCompat(context), block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun PreferenceGroup.checkBoxPreference(block: (@DSL CheckBoxPreference).() -> Unit): CheckBoxPreference {
|
||||||
|
return initThenAdd(CheckBoxPreference(context), block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun PreferenceGroup.editTextPreference(block: (@DSL EditTextPreference).() -> Unit): EditTextPreference {
|
||||||
|
return initThenAdd(EditTextPreference(context), block).also(::initDialog)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun PreferenceGroup.listPreference(block: (@DSL ListPreference).() -> Unit): ListPreference {
|
||||||
|
return initThenAdd(ListPreference(context), block).also(::initDialog)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun PreferenceGroup.intListPreference(block: (@DSL IntListPreference).() -> Unit): IntListPreference {
|
||||||
|
return initThenAdd(IntListPreference(context), block).also(::initDialog)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun PreferenceGroup.multiSelectListPreference(block: (@DSL MultiSelectListPreference).() -> Unit): MultiSelectListPreference {
|
||||||
|
return initThenAdd(MultiSelectListPreference(context), block).also(::initDialog)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun PreferenceScreen.preferenceCategory(block: (@DSL PreferenceCategory).() -> Unit): PreferenceCategory {
|
||||||
|
return addThenInit(PreferenceCategory(context), block)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun PreferenceScreen.preferenceScreen(block: (@DSL PreferenceScreen).() -> Unit): PreferenceScreen {
|
||||||
|
return addThenInit(preferenceManager.createPreferenceScreen(context), block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initDialog(dialogPreference: DialogPreference) {
|
||||||
|
with(dialogPreference) {
|
||||||
|
if (dialogTitle == null) {
|
||||||
|
dialogTitle = title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <P : Preference> PreferenceGroup.initThenAdd(p: P, block: P.() -> Unit): P {
|
||||||
|
return p.apply { block(); addPreference(this); }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <P : Preference> PreferenceGroup.addThenInit(p: P, block: P.() -> Unit): P {
|
||||||
|
return p.apply { addPreference(this); block() }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun Preference.onClick(crossinline block: () -> Unit) {
|
||||||
|
setOnPreferenceClickListener { block(); true }
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun Preference.onChange(crossinline block: (Any?) -> Boolean) {
|
||||||
|
setOnPreferenceChangeListener { _, newValue -> block(newValue) }
|
||||||
|
}
|
||||||
|
|
||||||
|
var Preference.defaultValue: Any?
|
||||||
|
get() = null // set only
|
||||||
|
set(value) { setDefaultValue(value) }
|
||||||
|
|
||||||
|
var Preference.titleRes: Int
|
||||||
|
get() = 0 // set only
|
||||||
|
set(value) { setTitle(value) }
|
||||||
|
|
||||||
|
var Preference.iconRes: Int
|
||||||
|
get() = 0 // set only
|
||||||
|
set(value) { setIcon(value) }
|
||||||
|
|
||||||
|
var Preference.summaryRes: Int
|
||||||
|
get() = 0 // set only
|
||||||
|
set(value) { setSummary(value) }
|
||||||
|
|
||||||
|
var Preference.iconTint: Int
|
||||||
|
get() = 0 // set only
|
||||||
|
set(value) { DrawableCompat.setTint(icon, value) }
|
||||||
|
|
||||||
|
var ListPreference.entriesRes: Array<Int>
|
||||||
|
get() = emptyArray() // set only
|
||||||
|
set(value) { entries = value.map { context.getString(it) }.toTypedArray() }
|
||||||
|
|
||||||
|
var MultiSelectListPreference.entriesRes: Array<Int>
|
||||||
|
get() = emptyArray() // set only
|
||||||
|
set(value) { entries = value.map { context.getString(it) }.toTypedArray() }
|
@ -0,0 +1,166 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v7.preference.PreferenceScreen
|
||||||
|
import android.view.View
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.updater.GithubUpdateChecker
|
||||||
|
import eu.kanade.tachiyomi.data.updater.GithubUpdateResult
|
||||||
|
import eu.kanade.tachiyomi.data.updater.UpdateCheckerJob
|
||||||
|
import eu.kanade.tachiyomi.data.updater.UpdateDownloaderService
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
|
import eu.kanade.tachiyomi.util.toast
|
||||||
|
import rx.Subscription
|
||||||
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
import rx.schedulers.Schedulers
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.text.DateFormat
|
||||||
|
import java.text.ParseException
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||||
|
|
||||||
|
class SettingsAboutController : SettingsController() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks for new releases
|
||||||
|
*/
|
||||||
|
private val updateChecker by lazy { GithubUpdateChecker() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The subscribtion service of the obtained release object
|
||||||
|
*/
|
||||||
|
private var releaseSubscription: Subscription? = null
|
||||||
|
|
||||||
|
private val isUpdaterEnabled = !BuildConfig.DEBUG && BuildConfig.INCLUDE_UPDATER
|
||||||
|
|
||||||
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||||
|
titleRes = R.string.pref_category_about
|
||||||
|
|
||||||
|
switchPreference {
|
||||||
|
key = "acra.enable"
|
||||||
|
titleRes = R.string.pref_enable_acra
|
||||||
|
summaryRes = R.string.pref_acra_summary
|
||||||
|
defaultValue = true
|
||||||
|
}
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.automaticUpdates
|
||||||
|
titleRes = R.string.pref_enable_automatic_updates
|
||||||
|
summaryRes = R.string.pref_enable_automatic_updates_summary
|
||||||
|
defaultValue = false
|
||||||
|
|
||||||
|
if (isUpdaterEnabled) {
|
||||||
|
onChange { newValue ->
|
||||||
|
val checked = newValue as Boolean
|
||||||
|
if (checked) {
|
||||||
|
UpdateCheckerJob.setupTask()
|
||||||
|
} else {
|
||||||
|
UpdateCheckerJob.cancelTask()
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
titleRes = R.string.version
|
||||||
|
summary = if (BuildConfig.DEBUG)
|
||||||
|
"r" + BuildConfig.COMMIT_COUNT
|
||||||
|
else
|
||||||
|
BuildConfig.VERSION_NAME
|
||||||
|
|
||||||
|
if (isUpdaterEnabled) {
|
||||||
|
onClick { checkVersion() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
titleRes = R.string.build_time
|
||||||
|
summary = getFormattedBuildTime()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView(view: View) {
|
||||||
|
super.onDestroyView(view)
|
||||||
|
releaseSubscription?.unsubscribe()
|
||||||
|
releaseSubscription = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks version and shows a user prompt if an update is available.
|
||||||
|
*/
|
||||||
|
private fun checkVersion() {
|
||||||
|
if (activity == null) return
|
||||||
|
|
||||||
|
activity?.toast(R.string.update_check_look_for_updates)
|
||||||
|
releaseSubscription?.unsubscribe()
|
||||||
|
releaseSubscription = updateChecker.checkForUpdate()
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({ result ->
|
||||||
|
when (result) {
|
||||||
|
is GithubUpdateResult.NewUpdate -> {
|
||||||
|
val body = result.release.changeLog
|
||||||
|
val url = result.release.downloadLink
|
||||||
|
|
||||||
|
// Create confirmation window
|
||||||
|
NewUpdateDialogController(body, url).showDialog(router)
|
||||||
|
}
|
||||||
|
is GithubUpdateResult.NoNewUpdate -> {
|
||||||
|
activity?.toast(R.string.update_check_no_new_updates)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, { error ->
|
||||||
|
Timber.e(error)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
class NewUpdateDialogController(bundle: Bundle? = null) : DialogController(bundle) {
|
||||||
|
|
||||||
|
constructor(body: String, url: String) : this(Bundle().apply {
|
||||||
|
putString(BODY_KEY, body)
|
||||||
|
putString(URL_KEY, url)
|
||||||
|
})
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
return MaterialDialog.Builder(activity!!)
|
||||||
|
.title(R.string.update_check_title)
|
||||||
|
.content(args.getString(BODY_KEY))
|
||||||
|
.positiveText(R.string.update_check_confirm)
|
||||||
|
.negativeText(R.string.update_check_ignore)
|
||||||
|
.onPositive { _, _ ->
|
||||||
|
val appContext = applicationContext
|
||||||
|
if (appContext != null) {
|
||||||
|
// Start download
|
||||||
|
val url = args.getString(URL_KEY)
|
||||||
|
UpdateDownloaderService.downloadUpdate(appContext, url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val BODY_KEY = "NewUpdateDialogController.body"
|
||||||
|
const val URL_KEY = "NewUpdateDialogController.key"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFormattedBuildTime(): String {
|
||||||
|
try {
|
||||||
|
val inputDf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'", Locale.US)
|
||||||
|
inputDf.timeZone = TimeZone.getTimeZone("UTC")
|
||||||
|
val date = inputDf.parse(BuildConfig.BUILD_TIME)
|
||||||
|
|
||||||
|
val outputDf = DateFormat.getDateTimeInstance(
|
||||||
|
DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault())
|
||||||
|
outputDf.timeZone = TimeZone.getDefault()
|
||||||
|
|
||||||
|
return outputDf.format(date)
|
||||||
|
} catch (e: ParseException) {
|
||||||
|
return BuildConfig.BUILD_TIME
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,139 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.setting
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.support.v7.preference.XpPreferenceFragment
|
|
||||||
import android.view.View
|
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.data.updater.GithubUpdateChecker
|
|
||||||
import eu.kanade.tachiyomi.data.updater.GithubUpdateResult
|
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdateCheckerJob
|
|
||||||
import eu.kanade.tachiyomi.data.updater.UpdateDownloaderService
|
|
||||||
import eu.kanade.tachiyomi.util.toast
|
|
||||||
import net.xpece.android.support.preference.SwitchPreference
|
|
||||||
import rx.Subscription
|
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
|
||||||
import rx.schedulers.Schedulers
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.text.DateFormat
|
|
||||||
import java.text.ParseException
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class SettingsAboutFragment : SettingsFragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance(rootKey: String): SettingsAboutFragment {
|
|
||||||
val args = Bundle()
|
|
||||||
args.putString(XpPreferenceFragment.ARG_PREFERENCE_ROOT, rootKey)
|
|
||||||
return SettingsAboutFragment().apply { arguments = args }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks for new releases
|
|
||||||
*/
|
|
||||||
private val updateChecker by lazy { GithubUpdateChecker() }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The subscribtion service of the obtained release object
|
|
||||||
*/
|
|
||||||
private var releaseSubscription: Subscription? = null
|
|
||||||
|
|
||||||
val automaticUpdates: SwitchPreference by bindPref(R.string.pref_enable_automatic_updates_key)
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedState)
|
|
||||||
|
|
||||||
val version = findPreference(getString(R.string.pref_version))
|
|
||||||
val buildTime = findPreference(getString(R.string.pref_build_time))
|
|
||||||
|
|
||||||
version.summary = if (BuildConfig.DEBUG)
|
|
||||||
"r" + BuildConfig.COMMIT_COUNT
|
|
||||||
else
|
|
||||||
BuildConfig.VERSION_NAME
|
|
||||||
|
|
||||||
if (!BuildConfig.DEBUG && BuildConfig.INCLUDE_UPDATER) {
|
|
||||||
//Set onClickListener to check for new version
|
|
||||||
version.setOnPreferenceClickListener {
|
|
||||||
checkVersion()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
automaticUpdates.setOnPreferenceChangeListener { preference, any ->
|
|
||||||
val checked = any as Boolean
|
|
||||||
if (checked) {
|
|
||||||
UpdateCheckerJob.setupTask()
|
|
||||||
} else {
|
|
||||||
UpdateCheckerJob.cancelTask()
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
automaticUpdates.isVisible = false
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTime.summary = getFormattedBuildTime()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
releaseSubscription?.unsubscribe()
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getFormattedBuildTime(): String {
|
|
||||||
try {
|
|
||||||
val inputDf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'")
|
|
||||||
inputDf.timeZone = TimeZone.getTimeZone("UTC")
|
|
||||||
val date = inputDf.parse(BuildConfig.BUILD_TIME)
|
|
||||||
|
|
||||||
val outputDf = DateFormat.getDateTimeInstance(
|
|
||||||
DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault())
|
|
||||||
outputDf.timeZone = TimeZone.getDefault()
|
|
||||||
|
|
||||||
return outputDf.format(date)
|
|
||||||
} catch (e: ParseException) {
|
|
||||||
return BuildConfig.BUILD_TIME
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks version and shows a user prompt if an update is available.
|
|
||||||
*/
|
|
||||||
private fun checkVersion() {
|
|
||||||
releaseSubscription?.unsubscribe()
|
|
||||||
|
|
||||||
context.toast(R.string.update_check_look_for_updates)
|
|
||||||
|
|
||||||
releaseSubscription = updateChecker.checkForUpdate()
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe({ result ->
|
|
||||||
when (result) {
|
|
||||||
is GithubUpdateResult.NewUpdate -> {
|
|
||||||
val body = result.release.changeLog
|
|
||||||
val url = result.release.downloadLink
|
|
||||||
|
|
||||||
// Create confirmation window
|
|
||||||
MaterialDialog.Builder(context)
|
|
||||||
.title(R.string.update_check_title)
|
|
||||||
.content(body)
|
|
||||||
.positiveText(getString(R.string.update_check_confirm))
|
|
||||||
.negativeText(getString(R.string.update_check_ignore))
|
|
||||||
.onPositive { dialog, which ->
|
|
||||||
// Start download
|
|
||||||
UpdateDownloaderService.downloadUpdate(context, url)
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
is GithubUpdateResult.NoNewUpdate -> {
|
|
||||||
context.toast(R.string.update_check_no_new_updates)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, { error ->
|
|
||||||
Timber.e(error)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.setting
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.support.v7.preference.PreferenceFragmentCompat
|
|
||||||
import android.support.v7.preference.PreferenceScreen
|
|
||||||
import android.view.MenuItem
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
|
||||||
import kotlinx.android.synthetic.main.toolbar.*
|
|
||||||
import net.xpece.android.support.preference.PreferenceScreenNavigationStrategy
|
|
||||||
import net.xpece.android.support.preference.PreferenceScreenNavigationStrategy.ReplaceFragment
|
|
||||||
|
|
||||||
class SettingsActivity : BaseActivity(),
|
|
||||||
PreferenceFragmentCompat.OnPreferenceStartScreenCallback,
|
|
||||||
PreferenceScreenNavigationStrategy.ReplaceFragment.Callbacks {
|
|
||||||
|
|
||||||
private lateinit var replaceFragmentStrategy: ReplaceFragment
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flags to send to the parent activity for reacting to preference changes.
|
|
||||||
*/
|
|
||||||
var parentFlags = 0
|
|
||||||
set(value) {
|
|
||||||
field = field or value
|
|
||||||
setResult(field)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedState: Bundle?) {
|
|
||||||
setAppTheme()
|
|
||||||
super.onCreate(savedState)
|
|
||||||
setTitle(R.string.label_settings)
|
|
||||||
setContentView(R.layout.activity_preferences)
|
|
||||||
|
|
||||||
replaceFragmentStrategy = ReplaceFragment(this,
|
|
||||||
R.anim.abc_fade_in, R.anim.abc_fade_out,
|
|
||||||
R.anim.abc_fade_in, R.anim.abc_fade_out)
|
|
||||||
|
|
||||||
if (savedState == null) {
|
|
||||||
supportFragmentManager.beginTransaction()
|
|
||||||
.add(R.id.settings_content, SettingsFragment.newInstance(null), "Settings")
|
|
||||||
.commit()
|
|
||||||
} else {
|
|
||||||
parentFlags = savedState.getInt(SettingsActivity::parentFlags.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
setupToolbar(toolbar, backNavigation = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
|
||||||
outState.putInt(SettingsActivity::parentFlags.name, parentFlags)
|
|
||||||
super.onSaveInstanceState(outState)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
||||||
when (item.itemId) {
|
|
||||||
android.R.id.home -> onBackPressed()
|
|
||||||
else -> return super.onOptionsItemSelected(item)
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBuildPreferenceFragment(key: String?): PreferenceFragmentCompat {
|
|
||||||
return when (key) {
|
|
||||||
"general_screen" -> SettingsGeneralFragment.newInstance(key)
|
|
||||||
"downloads_screen" -> SettingsDownloadsFragment.newInstance(key)
|
|
||||||
"sources_screen" -> SettingsSourcesFragment.newInstance(key)
|
|
||||||
"tracking_screen" -> SettingsTrackingFragment.newInstance(key)
|
|
||||||
"backup_screen" -> SettingsBackupFragment.newInstance(key)
|
|
||||||
"advanced_screen" -> SettingsAdvancedFragment.newInstance(key)
|
|
||||||
"about_screen" -> SettingsAboutFragment.newInstance(key)
|
|
||||||
else -> SettingsFragment.newInstance(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPreferenceStartScreen(p0: PreferenceFragmentCompat, p1: PreferenceScreen): Boolean {
|
|
||||||
replaceFragmentStrategy.onPreferenceStartScreen(supportFragmentManager, p0, p1)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val FLAG_THEME_CHANGED = 0x1
|
|
||||||
const val FLAG_DATABASE_CLEARED = 0x2
|
|
||||||
const val FLAG_LANG_CHANGED = 0x4
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,159 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v7.preference.PreferenceScreen
|
||||||
|
import android.view.View
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import com.bluelinelabs.conductor.RouterTransaction
|
||||||
|
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||||
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||||
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
|
import eu.kanade.tachiyomi.ui.library.LibraryController
|
||||||
|
import eu.kanade.tachiyomi.util.toast
|
||||||
|
import rx.Observable
|
||||||
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
import rx.schedulers.Schedulers
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
class SettingsAdvancedController : SettingsController() {
|
||||||
|
|
||||||
|
private val network: NetworkHelper by injectLazy()
|
||||||
|
|
||||||
|
private val chapterCache: ChapterCache by injectLazy()
|
||||||
|
|
||||||
|
private val db: DatabaseHelper by injectLazy()
|
||||||
|
|
||||||
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||||
|
titleRes = R.string.pref_category_advanced
|
||||||
|
|
||||||
|
preference {
|
||||||
|
key = CLEAR_CACHE_KEY
|
||||||
|
titleRes = R.string.pref_clear_chapter_cache
|
||||||
|
summary = context.getString(R.string.used_cache, chapterCache.readableSize)
|
||||||
|
|
||||||
|
onClick { clearChapterCache() }
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
titleRes = R.string.pref_clear_cookies
|
||||||
|
|
||||||
|
onClick {
|
||||||
|
network.cookies.removeAll()
|
||||||
|
activity?.toast(R.string.cookies_cleared)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
titleRes = R.string.pref_clear_database
|
||||||
|
summaryRes = R.string.pref_clear_database_summary
|
||||||
|
|
||||||
|
onClick {
|
||||||
|
val ctrl = ClearDatabaseDialogController()
|
||||||
|
ctrl.targetController = this@SettingsAdvancedController
|
||||||
|
ctrl.showDialog(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
titleRes = R.string.pref_refresh_library_metadata
|
||||||
|
summaryRes = R.string.pref_refresh_library_metadata_summary
|
||||||
|
|
||||||
|
onClick { LibraryUpdateService.start(context, details = true) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearChapterCache() {
|
||||||
|
if (activity == null) return
|
||||||
|
val files = chapterCache.cacheDir.listFiles() ?: return
|
||||||
|
|
||||||
|
var deletedFiles = 0
|
||||||
|
|
||||||
|
val ctrl = DeletingFilesDialogController()
|
||||||
|
ctrl.total = files.size
|
||||||
|
ctrl.showDialog(router)
|
||||||
|
|
||||||
|
Observable.defer { Observable.from(files) }
|
||||||
|
.doOnNext { file ->
|
||||||
|
if (chapterCache.removeFileFromCache(file.name)) {
|
||||||
|
deletedFiles++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({
|
||||||
|
ctrl.setProgress(deletedFiles)
|
||||||
|
}, {
|
||||||
|
activity?.toast(R.string.cache_delete_error)
|
||||||
|
}, {
|
||||||
|
ctrl.finish()
|
||||||
|
activity?.toast(resources?.getString(R.string.cache_deleted, deletedFiles))
|
||||||
|
findPreference(CLEAR_CACHE_KEY)?.summary =
|
||||||
|
resources?.getString(R.string.used_cache, chapterCache.readableSize)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
class DeletingFilesDialogController : DialogController() {
|
||||||
|
|
||||||
|
var total = 0
|
||||||
|
|
||||||
|
private var materialDialog: MaterialDialog? = null
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
return MaterialDialog.Builder(activity!!)
|
||||||
|
.title(R.string.deleting)
|
||||||
|
.progress(false, total, true)
|
||||||
|
.cancelable(false)
|
||||||
|
.build()
|
||||||
|
.also { materialDialog = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView(view: View) {
|
||||||
|
super.onDestroyView(view)
|
||||||
|
materialDialog = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||||
|
super.onRestoreInstanceState(savedInstanceState)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setProgress(deletedFiles: Int) {
|
||||||
|
materialDialog?.setProgress(deletedFiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun finish() {
|
||||||
|
router.popController(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClearDatabaseDialogController : DialogController() {
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
return MaterialDialog.Builder(activity!!)
|
||||||
|
.content(R.string.clear_database_confirmation)
|
||||||
|
.positiveText(android.R.string.yes)
|
||||||
|
.negativeText(android.R.string.no)
|
||||||
|
.onPositive { _, _ ->
|
||||||
|
(targetController as? SettingsAdvancedController)?.clearDatabase()
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearDatabase() {
|
||||||
|
// Avoid weird behavior by going back to the library.
|
||||||
|
val newBackstack = listOf(RouterTransaction.with(LibraryController())) +
|
||||||
|
router.backstack.drop(1)
|
||||||
|
|
||||||
|
router.setBackstack(newBackstack, FadeChangeHandler())
|
||||||
|
|
||||||
|
db.deleteMangasNotInLibrary().executeAsBlocking()
|
||||||
|
db.deleteHistoryNoLastRead().executeAsBlocking()
|
||||||
|
activity?.toast(R.string.clear_database_completed)
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val CLEAR_CACHE_KEY = "pref_clear_cache_key"
|
||||||
|
}
|
||||||
|
}
|
@ -1,117 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.setting
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.support.v7.preference.Preference
|
|
||||||
import android.support.v7.preference.XpPreferenceFragment
|
|
||||||
import android.view.View
|
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
|
||||||
import eu.kanade.tachiyomi.util.plusAssign
|
|
||||||
import eu.kanade.tachiyomi.util.toast
|
|
||||||
import rx.Observable
|
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
|
||||||
import rx.schedulers.Schedulers
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
|
||||||
|
|
||||||
class SettingsAdvancedFragment : SettingsFragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance(rootKey: String): SettingsAdvancedFragment {
|
|
||||||
val args = Bundle()
|
|
||||||
args.putString(XpPreferenceFragment.ARG_PREFERENCE_ROOT, rootKey)
|
|
||||||
return SettingsAdvancedFragment().apply { arguments = args }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val network: NetworkHelper by injectLazy()
|
|
||||||
|
|
||||||
private val chapterCache: ChapterCache by injectLazy()
|
|
||||||
|
|
||||||
private val db: DatabaseHelper by injectLazy()
|
|
||||||
|
|
||||||
private val clearCache: Preference by bindPref(R.string.pref_clear_chapter_cache_key)
|
|
||||||
|
|
||||||
private val clearDatabase: Preference by bindPref(R.string.pref_clear_database_key)
|
|
||||||
|
|
||||||
private val clearCookies: Preference by bindPref(R.string.pref_clear_cookies_key)
|
|
||||||
|
|
||||||
private val refreshMetadata: Preference by bindPref(R.string.pref_refresh_library_metadata_key)
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedState)
|
|
||||||
|
|
||||||
clearCache.setOnPreferenceClickListener {
|
|
||||||
clearChapterCache()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
clearCache.summary = getString(R.string.used_cache, chapterCache.readableSize)
|
|
||||||
|
|
||||||
clearCookies.setOnPreferenceClickListener {
|
|
||||||
network.cookies.removeAll()
|
|
||||||
activity.toast(R.string.cookies_cleared)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
clearDatabase.setOnPreferenceClickListener {
|
|
||||||
clearDatabase()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshMetadata.setOnPreferenceClickListener {
|
|
||||||
LibraryUpdateService.start(context, details = true)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun clearChapterCache() {
|
|
||||||
val deletedFiles = AtomicInteger()
|
|
||||||
|
|
||||||
val files = chapterCache.cacheDir.listFiles() ?: return
|
|
||||||
|
|
||||||
val dialog = MaterialDialog.Builder(activity)
|
|
||||||
.title(R.string.deleting)
|
|
||||||
.progress(false, files.size, true)
|
|
||||||
.cancelable(false)
|
|
||||||
.show()
|
|
||||||
|
|
||||||
subscriptions += Observable.defer { Observable.from(files) }
|
|
||||||
.concatMap { file ->
|
|
||||||
if (chapterCache.removeFileFromCache(file.name)) {
|
|
||||||
deletedFiles.incrementAndGet()
|
|
||||||
}
|
|
||||||
Observable.just(file)
|
|
||||||
}
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe({
|
|
||||||
dialog.incrementProgress(1)
|
|
||||||
}, {
|
|
||||||
dialog.dismiss()
|
|
||||||
activity.toast(R.string.cache_delete_error)
|
|
||||||
}, {
|
|
||||||
dialog.dismiss()
|
|
||||||
activity.toast(getString(R.string.cache_deleted, deletedFiles.get()))
|
|
||||||
clearCache.summary = getString(R.string.used_cache, chapterCache.readableSize)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun clearDatabase() {
|
|
||||||
MaterialDialog.Builder(activity)
|
|
||||||
.content(R.string.clear_database_confirmation)
|
|
||||||
.positiveText(android.R.string.yes)
|
|
||||||
.negativeText(android.R.string.no)
|
|
||||||
.onPositive { dialog, which ->
|
|
||||||
(activity as SettingsActivity).parentFlags = SettingsActivity.FLAG_DATABASE_CLEARED
|
|
||||||
db.deleteMangasNotInLibrary().executeAsBlocking()
|
|
||||||
db.deleteHistoryNoLastRead().executeAsBlocking()
|
|
||||||
activity.toast(R.string.clear_database_completed)
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,458 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
|
import android.Manifest.permission.READ_EXTERNAL_STORAGE
|
||||||
|
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v7.preference.PreferenceScreen
|
||||||
|
import android.view.View
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import com.hippo.unifile.UniFile
|
||||||
|
import com.nononsenseapps.filepicker.FilePickerActivity
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.backup.BackupConst
|
||||||
|
import eu.kanade.tachiyomi.data.backup.BackupCreateService
|
||||||
|
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
|
||||||
|
import eu.kanade.tachiyomi.data.backup.BackupRestoreService
|
||||||
|
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.popControllerWithTag
|
||||||
|
import eu.kanade.tachiyomi.util.getUriCompat
|
||||||
|
import eu.kanade.tachiyomi.util.registerLocalReceiver
|
||||||
|
import eu.kanade.tachiyomi.util.toast
|
||||||
|
import eu.kanade.tachiyomi.util.unregisterLocalReceiver
|
||||||
|
import eu.kanade.tachiyomi.widget.CustomLayoutPickerActivity
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.io.File
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||||
|
|
||||||
|
class SettingsBackupController : SettingsController() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags containing information of what to backup.
|
||||||
|
*/
|
||||||
|
private var backupFlags = 0
|
||||||
|
|
||||||
|
private val receiver = BackupBroadcastReceiver()
|
||||||
|
|
||||||
|
init {
|
||||||
|
preferences.context.registerLocalReceiver(receiver, IntentFilter(BackupConst.INTENT_FILTER))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
requestPermissions(arrayOf(WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE), 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
preferences.context.unregisterLocalReceiver(receiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||||
|
titleRes = R.string.backup
|
||||||
|
|
||||||
|
preference {
|
||||||
|
titleRes = R.string.pref_create_backup
|
||||||
|
summaryRes = R.string.pref_create_backup_summ
|
||||||
|
|
||||||
|
onClick {
|
||||||
|
val ctrl = CreateBackupDialog()
|
||||||
|
ctrl.targetController = this@SettingsBackupController
|
||||||
|
ctrl.showDialog(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
titleRes = R.string.pref_restore_backup
|
||||||
|
summaryRes = R.string.pref_restore_backup_summ
|
||||||
|
|
||||||
|
onClick {
|
||||||
|
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||||
|
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
intent.type = "application/*"
|
||||||
|
val title = resources?.getString(R.string.file_select_backup)
|
||||||
|
val chooser = Intent.createChooser(intent, title)
|
||||||
|
startActivityForResult(chooser, CODE_BACKUP_RESTORE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preferenceCategory {
|
||||||
|
titleRes = R.string.pref_backup_service_category
|
||||||
|
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.backupInterval
|
||||||
|
titleRes = R.string.pref_backup_interval
|
||||||
|
entriesRes = arrayOf(R.string.update_never, R.string.update_6hour,
|
||||||
|
R.string.update_12hour, R.string.update_24hour,
|
||||||
|
R.string.update_48hour, R.string.update_weekly)
|
||||||
|
entryValues = arrayOf("0", "6", "12", "24", "168")
|
||||||
|
defaultValue = "0"
|
||||||
|
summary = "%s"
|
||||||
|
|
||||||
|
onChange { newValue ->
|
||||||
|
// Always cancel the previous task, it seems that sometimes they are not updated
|
||||||
|
BackupCreatorJob.cancelTask()
|
||||||
|
|
||||||
|
val interval = (newValue as String).toInt()
|
||||||
|
if (interval > 0) {
|
||||||
|
BackupCreatorJob.setupTask(interval)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val backupDir = preference {
|
||||||
|
key = Keys.backupDirectory
|
||||||
|
titleRes = R.string.pref_backup_directory
|
||||||
|
|
||||||
|
onClick {
|
||||||
|
val currentDir = preferences.backupsDirectory().getOrDefault()
|
||||||
|
|
||||||
|
val intent = if (Build.VERSION.SDK_INT < 21) {
|
||||||
|
// Custom dir selected, open directory selector
|
||||||
|
val i = Intent(activity, CustomLayoutPickerActivity::class.java)
|
||||||
|
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
|
||||||
|
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
|
||||||
|
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR)
|
||||||
|
i.putExtra(FilePickerActivity.EXTRA_START_PATH, currentDir)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||||
|
}
|
||||||
|
startActivityForResult(intent, CODE_BACKUP_DIR)
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences.backupsDirectory().asObservable()
|
||||||
|
.subscribeUntilDestroy { path ->
|
||||||
|
val dir = UniFile.fromUri(context, Uri.parse(path))
|
||||||
|
summary = dir.filePath ?: path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val backupNumber = intListPreference {
|
||||||
|
key = Keys.numberOfBackups
|
||||||
|
titleRes = R.string.pref_backup_slots
|
||||||
|
entries = arrayOf("1", "2", "3", "4", "5")
|
||||||
|
entryValues = entries
|
||||||
|
defaultValue = "1"
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences.backupInterval().asObservable()
|
||||||
|
.subscribeUntilDestroy {
|
||||||
|
backupDir.isVisible = it > 0
|
||||||
|
backupNumber.isVisible = it > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
when (requestCode) {
|
||||||
|
CODE_BACKUP_DIR -> if (data != null && resultCode == Activity.RESULT_OK) {
|
||||||
|
val activity = activity ?: return
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
val uri = Uri.fromFile(File(data.data.path))
|
||||||
|
preferences.backupsDirectory().set(uri.toString())
|
||||||
|
} else {
|
||||||
|
val uri = data.data
|
||||||
|
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||||
|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
|
|
||||||
|
activity.contentResolver.takePersistableUriPermission(uri, flags)
|
||||||
|
|
||||||
|
val file = UniFile.fromUri(activity, uri)
|
||||||
|
preferences.backupsDirectory().set(file.uri.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CODE_BACKUP_CREATE -> if (data != null && resultCode == Activity.RESULT_OK) {
|
||||||
|
val activity = activity ?: return
|
||||||
|
val path = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
val dir = data.data.path
|
||||||
|
val file = File(dir, Backup.getDefaultFilename())
|
||||||
|
|
||||||
|
file.absolutePath
|
||||||
|
} else {
|
||||||
|
val uri = data.data
|
||||||
|
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||||
|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
|
|
||||||
|
activity.contentResolver.takePersistableUriPermission(uri, flags)
|
||||||
|
val file = UniFile.fromUri(activity, uri)
|
||||||
|
|
||||||
|
file.uri.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
CreatingBackupDialog().showDialog(router, TAG_CREATING_BACKUP_DIALOG)
|
||||||
|
BackupCreateService.makeBackup(activity, path, backupFlags)
|
||||||
|
}
|
||||||
|
CODE_BACKUP_RESTORE -> if (data != null && resultCode == Activity.RESULT_OK) {
|
||||||
|
val uri = data.data
|
||||||
|
RestoreBackupDialog(uri).showDialog(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createBackup(flags: Int) {
|
||||||
|
backupFlags = flags
|
||||||
|
|
||||||
|
// If API lower as KitKat use custom dir picker
|
||||||
|
val intent = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
// Get dirs
|
||||||
|
val preferences: PreferencesHelper = Injekt.get()
|
||||||
|
val currentDir = preferences.backupsDirectory().getOrDefault()
|
||||||
|
|
||||||
|
Intent(activity, CustomLayoutPickerActivity::class.java)
|
||||||
|
.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
|
||||||
|
.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
|
||||||
|
.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR)
|
||||||
|
.putExtra(FilePickerActivity.EXTRA_START_PATH, currentDir)
|
||||||
|
} else {
|
||||||
|
// Use Androids build in file creator
|
||||||
|
Intent(Intent.ACTION_CREATE_DOCUMENT)
|
||||||
|
.addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
.setType("application/*")
|
||||||
|
.putExtra(Intent.EXTRA_TITLE, Backup.getDefaultFilename())
|
||||||
|
}
|
||||||
|
startActivityForResult(intent, CODE_BACKUP_CREATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreateBackupDialog : DialogController() {
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
return MaterialDialog.Builder(activity!!)
|
||||||
|
.title(R.string.pref_create_backup)
|
||||||
|
.content(R.string.backup_choice)
|
||||||
|
.items(R.array.backup_options)
|
||||||
|
.itemsDisabledIndices(0)
|
||||||
|
.itemsCallbackMultiChoice(arrayOf(0, 1, 2, 3, 4), { _, positions, _ ->
|
||||||
|
var flags = 0
|
||||||
|
for (i in 1..positions.size - 1) {
|
||||||
|
when (positions[i]) {
|
||||||
|
1 -> flags = flags or BackupCreateService.BACKUP_CATEGORY
|
||||||
|
2 -> flags = flags or BackupCreateService.BACKUP_CHAPTER
|
||||||
|
3 -> flags = flags or BackupCreateService.BACKUP_TRACK
|
||||||
|
4 -> flags = flags or BackupCreateService.BACKUP_HISTORY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(targetController as? SettingsBackupController)?.createBackup(flags)
|
||||||
|
true
|
||||||
|
})
|
||||||
|
.positiveText(R.string.action_create)
|
||||||
|
.negativeText(android.R.string.cancel)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreatingBackupDialog : DialogController() {
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
return MaterialDialog.Builder(activity!!)
|
||||||
|
.title(R.string.backup)
|
||||||
|
.content(R.string.creating_backup)
|
||||||
|
.progress(true, 0)
|
||||||
|
.cancelable(false)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||||
|
super.onRestoreInstanceState(savedInstanceState)
|
||||||
|
router.popController(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreatedBackupDialog(bundle: Bundle? = null) : DialogController(bundle) {
|
||||||
|
constructor(uri: Uri) : this(Bundle().apply {
|
||||||
|
putParcelable(KEY_URI, uri)
|
||||||
|
})
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
val activity = activity!!
|
||||||
|
val unifile = UniFile.fromUri(activity, args.getParcelable<Uri>(KEY_URI))
|
||||||
|
return MaterialDialog.Builder(activity)
|
||||||
|
.title(R.string.backup_created)
|
||||||
|
.content(activity.getString(R.string.file_saved, unifile.filePath))
|
||||||
|
.positiveText(R.string.action_close)
|
||||||
|
.negativeText(R.string.action_export)
|
||||||
|
.onNegative { _, _ ->
|
||||||
|
val sendIntent = Intent(Intent.ACTION_SEND)
|
||||||
|
sendIntent.type = "application/json"
|
||||||
|
sendIntent.putExtra(Intent.EXTRA_STREAM, unifile.uri)
|
||||||
|
startActivity(Intent.createChooser(sendIntent, ""))
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val KEY_URI = "BackupCreatedDialog.uri"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RestoreBackupDialog(bundle: Bundle? = null) : DialogController(bundle) {
|
||||||
|
constructor(uri: Uri) : this(Bundle().apply {
|
||||||
|
putParcelable(KEY_URI, uri)
|
||||||
|
})
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
return MaterialDialog.Builder(activity!!)
|
||||||
|
.title(R.string.pref_restore_backup)
|
||||||
|
.content(R.string.backup_restore_content)
|
||||||
|
.positiveText(R.string.action_restore)
|
||||||
|
.onPositive { _, _ ->
|
||||||
|
val context = applicationContext
|
||||||
|
if (context != null) {
|
||||||
|
RestoringBackupDialog().showDialog(router, TAG_RESTORING_BACKUP_DIALOG)
|
||||||
|
BackupRestoreService.start(context, args.getParcelable<Uri>(KEY_URI))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val KEY_URI = "RestoreBackupDialog.uri"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RestoringBackupDialog : DialogController() {
|
||||||
|
private var materialDialog: MaterialDialog? = null
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
return MaterialDialog.Builder(activity!!)
|
||||||
|
.title(R.string.backup)
|
||||||
|
.content(R.string.restoring_backup)
|
||||||
|
.progress(false, 100, true)
|
||||||
|
.cancelable(false)
|
||||||
|
.negativeText(R.string.action_stop)
|
||||||
|
.onNegative { _, _ ->
|
||||||
|
applicationContext?.let { BackupRestoreService.stop(it) }
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
.also { materialDialog = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView(view: View) {
|
||||||
|
super.onDestroyView(view)
|
||||||
|
materialDialog = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||||
|
super.onRestoreInstanceState(savedInstanceState)
|
||||||
|
router.popController(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateProgress(content: String?, progress: Int, amount: Int) {
|
||||||
|
val dialog = materialDialog ?: return
|
||||||
|
dialog.setContent(content)
|
||||||
|
dialog.setProgress(progress)
|
||||||
|
dialog.maxProgress = amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RestoredBackupDialog(bundle: Bundle? = null) : DialogController(bundle) {
|
||||||
|
constructor(time: Long, errorCount: Int, path: String, file: String) : this(Bundle().apply {
|
||||||
|
putLong(KEY_TIME, time)
|
||||||
|
putInt(KEY_ERROR_COUNT, errorCount)
|
||||||
|
putString(KEY_PATH, path)
|
||||||
|
putString(KEY_FILE, file)
|
||||||
|
})
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
val activity = activity!!
|
||||||
|
val time = args.getLong(KEY_TIME)
|
||||||
|
val errors = args.getInt(KEY_ERROR_COUNT)
|
||||||
|
val path = args.getString(KEY_PATH)
|
||||||
|
val file = args.getString(KEY_FILE)
|
||||||
|
val timeString = String.format("%02d min, %02d sec",
|
||||||
|
TimeUnit.MILLISECONDS.toMinutes(time),
|
||||||
|
TimeUnit.MILLISECONDS.toSeconds(time) - TimeUnit.MINUTES.toSeconds(
|
||||||
|
TimeUnit.MILLISECONDS.toMinutes(time))
|
||||||
|
)
|
||||||
|
|
||||||
|
return MaterialDialog.Builder(activity)
|
||||||
|
.title(R.string.restore_completed)
|
||||||
|
.content(activity.getString(R.string.restore_completed_content, timeString,
|
||||||
|
if (errors > 0) "$errors" else activity.getString(android.R.string.no)))
|
||||||
|
.positiveText(R.string.action_close)
|
||||||
|
.negativeText(R.string.action_open_log)
|
||||||
|
.onNegative { _, _ ->
|
||||||
|
val context = applicationContext ?: return@onNegative
|
||||||
|
if (!path.isEmpty()) {
|
||||||
|
val destFile = File(path, file)
|
||||||
|
val uri = destFile.getUriCompat(context)
|
||||||
|
val sendIntent = Intent(Intent.ACTION_VIEW).apply {
|
||||||
|
setDataAndType(uri, "text/plain")
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK or
|
||||||
|
Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
|
}
|
||||||
|
startActivity(sendIntent)
|
||||||
|
} else {
|
||||||
|
context.toast(context.getString(R.string.error_opening_log))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val KEY_TIME = "RestoredBackupDialog.time"
|
||||||
|
const val KEY_ERROR_COUNT = "RestoredBackupDialog.errors"
|
||||||
|
const val KEY_PATH = "RestoredBackupDialog.path"
|
||||||
|
const val KEY_FILE = "RestoredBackupDialog.file"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class BackupBroadcastReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
when (intent.getStringExtra(BackupConst.ACTION)) {
|
||||||
|
BackupConst.ACTION_BACKUP_COMPLETED_DIALOG -> {
|
||||||
|
router.popControllerWithTag(TAG_CREATING_BACKUP_DIALOG)
|
||||||
|
val uri = Uri.parse(intent.getStringExtra(BackupConst.EXTRA_URI))
|
||||||
|
CreatedBackupDialog(uri).showDialog(router)
|
||||||
|
}
|
||||||
|
BackupConst.ACTION_SET_PROGRESS_DIALOG -> {
|
||||||
|
val progress = intent.getIntExtra(BackupConst.EXTRA_PROGRESS, 0)
|
||||||
|
val amount = intent.getIntExtra(BackupConst.EXTRA_AMOUNT, 0)
|
||||||
|
val content = intent.getStringExtra(BackupConst.EXTRA_CONTENT)
|
||||||
|
(router.getControllerWithTag(TAG_RESTORING_BACKUP_DIALOG)
|
||||||
|
as? RestoringBackupDialog)?.updateProgress(content, progress, amount)
|
||||||
|
}
|
||||||
|
BackupConst.ACTION_RESTORE_COMPLETED_DIALOG -> {
|
||||||
|
router.popControllerWithTag(TAG_RESTORING_BACKUP_DIALOG)
|
||||||
|
val time = intent.getLongExtra(BackupConst.EXTRA_TIME, 0)
|
||||||
|
val errors = intent.getIntExtra(BackupConst.EXTRA_ERRORS, 0)
|
||||||
|
val path = intent.getStringExtra(BackupConst.EXTRA_ERROR_FILE_PATH)
|
||||||
|
val file = intent.getStringExtra(BackupConst.EXTRA_ERROR_FILE)
|
||||||
|
if (errors > 0) {
|
||||||
|
RestoredBackupDialog(time, errors, path, file).showDialog(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BackupConst.ACTION_ERROR_BACKUP_DIALOG -> {
|
||||||
|
router.popControllerWithTag(TAG_CREATING_BACKUP_DIALOG)
|
||||||
|
context.toast(intent.getStringExtra(BackupConst.EXTRA_ERROR_MESSAGE))
|
||||||
|
}
|
||||||
|
BackupConst.ACTION_ERROR_RESTORE_DIALOG -> {
|
||||||
|
router.popControllerWithTag(TAG_RESTORING_BACKUP_DIALOG)
|
||||||
|
context.toast(intent.getStringExtra(BackupConst.EXTRA_ERROR_MESSAGE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val CODE_BACKUP_CREATE = 501
|
||||||
|
const val CODE_BACKUP_RESTORE = 502
|
||||||
|
const val CODE_BACKUP_DIR = 503
|
||||||
|
|
||||||
|
const val TAG_CREATING_BACKUP_DIALOG = "CreatingBackupDialog"
|
||||||
|
const val TAG_RESTORING_BACKUP_DIALOG = "RestoringBackupDialog"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,407 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.setting
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.IntentFilter
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.support.v7.preference.XpPreferenceFragment
|
|
||||||
import android.view.View
|
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
|
||||||
import com.hippo.unifile.UniFile
|
|
||||||
import com.nononsenseapps.filepicker.FilePickerActivity
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupCreateService
|
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
|
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupRestoreService
|
|
||||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
|
||||||
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
|
|
||||||
import eu.kanade.tachiyomi.util.*
|
|
||||||
import eu.kanade.tachiyomi.widget.CustomLayoutPickerActivity
|
|
||||||
import eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
import net.xpece.android.support.preference.Preference
|
|
||||||
import rx.subscriptions.Subscriptions
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.io.File
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Settings for [BackupCreateService] and [BackupRestoreService]
|
|
||||||
*/
|
|
||||||
class SettingsBackupFragment : SettingsFragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val INTENT_FILTER = "SettingsBackupFragment"
|
|
||||||
const val ACTION_BACKUP_COMPLETED_DIALOG = "$ID.$INTENT_FILTER.ACTION_BACKUP_COMPLETED_DIALOG"
|
|
||||||
const val ACTION_SET_PROGRESS_DIALOG = "$ID.$INTENT_FILTER.ACTION_SET_PROGRESS_DIALOG"
|
|
||||||
const val ACTION_ERROR_BACKUP_DIALOG = "$ID.$INTENT_FILTER.ACTION_ERROR_BACKUP_DIALOG"
|
|
||||||
const val ACTION_ERROR_RESTORE_DIALOG = "$ID.$INTENT_FILTER.ACTION_ERROR_RESTORE_DIALOG"
|
|
||||||
const val ACTION_RESTORE_COMPLETED_DIALOG = "$ID.$INTENT_FILTER.ACTION_RESTORE_COMPLETED_DIALOG"
|
|
||||||
const val ACTION = "$ID.$INTENT_FILTER.ACTION"
|
|
||||||
const val EXTRA_PROGRESS = "$ID.$INTENT_FILTER.EXTRA_PROGRESS"
|
|
||||||
const val EXTRA_AMOUNT = "$ID.$INTENT_FILTER.EXTRA_AMOUNT"
|
|
||||||
const val EXTRA_ERRORS = "$ID.$INTENT_FILTER.EXTRA_ERRORS"
|
|
||||||
const val EXTRA_CONTENT = "$ID.$INTENT_FILTER.EXTRA_CONTENT"
|
|
||||||
const val EXTRA_ERROR_MESSAGE = "$ID.$INTENT_FILTER.EXTRA_ERROR_MESSAGE"
|
|
||||||
const val EXTRA_URI = "$ID.$INTENT_FILTER.EXTRA_URI"
|
|
||||||
const val EXTRA_TIME = "$ID.$INTENT_FILTER.EXTRA_TIME"
|
|
||||||
const val EXTRA_ERROR_FILE_PATH = "$ID.$INTENT_FILTER.EXTRA_ERROR_FILE_PATH"
|
|
||||||
const val EXTRA_ERROR_FILE = "$ID.$INTENT_FILTER.EXTRA_ERROR_FILE"
|
|
||||||
|
|
||||||
private const val BACKUP_CREATE = 201
|
|
||||||
private const val BACKUP_RESTORE = 202
|
|
||||||
private const val BACKUP_DIR = 203
|
|
||||||
|
|
||||||
fun newInstance(rootKey: String): SettingsBackupFragment {
|
|
||||||
val args = Bundle()
|
|
||||||
args.putString(XpPreferenceFragment.ARG_PREFERENCE_ROOT, rootKey)
|
|
||||||
return SettingsBackupFragment().apply { arguments = args }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Preference selected to create backup
|
|
||||||
*/
|
|
||||||
private val createBackup: Preference by bindPref(R.string.pref_create_local_backup_key)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Preference selected to restore backup
|
|
||||||
*/
|
|
||||||
private val restoreBackup: Preference by bindPref(R.string.pref_restore_local_backup_key)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Preference which determines the frequency of automatic backups.
|
|
||||||
*/
|
|
||||||
private val automaticBackup: IntListPreference by bindPref(R.string.pref_backup_interval_key)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Preference containing number of automatic backups
|
|
||||||
*/
|
|
||||||
private val backupSlots: IntListPreference by bindPref(R.string.pref_backup_slots_key)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Preference containing interval of automatic backups
|
|
||||||
*/
|
|
||||||
private val backupDirPref: Preference by bindPref(R.string.pref_backup_directory_key)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Preferences
|
|
||||||
*/
|
|
||||||
private val preferences: PreferencesHelper by injectLazy()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Value containing information on what to backup
|
|
||||||
*/
|
|
||||||
private var backup_flags = 0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The root directory for backups..
|
|
||||||
*/
|
|
||||||
private var backupDir = preferences.backupsDirectory().getOrDefault().let {
|
|
||||||
UniFile.fromUri(context, Uri.parse(it))
|
|
||||||
}
|
|
||||||
|
|
||||||
val restoreDialog: MaterialDialog by lazy {
|
|
||||||
MaterialDialog.Builder(context)
|
|
||||||
.title(R.string.backup)
|
|
||||||
.content(R.string.restoring_backup)
|
|
||||||
.progress(false, 100, true)
|
|
||||||
.cancelable(false)
|
|
||||||
.negativeText(R.string.action_stop)
|
|
||||||
.onNegative { materialDialog, _ ->
|
|
||||||
BackupRestoreService.stop(context)
|
|
||||||
materialDialog.dismiss()
|
|
||||||
}
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
val backupDialog: MaterialDialog by lazy {
|
|
||||||
MaterialDialog.Builder(context)
|
|
||||||
.title(R.string.backup)
|
|
||||||
.content(R.string.creating_backup)
|
|
||||||
.progress(true, 0)
|
|
||||||
.cancelable(false)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val receiver = object : BroadcastReceiver() {
|
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
when (intent.getStringExtra(ACTION)) {
|
|
||||||
ACTION_BACKUP_COMPLETED_DIALOG -> {
|
|
||||||
backupDialog.dismiss()
|
|
||||||
val uri = Uri.parse(intent.getStringExtra(EXTRA_URI))
|
|
||||||
val file = UniFile.fromUri(context, uri)
|
|
||||||
MaterialDialog.Builder(this@SettingsBackupFragment.context)
|
|
||||||
.title(getString(R.string.backup_created))
|
|
||||||
.content(getString(R.string.file_saved, file.filePath))
|
|
||||||
.positiveText(getString(R.string.action_close))
|
|
||||||
.negativeText(getString(R.string.action_export))
|
|
||||||
.onPositive { materialDialog, _ -> materialDialog.dismiss() }
|
|
||||||
.onNegative { _, _ ->
|
|
||||||
val sendIntent = Intent(Intent.ACTION_SEND)
|
|
||||||
sendIntent.type = "application/json"
|
|
||||||
sendIntent.putExtra(Intent.EXTRA_STREAM, file.uri)
|
|
||||||
startActivity(Intent.createChooser(sendIntent, ""))
|
|
||||||
}
|
|
||||||
.safeShow()
|
|
||||||
|
|
||||||
}
|
|
||||||
ACTION_SET_PROGRESS_DIALOG -> {
|
|
||||||
val progress = intent.getIntExtra(EXTRA_PROGRESS, 0)
|
|
||||||
val amount = intent.getIntExtra(EXTRA_AMOUNT, 0)
|
|
||||||
val content = intent.getStringExtra(EXTRA_CONTENT)
|
|
||||||
restoreDialog.setContent(content)
|
|
||||||
restoreDialog.setProgress(progress)
|
|
||||||
restoreDialog.maxProgress = amount
|
|
||||||
}
|
|
||||||
ACTION_RESTORE_COMPLETED_DIALOG -> {
|
|
||||||
restoreDialog.dismiss()
|
|
||||||
val time = intent.getLongExtra(EXTRA_TIME, 0)
|
|
||||||
val errors = intent.getIntExtra(EXTRA_ERRORS, 0)
|
|
||||||
val path = intent.getStringExtra(EXTRA_ERROR_FILE_PATH)
|
|
||||||
val file = intent.getStringExtra(EXTRA_ERROR_FILE)
|
|
||||||
val timeString = String.format("%02d min, %02d sec",
|
|
||||||
TimeUnit.MILLISECONDS.toMinutes(time),
|
|
||||||
TimeUnit.MILLISECONDS.toSeconds(time) -
|
|
||||||
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(time))
|
|
||||||
)
|
|
||||||
|
|
||||||
if (errors > 0) {
|
|
||||||
MaterialDialog.Builder(this@SettingsBackupFragment.context)
|
|
||||||
.title(getString(R.string.restore_completed))
|
|
||||||
.content(getString(R.string.restore_completed_content, timeString,
|
|
||||||
if (errors > 0) "$errors" else getString(android.R.string.no)))
|
|
||||||
.positiveText(getString(R.string.action_close))
|
|
||||||
.negativeText(getString(R.string.action_open_log))
|
|
||||||
.onPositive { materialDialog, _ -> materialDialog.dismiss() }
|
|
||||||
.onNegative { materialDialog, _ ->
|
|
||||||
if (!path.isEmpty()) {
|
|
||||||
val destFile = File(path, file)
|
|
||||||
val uri = destFile.getUriCompat(context)
|
|
||||||
val sendIntent = Intent(Intent.ACTION_VIEW).apply {
|
|
||||||
setDataAndType(uri, "text/plain")
|
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION
|
|
||||||
}
|
|
||||||
startActivity(sendIntent)
|
|
||||||
} else {
|
|
||||||
context.toast(getString(R.string.error_opening_log))
|
|
||||||
}
|
|
||||||
materialDialog.dismiss()
|
|
||||||
}
|
|
||||||
.safeShow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ACTION_ERROR_BACKUP_DIALOG -> {
|
|
||||||
context.toast(intent.getStringExtra(EXTRA_ERROR_MESSAGE))
|
|
||||||
backupDialog.dismiss()
|
|
||||||
}
|
|
||||||
ACTION_ERROR_RESTORE_DIALOG -> {
|
|
||||||
context.toast(intent.getStringExtra(EXTRA_ERROR_MESSAGE))
|
|
||||||
restoreDialog.dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
context.registerLocalReceiver(receiver, IntentFilter(INTENT_FILTER))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
context.unregisterLocalReceiver(receiver)
|
|
||||||
super.onPause()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedState)
|
|
||||||
|
|
||||||
if (savedState != null) {
|
|
||||||
if (BackupRestoreService.isRunning(context)) {
|
|
||||||
restoreDialog.safeShow()
|
|
||||||
}
|
|
||||||
else if (BackupCreateService.isRunning(context)) {
|
|
||||||
backupDialog.safeShow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(activity as BaseActivity).requestPermissionsOnMarshmallow()
|
|
||||||
|
|
||||||
// Set onClickListeners
|
|
||||||
createBackup.setOnPreferenceClickListener {
|
|
||||||
MaterialDialog.Builder(context)
|
|
||||||
.title(R.string.pref_create_backup)
|
|
||||||
.content(R.string.backup_choice)
|
|
||||||
.items(R.array.backup_options)
|
|
||||||
.itemsCallbackMultiChoice(arrayOf(0, 1, 2, 3, 4 /*todo not hard code*/)) { _, positions, _ ->
|
|
||||||
// TODO not very happy with global value, but putExtra doesn't work
|
|
||||||
backup_flags = 0
|
|
||||||
for (i in 1..positions.size - 1) {
|
|
||||||
when (positions[i]) {
|
|
||||||
1 -> backup_flags = backup_flags or BackupCreateService.BACKUP_CATEGORY
|
|
||||||
2 -> backup_flags = backup_flags or BackupCreateService.BACKUP_CHAPTER
|
|
||||||
3 -> backup_flags = backup_flags or BackupCreateService.BACKUP_TRACK
|
|
||||||
4 -> backup_flags = backup_flags or BackupCreateService.BACKUP_HISTORY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If API lower as KitKat use custom dir picker
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
|
||||||
// Get dirs
|
|
||||||
val currentDir = preferences.backupsDirectory().getOrDefault()
|
|
||||||
|
|
||||||
val i = Intent(activity, CustomLayoutPickerActivity::class.java)
|
|
||||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
|
|
||||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
|
|
||||||
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR)
|
|
||||||
i.putExtra(FilePickerActivity.EXTRA_START_PATH, currentDir)
|
|
||||||
startActivityForResult(i, BACKUP_CREATE)
|
|
||||||
} else {
|
|
||||||
// Use Androids build in file creator
|
|
||||||
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
|
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
|
|
||||||
// TODO create custom MIME data type? Will make older backups deprecated
|
|
||||||
intent.type = "application/*"
|
|
||||||
intent.putExtra(Intent.EXTRA_TITLE, Backup.getDefaultFilename())
|
|
||||||
startActivityForResult(intent, BACKUP_CREATE)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
.itemsDisabledIndices(0)
|
|
||||||
.positiveText(getString(R.string.action_create))
|
|
||||||
.negativeText(android.R.string.cancel)
|
|
||||||
.safeShow()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
restoreBackup.setOnPreferenceClickListener {
|
|
||||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
|
||||||
intent.type = "application/*"
|
|
||||||
val chooser = Intent.createChooser(intent, getString(R.string.file_select_backup))
|
|
||||||
startActivityForResult(chooser, BACKUP_RESTORE)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
automaticBackup.setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
// Always cancel the previous task, it seems that sometimes they are not updated.
|
|
||||||
BackupCreatorJob.cancelTask()
|
|
||||||
|
|
||||||
val interval = (newValue as String).toInt()
|
|
||||||
if (interval > 0) {
|
|
||||||
BackupCreatorJob.setupTask(interval)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
backupSlots.setOnPreferenceChangeListener { preference, newValue ->
|
|
||||||
preferences.numberOfBackups().set((newValue as String).toInt())
|
|
||||||
preference.summary = newValue
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
backupDirPref.setOnPreferenceClickListener {
|
|
||||||
val currentDir = preferences.backupsDirectory().getOrDefault()
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < 21) {
|
|
||||||
// Custom dir selected, open directory selector
|
|
||||||
val i = Intent(activity, CustomLayoutPickerActivity::class.java)
|
|
||||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
|
|
||||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
|
|
||||||
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR)
|
|
||||||
i.putExtra(FilePickerActivity.EXTRA_START_PATH, currentDir)
|
|
||||||
|
|
||||||
startActivityForResult(i, BACKUP_DIR)
|
|
||||||
} else {
|
|
||||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
|
||||||
startActivityForResult(i, BACKUP_DIR)
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
subscriptions += preferences.backupsDirectory().asObservable()
|
|
||||||
.subscribe { path ->
|
|
||||||
backupDir = UniFile.fromUri(context, Uri.parse(path))
|
|
||||||
backupDirPref.summary = backupDir.filePath ?: path
|
|
||||||
}
|
|
||||||
|
|
||||||
subscriptions += preferences.backupInterval().asObservable()
|
|
||||||
.subscribe {
|
|
||||||
backupDirPref.isVisible = it > 0
|
|
||||||
backupSlots.isVisible = it > 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
when (requestCode) {
|
|
||||||
BACKUP_DIR -> if (data != null && resultCode == Activity.RESULT_OK) {
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
val uri = Uri.fromFile(File(data.data.path))
|
|
||||||
preferences.backupsDirectory().set(uri.toString())
|
|
||||||
} else {
|
|
||||||
val uri = data.data
|
|
||||||
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
|
||||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
|
||||||
|
|
||||||
context.contentResolver.takePersistableUriPermission(uri, flags)
|
|
||||||
|
|
||||||
val file = UniFile.fromUri(context, uri)
|
|
||||||
preferences.backupsDirectory().set(file.uri.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BACKUP_CREATE -> if (data != null && resultCode == Activity.RESULT_OK) {
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
|
||||||
val dir = data.data.path
|
|
||||||
val file = File(dir, Backup.getDefaultFilename())
|
|
||||||
|
|
||||||
backupDialog.safeShow()
|
|
||||||
BackupCreateService.makeBackup(context, file.toURI().toString(), backup_flags)
|
|
||||||
} else {
|
|
||||||
val uri = data.data
|
|
||||||
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
|
||||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
|
||||||
|
|
||||||
context.contentResolver.takePersistableUriPermission(uri, flags)
|
|
||||||
val file = UniFile.fromUri(context, uri)
|
|
||||||
|
|
||||||
backupDialog.safeShow()
|
|
||||||
BackupCreateService.makeBackup(context, file.uri.toString(), backup_flags)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BACKUP_RESTORE -> if (data != null && resultCode == Activity.RESULT_OK) {
|
|
||||||
val uri = data.data
|
|
||||||
|
|
||||||
MaterialDialog.Builder(context)
|
|
||||||
.title(getString(R.string.pref_restore_backup))
|
|
||||||
.content(getString(R.string.backup_restore_content))
|
|
||||||
.positiveText(getString(R.string.action_restore))
|
|
||||||
.onPositive { _, _ ->
|
|
||||||
restoreDialog.safeShow()
|
|
||||||
BackupRestoreService.start(context, uri)
|
|
||||||
}
|
|
||||||
.safeShow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun MaterialDialog.Builder.safeShow(): Dialog {
|
|
||||||
return build().safeShow()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Dialog.safeShow(): Dialog {
|
|
||||||
subscriptions += Subscriptions.create { dismiss() }
|
|
||||||
show()
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,70 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v7.app.AppCompatActivity
|
||||||
|
import android.support.v7.preference.PreferenceController
|
||||||
|
import android.support.v7.preference.PreferenceScreen
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.ContextThemeWrapper
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import rx.Observable
|
||||||
|
import rx.Subscription
|
||||||
|
import rx.subscriptions.CompositeSubscription
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
abstract class SettingsController : PreferenceController() {
|
||||||
|
|
||||||
|
val preferences: PreferencesHelper = Injekt.get()
|
||||||
|
|
||||||
|
var untilDestroySubscriptions = CompositeSubscription()
|
||||||
|
private set
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View {
|
||||||
|
if (untilDestroySubscriptions.isUnsubscribed) {
|
||||||
|
untilDestroySubscriptions = CompositeSubscription()
|
||||||
|
}
|
||||||
|
return super.onCreateView(inflater, container, savedInstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView(view: View) {
|
||||||
|
super.onDestroyView(view)
|
||||||
|
untilDestroySubscriptions.unsubscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
val screen = preferenceManager.createPreferenceScreen(getThemedContext())
|
||||||
|
preferenceScreen = screen
|
||||||
|
setupPreferenceScreen(screen)
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun setupPreferenceScreen(screen: PreferenceScreen): Any?
|
||||||
|
|
||||||
|
private fun getThemedContext(): Context {
|
||||||
|
val tv = TypedValue()
|
||||||
|
activity!!.theme.resolveAttribute(R.attr.preferenceTheme, tv, true)
|
||||||
|
return ContextThemeWrapper(activity, tv.resourceId)
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun getTitle(): String? {
|
||||||
|
return preferenceScreen?.title?.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAttach(view: View) {
|
||||||
|
(activity as? AppCompatActivity)?.supportActionBar?.title = getTitle()
|
||||||
|
super.onAttach(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Observable<T>.subscribeUntilDestroy(): Subscription {
|
||||||
|
return subscribe().also { untilDestroySubscriptions.add(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> Observable<T>.subscribeUntilDestroy(onNext: (T) -> Unit): Subscription {
|
||||||
|
return subscribe(onNext).also { untilDestroySubscriptions.add(it) }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,186 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Environment
|
||||||
|
import android.support.v4.content.ContextCompat
|
||||||
|
import android.support.v7.preference.PreferenceScreen
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import com.hippo.unifile.UniFile
|
||||||
|
import com.nononsenseapps.filepicker.FilePickerActivity
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
|
import eu.kanade.tachiyomi.util.DiskUtil
|
||||||
|
import eu.kanade.tachiyomi.widget.CustomLayoutPickerActivity
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.io.File
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||||
|
|
||||||
|
class SettingsDownloadController : SettingsController() {
|
||||||
|
|
||||||
|
private val db: DatabaseHelper by injectLazy()
|
||||||
|
|
||||||
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||||
|
titleRes = R.string.pref_category_downloads
|
||||||
|
|
||||||
|
preference {
|
||||||
|
key = Keys.downloadsDirectory
|
||||||
|
titleRes = R.string.pref_download_directory
|
||||||
|
onClick {
|
||||||
|
showDownloadDirectoriesDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences.downloadsDirectory().asObservable()
|
||||||
|
.subscribeUntilDestroy { path ->
|
||||||
|
val dir = UniFile.fromUri(context, Uri.parse(path))
|
||||||
|
summary = dir.filePath ?: path
|
||||||
|
|
||||||
|
// Don't display downloaded chapters in gallery apps creating .nomedia
|
||||||
|
if (dir != null && dir.exists()) {
|
||||||
|
val nomedia = dir.findFile(".nomedia")
|
||||||
|
if (nomedia == null) {
|
||||||
|
dir.createFile(".nomedia")
|
||||||
|
applicationContext?.let { DiskUtil.scanMedia(it, dir.uri) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.downloadOnlyOverWifi
|
||||||
|
titleRes = R.string.pref_download_only_over_wifi
|
||||||
|
defaultValue = true
|
||||||
|
}
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.downloadThreads
|
||||||
|
titleRes = R.string.pref_download_slots
|
||||||
|
entries = arrayOf("1", "2", "3")
|
||||||
|
entryValues = arrayOf("1", "2", "3")
|
||||||
|
defaultValue = "1"
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
preferenceCategory {
|
||||||
|
titleRes = R.string.pref_remove_after_read
|
||||||
|
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.removeAfterMarkedAsRead
|
||||||
|
titleRes = R.string.pref_remove_after_marked_as_read
|
||||||
|
defaultValue = false
|
||||||
|
}
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.removeAfterReadSlots
|
||||||
|
titleRes = R.string.pref_remove_after_read
|
||||||
|
entriesRes = arrayOf(R.string.disabled, R.string.last_read_chapter,
|
||||||
|
R.string.second_to_last, R.string.third_to_last, R.string.fourth_to_last,
|
||||||
|
R.string.fifth_to_last)
|
||||||
|
entryValues = arrayOf("-1", "0", "1", "2", "3", "4")
|
||||||
|
defaultValue = "-1"
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val dbCategories = db.getCategories().executeAsBlocking()
|
||||||
|
|
||||||
|
preferenceCategory {
|
||||||
|
titleRes = R.string.pref_download_new
|
||||||
|
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.downloadNew
|
||||||
|
titleRes = R.string.pref_download_new
|
||||||
|
defaultValue = false
|
||||||
|
}
|
||||||
|
multiSelectListPreference {
|
||||||
|
key = Keys.downloadNewCategories
|
||||||
|
titleRes = R.string.pref_download_new_categories
|
||||||
|
entries = dbCategories.map { it.name }.toTypedArray()
|
||||||
|
entryValues = dbCategories.map { it.id.toString() }.toTypedArray()
|
||||||
|
|
||||||
|
preferences.downloadNew().asObservable()
|
||||||
|
.subscribeUntilDestroy { isVisible = it }
|
||||||
|
|
||||||
|
preferences.downloadNewCategories().asObservable()
|
||||||
|
.subscribe {
|
||||||
|
val selectedCategories = it
|
||||||
|
.mapNotNull { id -> dbCategories.find { it.id == id.toInt() } }
|
||||||
|
.sortedBy { it.order }
|
||||||
|
|
||||||
|
summary = if (selectedCategories.isEmpty())
|
||||||
|
resources?.getString(R.string.all)
|
||||||
|
else
|
||||||
|
selectedCategories.joinToString { it.name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showDownloadDirectoriesDialog() {
|
||||||
|
val activity = activity ?: return
|
||||||
|
|
||||||
|
val currentDir = preferences.downloadsDirectory().getOrDefault()
|
||||||
|
val externalDirs = getExternalFilesDirs() + File(activity.getString(R.string.custom_dir))
|
||||||
|
val selectedIndex = externalDirs.map(File::toString).indexOfFirst { it in currentDir }
|
||||||
|
|
||||||
|
MaterialDialog.Builder(activity)
|
||||||
|
.items(externalDirs)
|
||||||
|
.itemsCallbackSingleChoice(selectedIndex, { _, _, which, text ->
|
||||||
|
if (which == externalDirs.lastIndex) {
|
||||||
|
if (Build.VERSION.SDK_INT < 21) {
|
||||||
|
// Custom dir selected, open directory selector
|
||||||
|
val i = Intent(activity, CustomLayoutPickerActivity::class.java)
|
||||||
|
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
|
||||||
|
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
|
||||||
|
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR)
|
||||||
|
i.putExtra(FilePickerActivity.EXTRA_START_PATH, currentDir)
|
||||||
|
|
||||||
|
startActivityForResult(i, DOWNLOAD_DIR_PRE_L)
|
||||||
|
} else {
|
||||||
|
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||||
|
startActivityForResult(i, DOWNLOAD_DIR_L)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// One of the predefined folders was selected
|
||||||
|
val path = Uri.fromFile(File(text.toString()))
|
||||||
|
preferences.downloadsDirectory().set(path.toString())
|
||||||
|
}
|
||||||
|
true
|
||||||
|
})
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getExternalFilesDirs(): List<File> {
|
||||||
|
val defaultDir = Environment.getExternalStorageDirectory().absolutePath +
|
||||||
|
File.separator + resources?.getString(R.string.app_name) +
|
||||||
|
File.separator + "downloads"
|
||||||
|
|
||||||
|
return mutableListOf(File(defaultDir)) +
|
||||||
|
ContextCompat.getExternalFilesDirs(activity, "").filterNotNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
when (requestCode) {
|
||||||
|
DOWNLOAD_DIR_PRE_L -> if (data != null && resultCode == Activity.RESULT_OK) {
|
||||||
|
val uri = Uri.fromFile(File(data.data.path))
|
||||||
|
preferences.downloadsDirectory().set(uri.toString())
|
||||||
|
}
|
||||||
|
DOWNLOAD_DIR_L -> if (data != null && resultCode == Activity.RESULT_OK) {
|
||||||
|
val context = applicationContext ?: return
|
||||||
|
val uri = data.data
|
||||||
|
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||||
|
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||||
|
|
||||||
|
@Suppress("NewApi")
|
||||||
|
context.contentResolver.takePersistableUriPermission(uri, flags)
|
||||||
|
|
||||||
|
val file = UniFile.fromUri(context, uri)
|
||||||
|
preferences.downloadsDirectory().set(file.uri.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val DOWNLOAD_DIR_PRE_L = 103
|
||||||
|
const val DOWNLOAD_DIR_L = 104
|
||||||
|
}
|
||||||
|
}
|
@ -1,149 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.setting
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Environment
|
|
||||||
import android.support.v4.content.ContextCompat
|
|
||||||
import android.support.v7.preference.Preference
|
|
||||||
import android.support.v7.preference.XpPreferenceFragment
|
|
||||||
import android.view.View
|
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
|
||||||
import com.hippo.unifile.UniFile
|
|
||||||
import com.nononsenseapps.filepicker.FilePickerActivity
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
|
||||||
import eu.kanade.tachiyomi.util.plusAssign
|
|
||||||
import eu.kanade.tachiyomi.widget.CustomLayoutPickerActivity
|
|
||||||
import net.xpece.android.support.preference.MultiSelectListPreference
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class SettingsDownloadsFragment : SettingsFragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val DOWNLOAD_DIR_PRE_L = 103
|
|
||||||
const val DOWNLOAD_DIR_L = 104
|
|
||||||
|
|
||||||
fun newInstance(rootKey: String): SettingsDownloadsFragment {
|
|
||||||
val args = Bundle()
|
|
||||||
args.putString(XpPreferenceFragment.ARG_PREFERENCE_ROOT, rootKey)
|
|
||||||
return SettingsDownloadsFragment().apply { arguments = args }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val preferences: PreferencesHelper by injectLazy()
|
|
||||||
|
|
||||||
private val db: DatabaseHelper by injectLazy()
|
|
||||||
|
|
||||||
val downloadDirPref: Preference by bindPref(R.string.pref_download_directory_key)
|
|
||||||
|
|
||||||
val downloadCategory: MultiSelectListPreference by bindPref(R.string.pref_download_new_categories_key)
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedState)
|
|
||||||
|
|
||||||
downloadDirPref.setOnPreferenceClickListener {
|
|
||||||
|
|
||||||
val currentDir = preferences.downloadsDirectory().getOrDefault()
|
|
||||||
val externalDirs = getExternalFilesDirs() + File(getString(R.string.custom_dir))
|
|
||||||
val selectedIndex = externalDirs.map(File::toString).indexOfFirst { it in currentDir }
|
|
||||||
|
|
||||||
MaterialDialog.Builder(activity)
|
|
||||||
.items(externalDirs)
|
|
||||||
.itemsCallbackSingleChoice(selectedIndex, { dialog, view, which, text ->
|
|
||||||
if (which == externalDirs.lastIndex) {
|
|
||||||
if (Build.VERSION.SDK_INT < 21) {
|
|
||||||
// Custom dir selected, open directory selector
|
|
||||||
val i = Intent(activity, CustomLayoutPickerActivity::class.java)
|
|
||||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
|
|
||||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
|
|
||||||
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR)
|
|
||||||
i.putExtra(FilePickerActivity.EXTRA_START_PATH, currentDir)
|
|
||||||
|
|
||||||
startActivityForResult(i, DOWNLOAD_DIR_PRE_L)
|
|
||||||
} else {
|
|
||||||
val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
|
||||||
startActivityForResult(i, DOWNLOAD_DIR_L)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// One of the predefined folders was selected
|
|
||||||
val path = Uri.fromFile(File(text.toString()))
|
|
||||||
preferences.downloadsDirectory().set(path.toString())
|
|
||||||
}
|
|
||||||
true
|
|
||||||
})
|
|
||||||
.show()
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
subscriptions += preferences.downloadsDirectory().asObservable()
|
|
||||||
.subscribe { path ->
|
|
||||||
val dir = UniFile.fromUri(context, Uri.parse(path))
|
|
||||||
|
|
||||||
downloadDirPref.summary = dir.filePath ?: path
|
|
||||||
|
|
||||||
// Don't display downloaded chapters in gallery apps creating a ".nomedia" file.
|
|
||||||
if (dir != null && dir.exists()) {
|
|
||||||
dir.createFile(".nomedia")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
subscriptions += preferences.downloadNew().asObservable()
|
|
||||||
.subscribe { downloadCategory.isVisible = it }
|
|
||||||
|
|
||||||
val dbCategories = db.getCategories().executeAsBlocking()
|
|
||||||
downloadCategory.apply {
|
|
||||||
entries = dbCategories.map { it.name }.toTypedArray()
|
|
||||||
entryValues = dbCategories.map { it.id.toString() }.toTypedArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
subscriptions += preferences.downloadNewCategories().asObservable()
|
|
||||||
.subscribe {
|
|
||||||
val selectedCategories = it
|
|
||||||
.mapNotNull { id -> dbCategories.find { it.id == id.toInt() } }
|
|
||||||
.sortedBy { it.order }
|
|
||||||
|
|
||||||
val summary = if (selectedCategories.isEmpty())
|
|
||||||
getString(R.string.all)
|
|
||||||
else
|
|
||||||
selectedCategories.joinToString { it.name }
|
|
||||||
|
|
||||||
downloadCategory.summary = summary
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getExternalFilesDirs(): List<File> {
|
|
||||||
val defaultDir = Environment.getExternalStorageDirectory().absolutePath +
|
|
||||||
File.separator + getString(R.string.app_name) +
|
|
||||||
File.separator + "downloads"
|
|
||||||
|
|
||||||
return mutableListOf(File(defaultDir)) +
|
|
||||||
ContextCompat.getExternalFilesDirs(activity, "").filterNotNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
when (requestCode) {
|
|
||||||
DOWNLOAD_DIR_PRE_L -> if (data != null && resultCode == Activity.RESULT_OK) {
|
|
||||||
val uri = Uri.fromFile(File(data.data.path))
|
|
||||||
preferences.downloadsDirectory().set(uri.toString())
|
|
||||||
}
|
|
||||||
DOWNLOAD_DIR_L -> if (data != null && resultCode == Activity.RESULT_OK) {
|
|
||||||
val uri = data.data
|
|
||||||
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
|
||||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
|
||||||
|
|
||||||
@Suppress("NewApi")
|
|
||||||
context.contentResolver.takePersistableUriPermission(uri, flags)
|
|
||||||
|
|
||||||
val file = UniFile.fromUri(context, uri)
|
|
||||||
preferences.downloadsDirectory().set(file.uri.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.setting
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.support.annotation.CallSuper
|
|
||||||
import android.support.v7.preference.Preference
|
|
||||||
import android.support.v7.preference.XpPreferenceFragment
|
|
||||||
import android.view.View
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import net.xpece.android.support.preference.PreferenceScreenNavigationStrategy
|
|
||||||
import rx.subscriptions.CompositeSubscription
|
|
||||||
|
|
||||||
open class SettingsFragment : XpPreferenceFragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance(rootKey: String?): SettingsFragment {
|
|
||||||
val args = Bundle()
|
|
||||||
args.putString(XpPreferenceFragment.ARG_PREFERENCE_ROOT, rootKey)
|
|
||||||
return SettingsFragment().apply { arguments = args }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lateinit var subscriptions: CompositeSubscription
|
|
||||||
|
|
||||||
override final fun onCreatePreferences2(savedState: Bundle?, rootKey: String?) {
|
|
||||||
subscriptions = CompositeSubscription()
|
|
||||||
|
|
||||||
addPreferencesFromResource(R.xml.pref_general)
|
|
||||||
addPreferencesFromResource(R.xml.pref_reader)
|
|
||||||
addPreferencesFromResource(R.xml.pref_downloads)
|
|
||||||
addPreferencesFromResource(R.xml.pref_sources)
|
|
||||||
addPreferencesFromResource(R.xml.pref_tracking)
|
|
||||||
addPreferencesFromResource(R.xml.pref_backup)
|
|
||||||
addPreferencesFromResource(R.xml.pref_advanced)
|
|
||||||
addPreferencesFromResource(R.xml.pref_about)
|
|
||||||
|
|
||||||
// Setup root preference title.
|
|
||||||
preferenceScreen.title = activity.title
|
|
||||||
|
|
||||||
PreferenceScreenNavigationStrategy.ReplaceFragment.onCreatePreferences(this, rootKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
@CallSuper
|
|
||||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedState)
|
|
||||||
listView.isFocusable = false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
activity.title = preferenceScreen.title
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
subscriptions.unsubscribe()
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected inline fun <reified T : Preference> bindPref(resId: Int): Lazy<T> {
|
|
||||||
return lazy { findPreference(getString(resId)) as T }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,225 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.support.v7.preference.PreferenceScreen
|
||||||
|
import android.view.View
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
|
import eu.kanade.tachiyomi.util.LocaleHelper
|
||||||
|
import kotlinx.android.synthetic.main.pref_library_columns.view.*
|
||||||
|
import rx.Observable
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||||
|
|
||||||
|
class SettingsGeneralController : SettingsController() {
|
||||||
|
|
||||||
|
private val db: DatabaseHelper = Injekt.get()
|
||||||
|
|
||||||
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||||
|
titleRes = R.string.pref_category_general
|
||||||
|
|
||||||
|
listPreference {
|
||||||
|
key = Keys.lang
|
||||||
|
titleRes = R.string.pref_language
|
||||||
|
entryValues = arrayOf("", "bg", "en", "es", "fr", "it", "pt", "ru", "vi")
|
||||||
|
entries = entryValues.map { value ->
|
||||||
|
val locale = LocaleHelper.getLocaleFromString(value.toString())
|
||||||
|
locale?.getDisplayName(locale)?.capitalize() ?:
|
||||||
|
context.getString(R.string.system_default)
|
||||||
|
}.toTypedArray()
|
||||||
|
defaultValue = ""
|
||||||
|
summary = "%s"
|
||||||
|
|
||||||
|
onChange { newValue ->
|
||||||
|
val activity = activity ?: return@onChange false
|
||||||
|
val app = activity.application
|
||||||
|
LocaleHelper.changeLocale(newValue.toString())
|
||||||
|
LocaleHelper.updateConfiguration(app, app.resources.configuration)
|
||||||
|
activity.recreate()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.theme
|
||||||
|
titleRes = R.string.pref_theme
|
||||||
|
entriesRes = arrayOf(R.string.light_theme, R.string.dark_theme)
|
||||||
|
entryValues = arrayOf("1", "2")
|
||||||
|
defaultValue = "1"
|
||||||
|
summary = "%s"
|
||||||
|
|
||||||
|
onChange {
|
||||||
|
activity?.recreate()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
titleRes = R.string.pref_library_columns
|
||||||
|
onClick {
|
||||||
|
LibraryColumnsDialog().showDialog(router)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getColumnValue(value: Int): String {
|
||||||
|
return if (value == 0)
|
||||||
|
context.getString(R.string.default_columns)
|
||||||
|
else
|
||||||
|
value.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
Observable.combineLatest(
|
||||||
|
preferences.portraitColumns().asObservable(),
|
||||||
|
preferences.landscapeColumns().asObservable(),
|
||||||
|
{ portraitCols, landscapeCols -> Pair(portraitCols, landscapeCols) })
|
||||||
|
.subscribeUntilDestroy { (portraitCols, landscapeCols) ->
|
||||||
|
val portrait = getColumnValue(portraitCols)
|
||||||
|
val landscape = getColumnValue(landscapeCols)
|
||||||
|
summary = "${context.getString(R.string.portrait)}: $portrait, " +
|
||||||
|
"${context.getString(R.string.landscape)}: $landscape"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.startScreen
|
||||||
|
titleRes = R.string.pref_start_screen
|
||||||
|
entriesRes = arrayOf(R.string.label_library, R.string.label_recent_manga,
|
||||||
|
R.string.label_recent_updates)
|
||||||
|
entryValues = arrayOf("1", "2", "3")
|
||||||
|
defaultValue = "1"
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.libraryUpdateInterval
|
||||||
|
titleRes = R.string.pref_library_update_interval
|
||||||
|
entriesRes = arrayOf(R.string.update_never, R.string.update_1hour,
|
||||||
|
R.string.update_2hour, R.string.update_3hour, R.string.update_6hour,
|
||||||
|
R.string.update_12hour, R.string.update_24hour, R.string.update_48hour)
|
||||||
|
entryValues = arrayOf("0", "1", "2", "3", "6", "12", "24", "48")
|
||||||
|
defaultValue = "0"
|
||||||
|
summary = "%s"
|
||||||
|
|
||||||
|
onChange { newValue ->
|
||||||
|
// Always cancel the previous task, it seems that sometimes they are not updated.
|
||||||
|
LibraryUpdateJob.cancelTask()
|
||||||
|
|
||||||
|
val interval = (newValue as String).toInt()
|
||||||
|
if (interval > 0) {
|
||||||
|
LibraryUpdateJob.setupTask(interval)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
multiSelectListPreference {
|
||||||
|
key = Keys.libraryUpdateRestriction
|
||||||
|
titleRes = R.string.pref_library_update_restriction
|
||||||
|
entriesRes = arrayOf(R.string.wifi, R.string.charging)
|
||||||
|
entryValues = arrayOf("wifi", "ac")
|
||||||
|
summaryRes = R.string.pref_library_update_restriction_summary
|
||||||
|
|
||||||
|
preferences.libraryUpdateInterval().asObservable()
|
||||||
|
.subscribeUntilDestroy { isVisible = it > 0 }
|
||||||
|
|
||||||
|
onChange {
|
||||||
|
// Post to event looper to allow the preference to be updated.
|
||||||
|
Handler().post { LibraryUpdateJob.setupTask() }
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.updateOnlyNonCompleted
|
||||||
|
titleRes = R.string.pref_update_only_non_completed
|
||||||
|
defaultValue = false
|
||||||
|
}
|
||||||
|
|
||||||
|
val dbCategories = db.getCategories().executeAsBlocking()
|
||||||
|
|
||||||
|
multiSelectListPreference {
|
||||||
|
key = Keys.libraryUpdateCategories
|
||||||
|
titleRes = R.string.pref_library_update_categories
|
||||||
|
entries = dbCategories.map { it.name }.toTypedArray()
|
||||||
|
entryValues = dbCategories.map { it.id.toString() }.toTypedArray()
|
||||||
|
|
||||||
|
preferences.libraryUpdateCategories().asObservable()
|
||||||
|
.subscribeUntilDestroy {
|
||||||
|
val selectedCategories = it
|
||||||
|
.mapNotNull { id -> dbCategories.find { it.id == id.toInt() } }
|
||||||
|
.sortedBy { it.order }
|
||||||
|
|
||||||
|
summary = if (selectedCategories.isEmpty())
|
||||||
|
context.getString(R.string.all)
|
||||||
|
else
|
||||||
|
selectedCategories.joinToString { it.name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.defaultCategory
|
||||||
|
titleRes = R.string.default_category
|
||||||
|
|
||||||
|
val selectedCategory = dbCategories.find { it.id == preferences.defaultCategory() }
|
||||||
|
entries = arrayOf(context.getString(R.string.default_category_summary)) +
|
||||||
|
dbCategories.map { it.name }.toTypedArray()
|
||||||
|
entryValues = arrayOf("-1") + dbCategories.map { it.id.toString() }.toTypedArray()
|
||||||
|
defaultValue = "-1"
|
||||||
|
summary = selectedCategory?.name ?: context.getString(R.string.default_category_summary)
|
||||||
|
|
||||||
|
onChange { newValue ->
|
||||||
|
summary = dbCategories.find {
|
||||||
|
it.id == (newValue as String).toInt()
|
||||||
|
}?.name ?: context.getString(R.string.default_category_summary)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LibraryColumnsDialog : DialogController() {
|
||||||
|
|
||||||
|
private val preferences: PreferencesHelper = Injekt.get()
|
||||||
|
|
||||||
|
private var portrait = preferences.portraitColumns().getOrDefault()
|
||||||
|
private var landscape = preferences.landscapeColumns().getOrDefault()
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
val dialog = MaterialDialog.Builder(activity!!)
|
||||||
|
.title(R.string.pref_library_columns)
|
||||||
|
.customView(R.layout.pref_library_columns, false)
|
||||||
|
.positiveText(android.R.string.ok)
|
||||||
|
.negativeText(android.R.string.cancel)
|
||||||
|
.onPositive { _, _ ->
|
||||||
|
preferences.portraitColumns().set(portrait)
|
||||||
|
preferences.landscapeColumns().set(landscape)
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
|
||||||
|
onViewCreated(dialog.view)
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onViewCreated(view: View) {
|
||||||
|
with(view.portrait_columns) {
|
||||||
|
displayedValues = arrayOf(context.getString(R.string.default_columns)) +
|
||||||
|
IntRange(1, 10).map(Int::toString)
|
||||||
|
value = portrait
|
||||||
|
|
||||||
|
setOnValueChangedListener { _, _, newValue ->
|
||||||
|
portrait = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
with(view.landscape_columns) {
|
||||||
|
displayedValues = arrayOf(context.getString(R.string.default_columns)) +
|
||||||
|
IntRange(1, 10).map(Int::toString)
|
||||||
|
value = landscape
|
||||||
|
|
||||||
|
setOnValueChangedListener { _, _, newValue ->
|
||||||
|
landscape = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,166 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.setting
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.support.v7.preference.Preference
|
|
||||||
import android.support.v7.preference.PreferenceFragmentCompat
|
|
||||||
import android.support.v7.preference.XpPreferenceFragment
|
|
||||||
import android.view.View
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
|
||||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.util.LocaleHelper
|
|
||||||
import eu.kanade.tachiyomi.util.plusAssign
|
|
||||||
import eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
import eu.kanade.tachiyomi.widget.preference.LibraryColumnsDialog
|
|
||||||
import eu.kanade.tachiyomi.widget.preference.SimpleDialogPreference
|
|
||||||
import net.xpece.android.support.preference.ListPreference
|
|
||||||
import net.xpece.android.support.preference.MultiSelectListPreference
|
|
||||||
import rx.Observable
|
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
class SettingsGeneralFragment : SettingsFragment(),
|
|
||||||
PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {
|
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun newInstance(rootKey: String): SettingsGeneralFragment {
|
|
||||||
val args = Bundle()
|
|
||||||
args.putString(XpPreferenceFragment.ARG_PREFERENCE_ROOT, rootKey)
|
|
||||||
return SettingsGeneralFragment().apply { arguments = args }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val preferences: PreferencesHelper by injectLazy()
|
|
||||||
|
|
||||||
private val db: DatabaseHelper by injectLazy()
|
|
||||||
|
|
||||||
val columnsPreference: SimpleDialogPreference by bindPref(R.string.pref_library_columns_dialog_key)
|
|
||||||
|
|
||||||
val updateInterval: IntListPreference by bindPref(R.string.pref_library_update_interval_key)
|
|
||||||
|
|
||||||
val updateRestriction: MultiSelectListPreference by bindPref(R.string.pref_library_update_restriction_key)
|
|
||||||
|
|
||||||
val themePreference: IntListPreference by bindPref(R.string.pref_theme_key)
|
|
||||||
|
|
||||||
val categoryUpdate: MultiSelectListPreference by bindPref(R.string.pref_library_update_categories_key)
|
|
||||||
|
|
||||||
val defaultCategory: IntListPreference by bindPref(R.string.default_category_key)
|
|
||||||
|
|
||||||
val langPreference: ListPreference by bindPref(R.string.pref_language_key)
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedState)
|
|
||||||
|
|
||||||
subscriptions += preferences.libraryUpdateInterval().asObservable()
|
|
||||||
.subscribe { updateRestriction.isVisible = it > 0 }
|
|
||||||
|
|
||||||
subscriptions += Observable.combineLatest(
|
|
||||||
preferences.portraitColumns().asObservable(),
|
|
||||||
preferences.landscapeColumns().asObservable())
|
|
||||||
{ portraitColumns, landscapeColumns -> Pair(portraitColumns, landscapeColumns) }
|
|
||||||
.subscribe { updateColumnsSummary(it.first, it.second) }
|
|
||||||
|
|
||||||
updateInterval.setOnPreferenceChangeListener { preference, newValue ->
|
|
||||||
// Always cancel the previous task, it seems that sometimes they are not updated.
|
|
||||||
LibraryUpdateJob.cancelTask()
|
|
||||||
|
|
||||||
val interval = (newValue as String).toInt()
|
|
||||||
if (interval > 0) {
|
|
||||||
LibraryUpdateJob.setupTask(interval)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
updateRestriction.setOnPreferenceChangeListener { preference, newValue ->
|
|
||||||
// Post to event looper to allow the preference to be updated.
|
|
||||||
subscriptions += Observable.fromCallable {
|
|
||||||
LibraryUpdateJob.setupTask()
|
|
||||||
}.subscribeOn(AndroidSchedulers.mainThread()).subscribe()
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
val dbCategories = db.getCategories().executeAsBlocking()
|
|
||||||
categoryUpdate.apply {
|
|
||||||
entries = dbCategories.map { it.name }.toTypedArray()
|
|
||||||
entryValues = dbCategories.map { it.id.toString() }.toTypedArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
subscriptions += preferences.libraryUpdateCategories().asObservable()
|
|
||||||
.subscribe {
|
|
||||||
val selectedCategories = it
|
|
||||||
.mapNotNull { id -> dbCategories.find { it.id == id.toInt() } }
|
|
||||||
.sortedBy { it.order }
|
|
||||||
|
|
||||||
val summary = if (selectedCategories.isEmpty())
|
|
||||||
getString(R.string.all)
|
|
||||||
else
|
|
||||||
selectedCategories.joinToString { it.name }
|
|
||||||
|
|
||||||
categoryUpdate.summary = summary
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultCategory.apply {
|
|
||||||
val selectedCategory = dbCategories.find { it.id == preferences.defaultCategory()}
|
|
||||||
value = selectedCategory?.id?.toString() ?: value
|
|
||||||
entries += dbCategories.map { it.name }.toTypedArray()
|
|
||||||
entryValues += dbCategories.map { it.id.toString() }.toTypedArray()
|
|
||||||
summary = selectedCategory?.name ?: summary
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultCategory.setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
defaultCategory.summary = dbCategories.find {
|
|
||||||
it.id == (newValue as String).toInt()
|
|
||||||
}?.name ?: getString(R.string.default_category_summary)
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
themePreference.setOnPreferenceChangeListener { preference, newValue ->
|
|
||||||
(activity as SettingsActivity).parentFlags = SettingsActivity.FLAG_THEME_CHANGED
|
|
||||||
activity.recreate()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
val langValues = langPreference.entryValues.map { value ->
|
|
||||||
val locale = LocaleHelper.getLocaleFromString(value.toString())
|
|
||||||
locale?.getDisplayName(locale)?.capitalize() ?: context.getString(R.string.system_default)
|
|
||||||
}
|
|
||||||
|
|
||||||
langPreference.entries = langValues.toTypedArray()
|
|
||||||
langPreference.setOnPreferenceChangeListener { preference, newValue ->
|
|
||||||
(activity as SettingsActivity).parentFlags = SettingsActivity.FLAG_LANG_CHANGED
|
|
||||||
LocaleHelper.changeLocale(newValue.toString())
|
|
||||||
val app = activity.application
|
|
||||||
LocaleHelper.updateConfiguration(app, app.resources.configuration)
|
|
||||||
activity.recreate()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPreferenceDisplayDialog(p0: PreferenceFragmentCompat?, p: Preference): Boolean {
|
|
||||||
if (p === columnsPreference) {
|
|
||||||
val fragment = LibraryColumnsDialog.newInstance(p)
|
|
||||||
fragment.setTargetFragment(this, 0)
|
|
||||||
fragment.show(fragmentManager, null)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateColumnsSummary(portraitColumns: Int, landscapeColumns: Int) {
|
|
||||||
val portrait = getColumnValue(portraitColumns)
|
|
||||||
val landscape = getColumnValue(landscapeColumns)
|
|
||||||
val msg = "${getString(R.string.portrait)}: $portrait, ${getString(R.string.landscape)}: $landscape"
|
|
||||||
|
|
||||||
columnsPreference.summary = msg
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getColumnValue(value: Int): String {
|
|
||||||
return if (value == 0) getString(R.string.default_columns) else value.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,70 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
|
import android.support.v7.preference.PreferenceScreen
|
||||||
|
import com.bluelinelabs.conductor.RouterTransaction
|
||||||
|
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.util.getResourceColor
|
||||||
|
|
||||||
|
class SettingsMainController : SettingsController() {
|
||||||
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||||
|
titleRes = R.string.label_settings
|
||||||
|
|
||||||
|
val tintColor = context.getResourceColor(R.attr.colorAccent)
|
||||||
|
|
||||||
|
preference {
|
||||||
|
iconRes = R.drawable.ic_tune_black_24dp
|
||||||
|
iconTint = tintColor
|
||||||
|
titleRes = R.string.pref_category_general
|
||||||
|
onClick { navigateTo(SettingsGeneralController()) }
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
iconRes = R.drawable.ic_chrome_reader_mode_black_24dp
|
||||||
|
iconTint = tintColor
|
||||||
|
titleRes = R.string.pref_category_reader
|
||||||
|
onClick { navigateTo(SettingsReaderController()) }
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
iconRes = R.drawable.ic_file_download_black_24dp
|
||||||
|
iconTint = tintColor
|
||||||
|
titleRes = R.string.pref_category_downloads
|
||||||
|
onClick { navigateTo(SettingsDownloadController()) }
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
iconRes = R.drawable.ic_language_black_24dp
|
||||||
|
iconTint = tintColor
|
||||||
|
titleRes = R.string.pref_category_sources
|
||||||
|
onClick { navigateTo(SettingsSourcesController()) }
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
iconRes = R.drawable.ic_sync_black_24dp
|
||||||
|
iconTint = tintColor
|
||||||
|
titleRes = R.string.pref_category_tracking
|
||||||
|
onClick { navigateTo(SettingsTrackingController()) }
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
iconRes = R.drawable.ic_backup_black_24dp
|
||||||
|
iconTint = tintColor
|
||||||
|
titleRes = R.string.backup
|
||||||
|
onClick { navigateTo(SettingsBackupController()) }
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
iconRes = R.drawable.ic_code_black_24dp
|
||||||
|
iconTint = tintColor
|
||||||
|
titleRes = R.string.pref_category_advanced
|
||||||
|
onClick { navigateTo(SettingsAdvancedController()) }
|
||||||
|
}
|
||||||
|
preference {
|
||||||
|
iconRes = R.drawable.ic_help_black_24dp
|
||||||
|
iconTint = tintColor
|
||||||
|
titleRes = R.string.pref_category_about
|
||||||
|
onClick { navigateTo(SettingsAboutController()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun navigateTo(controller: SettingsController) {
|
||||||
|
router.pushController(RouterTransaction.with(controller)
|
||||||
|
.pushChangeHandler(FadeChangeHandler())
|
||||||
|
.popChangeHandler(FadeChangeHandler()))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,106 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
|
import android.support.v7.preference.PreferenceScreen
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||||
|
|
||||||
|
class SettingsReaderController : SettingsController() {
|
||||||
|
|
||||||
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||||
|
titleRes = R.string.pref_category_reader
|
||||||
|
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.defaultViewer
|
||||||
|
titleRes = R.string.pref_viewer_type
|
||||||
|
entriesRes = arrayOf(R.string.left_to_right_viewer, R.string.right_to_left_viewer,
|
||||||
|
R.string.vertical_viewer, R.string.webtoon_viewer)
|
||||||
|
entryValues = arrayOf("1", "2", "3", "4")
|
||||||
|
defaultValue = "1"
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.imageScaleType
|
||||||
|
titleRes = R.string.pref_image_scale_type
|
||||||
|
entriesRes = arrayOf(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)
|
||||||
|
entryValues = arrayOf("1", "2", "3", "4", "5", "6")
|
||||||
|
defaultValue = "1"
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.zoomStart
|
||||||
|
titleRes = R.string.pref_zoom_start
|
||||||
|
entriesRes = arrayOf(R.string.zoom_start_automatic, R.string.zoom_start_left,
|
||||||
|
R.string.zoom_start_right, R.string.zoom_start_center)
|
||||||
|
entryValues = arrayOf("1", "2", "3", "4")
|
||||||
|
defaultValue = "1"
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.rotation
|
||||||
|
titleRes = R.string.pref_rotation_type
|
||||||
|
entriesRes = arrayOf(R.string.rotation_free, R.string.rotation_lock,
|
||||||
|
R.string.rotation_force_portrait, R.string.rotation_force_landscape)
|
||||||
|
entryValues = arrayOf("1", "2", "3", "4")
|
||||||
|
defaultValue = "1"
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.readerTheme
|
||||||
|
titleRes = R.string.pref_reader_theme
|
||||||
|
entriesRes = arrayOf(R.string.white_background, R.string.black_background)
|
||||||
|
entryValues = arrayOf("0", "1")
|
||||||
|
defaultValue = "0"
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
intListPreference {
|
||||||
|
key = Keys.imageDecoder
|
||||||
|
titleRes = R.string.pref_image_decoder
|
||||||
|
entries = arrayOf("Image", "Rapid", "Skia")
|
||||||
|
entryValues = arrayOf("0", "1", "2")
|
||||||
|
defaultValue = "0"
|
||||||
|
summary = "%s"
|
||||||
|
}
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.fullscreen
|
||||||
|
titleRes = R.string.pref_fullscreen
|
||||||
|
defaultValue = true
|
||||||
|
}
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.enableTransitions
|
||||||
|
titleRes = R.string.pref_page_transitions
|
||||||
|
defaultValue = true
|
||||||
|
}
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.showPageNumber
|
||||||
|
titleRes = R.string.pref_show_page_number
|
||||||
|
defaultValue = true
|
||||||
|
}
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.cropBorders
|
||||||
|
titleRes = R.string.pref_crop_borders
|
||||||
|
defaultValue = false
|
||||||
|
}
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.keepScreenOn
|
||||||
|
titleRes = R.string.pref_keep_screen_on
|
||||||
|
defaultValue = true
|
||||||
|
}
|
||||||
|
preferenceCategory {
|
||||||
|
titleRes = R.string.pref_reader_navigation
|
||||||
|
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.readWithTapping
|
||||||
|
titleRes = R.string.pref_read_with_tapping
|
||||||
|
defaultValue = true
|
||||||
|
}
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.readWithVolumeKeys
|
||||||
|
titleRes = R.string.pref_read_with_volume_keys
|
||||||
|
defaultValue = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,47 +1,27 @@
|
|||||||
package eu.kanade.tachiyomi.ui.setting
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Bundle
|
import android.support.v7.preference.PreferenceGroup
|
||||||
import android.support.v7.preference.XpPreferenceFragment
|
import android.support.v7.preference.PreferenceScreen
|
||||||
import android.view.View
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
|
import eu.kanade.tachiyomi.source.online.LoginSource
|
||||||
import eu.kanade.tachiyomi.widget.preference.LoginCheckBoxPreference
|
import eu.kanade.tachiyomi.widget.preference.LoginCheckBoxPreference
|
||||||
import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog
|
import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog
|
||||||
import eu.kanade.tachiyomi.widget.preference.SwitchPreferenceCategory
|
import eu.kanade.tachiyomi.widget.preference.SwitchPreferenceCategory
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class SettingsSourcesFragment : SettingsFragment() {
|
class SettingsSourcesController : SettingsController(),
|
||||||
|
SourceLoginDialog.Listener {
|
||||||
companion object {
|
|
||||||
const val SOURCE_CHANGE_REQUEST = 120
|
|
||||||
|
|
||||||
fun newInstance(rootKey: String?): SettingsSourcesFragment {
|
|
||||||
val args = Bundle()
|
|
||||||
args.putString(XpPreferenceFragment.ARG_PREFERENCE_ROOT, rootKey)
|
|
||||||
return SettingsSourcesFragment().apply { arguments = args }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val preferences: PreferencesHelper by injectLazy()
|
|
||||||
|
|
||||||
private val onlineSources by lazy { Injekt.get<SourceManager>().getOnlineSources() }
|
private val onlineSources by lazy { Injekt.get<SourceManager>().getOnlineSources() }
|
||||||
|
|
||||||
override fun setDivider(divider: Drawable?) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||||
super.setDivider(null)
|
titleRes = R.string.pref_category_sources
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedState)
|
|
||||||
|
|
||||||
// Remove dummy preference
|
|
||||||
preferenceScreen.removeAll()
|
|
||||||
|
|
||||||
// Get the list of active language codes.
|
// Get the list of active language codes.
|
||||||
val activeLangsCodes = preferences.enabledLanguages().getOrDefault()
|
val activeLangsCodes = preferences.enabledLanguages().getOrDefault()
|
||||||
@ -66,8 +46,8 @@ class SettingsSourcesFragment : SettingsFragment() {
|
|||||||
addLanguageSources(this, sources)
|
addLanguageSources(this, sources)
|
||||||
}
|
}
|
||||||
|
|
||||||
setOnPreferenceChangeListener { preference, any ->
|
onChange { newValue ->
|
||||||
val checked = any as Boolean
|
val checked = newValue as Boolean
|
||||||
val current = preferences.enabledLanguages().getOrDefault()
|
val current = preferences.enabledLanguages().getOrDefault()
|
||||||
if (!checked) {
|
if (!checked) {
|
||||||
preferences.enabledLanguages().set(current - lang)
|
preferences.enabledLanguages().set(current - lang)
|
||||||
@ -82,24 +62,28 @@ class SettingsSourcesFragment : SettingsFragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setDivider(divider: Drawable?) {
|
||||||
|
super.setDivider(null)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the source list for the given group (language).
|
* Adds the source list for the given group (language).
|
||||||
*
|
*
|
||||||
* @param group the language category.
|
* @param group the language category.
|
||||||
*/
|
*/
|
||||||
private fun addLanguageSources(group: SwitchPreferenceCategory, sources: List<HttpSource>) {
|
private fun addLanguageSources(group: PreferenceGroup, sources: List<HttpSource>) {
|
||||||
val hiddenCatalogues = preferences.hiddenCatalogues().getOrDefault()
|
val hiddenCatalogues = preferences.hiddenCatalogues().getOrDefault()
|
||||||
|
|
||||||
sources.forEach { source ->
|
sources.forEach { source ->
|
||||||
val sourcePreference = LoginCheckBoxPreference(context, source).apply {
|
val sourcePreference = LoginCheckBoxPreference(group.context, source).apply {
|
||||||
val id = source.id.toString()
|
val id = source.id.toString()
|
||||||
title = source.name
|
title = source.name
|
||||||
key = getSourceKey(source.id)
|
key = getSourceKey(source.id)
|
||||||
isPersistent = false
|
isPersistent = false
|
||||||
isChecked = id !in hiddenCatalogues
|
isChecked = id !in hiddenCatalogues
|
||||||
|
|
||||||
setOnPreferenceChangeListener { preference, any ->
|
onChange { newValue ->
|
||||||
val checked = any as Boolean
|
val checked = newValue as Boolean
|
||||||
val current = preferences.hiddenCatalogues().getOrDefault()
|
val current = preferences.hiddenCatalogues().getOrDefault()
|
||||||
|
|
||||||
preferences.hiddenCatalogues().set(if (checked)
|
preferences.hiddenCatalogues().set(if (checked)
|
||||||
@ -111,23 +95,19 @@ class SettingsSourcesFragment : SettingsFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setOnLoginClickListener {
|
setOnLoginClickListener {
|
||||||
val fragment = SourceLoginDialog.newInstance(source)
|
val dialog = SourceLoginDialog(source)
|
||||||
fragment.setTargetFragment(this@SettingsSourcesFragment, SOURCE_CHANGE_REQUEST)
|
dialog.targetController = this@SettingsSourcesController
|
||||||
fragment.show(fragmentManager, null)
|
dialog.showDialog(router)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group.addPreference(sourcePreference)
|
group.addPreference(sourcePreference)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun loginDialogClosed(source: LoginSource) {
|
||||||
if (requestCode == SOURCE_CHANGE_REQUEST && data != null) {
|
val pref = findPreference(getSourceKey(source.id)) as? LoginCheckBoxPreference
|
||||||
val sourceId = data.getLongExtra("key", -1L)
|
pref?.notifyChanged()
|
||||||
val pref = findPreference(getSourceKey(sourceId)) as? LoginCheckBoxPreference
|
|
||||||
pref?.notifyChanged()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSourceKey(sourceId: Long): String {
|
private fun getSourceKey(sourceId: Long): String {
|
@ -0,0 +1,91 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import android.support.customtabs.CustomTabsIntent
|
||||||
|
import android.support.v7.preference.PreferenceScreen
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
|
import eu.kanade.tachiyomi.data.track.anilist.AnilistApi
|
||||||
|
import eu.kanade.tachiyomi.util.getResourceColor
|
||||||
|
import eu.kanade.tachiyomi.widget.preference.LoginPreference
|
||||||
|
import eu.kanade.tachiyomi.widget.preference.TrackLoginDialog
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||||
|
|
||||||
|
class SettingsTrackingController : SettingsController(),
|
||||||
|
TrackLoginDialog.Listener {
|
||||||
|
|
||||||
|
private val trackManager: TrackManager by injectLazy()
|
||||||
|
|
||||||
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||||
|
titleRes = R.string.pref_category_tracking
|
||||||
|
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.autoUpdateTrack
|
||||||
|
titleRes = R.string.pref_auto_update_manga_sync
|
||||||
|
defaultValue = true
|
||||||
|
}
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.askUpdateTrack
|
||||||
|
titleRes = R.string.pref_ask_update_manga_sync
|
||||||
|
defaultValue = false
|
||||||
|
}.apply {
|
||||||
|
dependency = Keys.autoUpdateTrack // the preference needs to be attached.
|
||||||
|
}
|
||||||
|
preferenceCategory {
|
||||||
|
titleRes = R.string.services
|
||||||
|
|
||||||
|
trackPreference(trackManager.myAnimeList) {
|
||||||
|
onClick {
|
||||||
|
val dialog = TrackLoginDialog(trackManager.myAnimeList)
|
||||||
|
dialog.targetController = this@SettingsTrackingController
|
||||||
|
dialog.showDialog(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trackPreference(trackManager.aniList) {
|
||||||
|
onClick {
|
||||||
|
val tabsIntent = CustomTabsIntent.Builder()
|
||||||
|
.setToolbarColor(context.getResourceColor(R.attr.colorPrimary))
|
||||||
|
.build()
|
||||||
|
tabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
|
||||||
|
tabsIntent.launchUrl(activity, AnilistApi.authUrl())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trackPreference(trackManager.kitsu) {
|
||||||
|
onClick {
|
||||||
|
val dialog = TrackLoginDialog(trackManager.kitsu)
|
||||||
|
dialog.targetController = this@SettingsTrackingController
|
||||||
|
dialog.showDialog(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun PreferenceScreen.trackPreference(
|
||||||
|
service: TrackService,
|
||||||
|
block: (@DSL LoginPreference).() -> Unit
|
||||||
|
): LoginPreference {
|
||||||
|
return initThenAdd(LoginPreference(context).apply {
|
||||||
|
key = Keys.trackUsername(service.id)
|
||||||
|
title = service.name
|
||||||
|
}, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResumed(activity: Activity) {
|
||||||
|
super.onActivityResumed(activity)
|
||||||
|
// Manually refresh anilist holder
|
||||||
|
updatePreference(trackManager.aniList.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updatePreference(id: Int) {
|
||||||
|
val pref = findPreference(Keys.trackUsername(id)) as? LoginPreference
|
||||||
|
pref?.notifyChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun trackDialogClosed(service: TrackService) {
|
||||||
|
updatePreference(service.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,95 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.setting
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.support.customtabs.CustomTabsIntent
|
|
||||||
import android.support.v7.preference.PreferenceCategory
|
|
||||||
import android.support.v7.preference.XpPreferenceFragment
|
|
||||||
import android.view.View
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
|
||||||
import eu.kanade.tachiyomi.data.track.anilist.AnilistApi
|
|
||||||
import eu.kanade.tachiyomi.util.getResourceColor
|
|
||||||
import eu.kanade.tachiyomi.widget.preference.LoginPreference
|
|
||||||
import eu.kanade.tachiyomi.widget.preference.TrackLoginDialog
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
class SettingsTrackingFragment : SettingsFragment() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val SYNC_CHANGE_REQUEST = 121
|
|
||||||
|
|
||||||
fun newInstance(rootKey: String): SettingsTrackingFragment {
|
|
||||||
val args = Bundle()
|
|
||||||
args.putString(XpPreferenceFragment.ARG_PREFERENCE_ROOT, rootKey)
|
|
||||||
return SettingsTrackingFragment().apply { arguments = args }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val trackManager: TrackManager by injectLazy()
|
|
||||||
|
|
||||||
private val preferences: PreferencesHelper by injectLazy()
|
|
||||||
|
|
||||||
val syncCategory: PreferenceCategory by bindPref(R.string.pref_category_tracking_accounts_key)
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedState)
|
|
||||||
|
|
||||||
registerService(trackManager.myAnimeList)
|
|
||||||
|
|
||||||
registerService(trackManager.aniList) {
|
|
||||||
val intent = CustomTabsIntent.Builder()
|
|
||||||
.setToolbarColor(activity.getResourceColor(R.attr.colorPrimary))
|
|
||||||
.build()
|
|
||||||
intent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
|
|
||||||
intent.launchUrl(activity, AnilistApi.authUrl())
|
|
||||||
}
|
|
||||||
|
|
||||||
registerService(trackManager.kitsu)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T : TrackService> registerService(
|
|
||||||
service: T,
|
|
||||||
onPreferenceClick: (T) -> Unit = defaultOnPreferenceClick) {
|
|
||||||
|
|
||||||
LoginPreference(preferenceManager.context).apply {
|
|
||||||
key = preferences.keys.trackUsername(service.id)
|
|
||||||
title = service.name
|
|
||||||
|
|
||||||
setOnPreferenceClickListener {
|
|
||||||
onPreferenceClick(service)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
syncCategory.addPreference(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val defaultOnPreferenceClick: (TrackService) -> Unit
|
|
||||||
get() = {
|
|
||||||
val fragment = TrackLoginDialog.newInstance(it)
|
|
||||||
fragment.setTargetFragment(this, SYNC_CHANGE_REQUEST)
|
|
||||||
fragment.show(fragmentManager, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
// Manually refresh anilist holder
|
|
||||||
updatePreference(trackManager.aniList.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
if (requestCode == SYNC_CHANGE_REQUEST && data != null) {
|
|
||||||
val serviceId = data.getIntExtra("key", -1)
|
|
||||||
updatePreference(serviceId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updatePreference(id: Int) {
|
|
||||||
val pref = findPreference(preferences.keys.trackUsername(id)) as? LoginPreference
|
|
||||||
pref?.notifyChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -107,13 +107,20 @@ object DiskUtil {
|
|||||||
* Scans the given file so that it can be shown in gallery apps, for example.
|
* Scans the given file so that it can be shown in gallery apps, for example.
|
||||||
*/
|
*/
|
||||||
fun scanMedia(context: Context, file: File) {
|
fun scanMedia(context: Context, file: File) {
|
||||||
|
scanMedia(context, Uri.fromFile(file))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans the given file so that it can be shown in gallery apps, for example.
|
||||||
|
*/
|
||||||
|
fun scanMedia(context: Context, uri: Uri) {
|
||||||
val action = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
val action = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
|
||||||
Intent.ACTION_MEDIA_MOUNTED
|
Intent.ACTION_MEDIA_MOUNTED
|
||||||
} else {
|
} else {
|
||||||
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE
|
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE
|
||||||
}
|
}
|
||||||
val mediaScanIntent = Intent(action)
|
val mediaScanIntent = Intent(action)
|
||||||
mediaScanIntent.data = Uri.fromFile(file)
|
mediaScanIntent.data = uri
|
||||||
context.sendBroadcast(mediaScanIntent)
|
context.sendBroadcast(mediaScanIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.widget.preference
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.support.v7.preference.CheckBoxPreference
|
||||||
import android.support.v7.preference.PreferenceViewHolder
|
import android.support.v7.preference.PreferenceViewHolder
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -11,7 +12,6 @@ import eu.kanade.tachiyomi.source.online.LoginSource
|
|||||||
import eu.kanade.tachiyomi.util.getResourceColor
|
import eu.kanade.tachiyomi.util.getResourceColor
|
||||||
import eu.kanade.tachiyomi.util.setVectorCompat
|
import eu.kanade.tachiyomi.util.setVectorCompat
|
||||||
import kotlinx.android.synthetic.main.pref_item_source.view.*
|
import kotlinx.android.synthetic.main.pref_item_source.view.*
|
||||||
import net.xpece.android.support.preference.CheckBoxPreference
|
|
||||||
|
|
||||||
class LoginCheckBoxPreference @JvmOverloads constructor(
|
class LoginCheckBoxPreference @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@ -1,23 +1,22 @@
|
|||||||
package eu.kanade.tachiyomi.widget.preference
|
package eu.kanade.tachiyomi.widget.preference
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.DialogInterface
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.v4.app.DialogFragment
|
|
||||||
import android.text.method.PasswordTransformationMethod
|
import android.text.method.PasswordTransformationMethod
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
|
import com.bluelinelabs.conductor.ControllerChangeType
|
||||||
import com.dd.processbutton.iml.ActionProcessButton
|
import com.dd.processbutton.iml.ActionProcessButton
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
import eu.kanade.tachiyomi.widget.SimpleTextWatcher
|
import eu.kanade.tachiyomi.widget.SimpleTextWatcher
|
||||||
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
abstract class LoginDialogPreference : DialogFragment() {
|
abstract class LoginDialogPreference(bundle: Bundle? = null) : DialogController(bundle) {
|
||||||
|
|
||||||
var v: View? = null
|
var v: View? = null
|
||||||
private set
|
private set
|
||||||
@ -27,7 +26,7 @@ abstract class LoginDialogPreference : DialogFragment() {
|
|||||||
var requestSubscription: Subscription? = null
|
var requestSubscription: Subscription? = null
|
||||||
|
|
||||||
override fun onCreateDialog(savedState: Bundle?): Dialog {
|
override fun onCreateDialog(savedState: Bundle?): Dialog {
|
||||||
val dialog = MaterialDialog.Builder(activity)
|
val dialog = MaterialDialog.Builder(activity!!)
|
||||||
.customView(R.layout.pref_account_login, false)
|
.customView(R.layout.pref_account_login, false)
|
||||||
.negativeText(android.R.string.cancel)
|
.negativeText(android.R.string.cancel)
|
||||||
.build()
|
.build()
|
||||||
@ -37,7 +36,7 @@ abstract class LoginDialogPreference : DialogFragment() {
|
|||||||
return dialog
|
return dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
fun onViewCreated(view: View, savedState: Bundle?) {
|
||||||
v = view.apply {
|
v = view.apply {
|
||||||
show_password.setOnCheckedChangeListener { v, isChecked ->
|
show_password.setOnCheckedChangeListener { v, isChecked ->
|
||||||
if (isChecked)
|
if (isChecked)
|
||||||
@ -55,7 +54,7 @@ abstract class LoginDialogPreference : DialogFragment() {
|
|||||||
|
|
||||||
password.addTextChangedListener(object : SimpleTextWatcher() {
|
password.addTextChangedListener(object : SimpleTextWatcher() {
|
||||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||||
if (s.length == 0) {
|
if (s.isEmpty()) {
|
||||||
show_password.isEnabled = true
|
show_password.isEnabled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,15 +63,15 @@ abstract class LoginDialogPreference : DialogFragment() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
||||||
super.onPause()
|
super.onChangeStarted(handler, type)
|
||||||
requestSubscription?.unsubscribe()
|
if (!type.isEnter) {
|
||||||
|
onDialogClosed()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDismiss(dialog: DialogInterface) {
|
open fun onDialogClosed() {
|
||||||
super.onDismiss(dialog)
|
requestSubscription?.unsubscribe()
|
||||||
val intent = Intent().putExtras(arguments)
|
|
||||||
targetFragment?.onActivityResult(targetRequestCode, Activity.RESULT_OK, intent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun checkLogin()
|
protected abstract fun checkLogin()
|
||||||
|
@ -10,34 +10,17 @@ import eu.kanade.tachiyomi.util.toast
|
|||||||
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class SourceLoginDialog : LoginDialogPreference() {
|
class SourceLoginDialog(bundle: Bundle? = null) : LoginDialogPreference(bundle) {
|
||||||
|
|
||||||
companion object {
|
private val source = Injekt.get<SourceManager>().get(args.getLong("key")) as LoginSource
|
||||||
|
|
||||||
fun newInstance(source: Source): LoginDialogPreference {
|
constructor(source: Source) : this(Bundle().apply { putLong("key", source.id) })
|
||||||
val fragment = SourceLoginDialog()
|
|
||||||
val bundle = Bundle(1)
|
|
||||||
bundle.putLong("key", source.id)
|
|
||||||
fragment.arguments = bundle
|
|
||||||
return fragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val sourceManager: SourceManager by injectLazy()
|
|
||||||
|
|
||||||
lateinit var source: LoginSource
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
val sourceId = arguments.getLong("key")
|
|
||||||
source = sourceManager.get(sourceId) as LoginSource
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setCredentialsOnView(view: View) = with(view) {
|
override fun setCredentialsOnView(view: View) = with(view) {
|
||||||
dialog_title.text = getString(R.string.login_title, source.toString())
|
dialog_title.text = context.getString(R.string.login_title, source.toString())
|
||||||
username.setText(preferences.sourceUsername(source))
|
username.setText(preferences.sourceUsername(source))
|
||||||
password.setText(preferences.sourcePassword(source))
|
password.setText(preferences.sourcePassword(source))
|
||||||
}
|
}
|
||||||
@ -60,7 +43,7 @@ class SourceLoginDialog : LoginDialogPreference() {
|
|||||||
username.text.toString(),
|
username.text.toString(),
|
||||||
password.text.toString())
|
password.text.toString())
|
||||||
|
|
||||||
dialog.dismiss()
|
dialog?.dismiss()
|
||||||
context.toast(R.string.login_success)
|
context.toast(R.string.login_success)
|
||||||
} else {
|
} else {
|
||||||
preferences.setSourceCredentials(source, "", "")
|
preferences.setSourceCredentials(source, "", "")
|
||||||
@ -74,4 +57,13 @@ class SourceLoginDialog : LoginDialogPreference() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDialogClosed() {
|
||||||
|
super.onDialogClosed()
|
||||||
|
(targetController as? Listener)?.loginDialogClosed(source)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun loginDialogClosed(source: LoginSource)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,16 @@ import android.annotation.TargetApi
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.TypedArray
|
import android.content.res.TypedArray
|
||||||
import android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH
|
import android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH
|
||||||
|
import android.support.v7.preference.PreferenceCategory
|
||||||
import android.support.v7.preference.PreferenceViewHolder
|
import android.support.v7.preference.PreferenceViewHolder
|
||||||
import android.support.v7.widget.SwitchCompat
|
import android.support.v7.widget.SwitchCompat
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Checkable
|
import android.widget.Checkable
|
||||||
import android.widget.CompoundButton
|
import android.widget.CompoundButton
|
||||||
|
import android.widget.TextView
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.util.getResourceColor
|
import eu.kanade.tachiyomi.util.getResourceColor
|
||||||
import net.xpece.android.support.preference.PreferenceCategory
|
|
||||||
import net.xpece.android.support.preference.R
|
|
||||||
|
|
||||||
class SwitchPreferenceCategory @JvmOverloads constructor(
|
class SwitchPreferenceCategory @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
@ -20,20 +21,17 @@ class SwitchPreferenceCategory @JvmOverloads constructor(
|
|||||||
: PreferenceCategory(
|
: PreferenceCategory(
|
||||||
context,
|
context,
|
||||||
attrs,
|
attrs,
|
||||||
R.attr.switchPreferenceCompatStyle,
|
R.attr.switchPreferenceCompatStyle),
|
||||||
R.style.Preference_Material_SwitchPreferenceCompat),
|
|
||||||
CompoundButton.OnCheckedChangeListener {
|
CompoundButton.OnCheckedChangeListener {
|
||||||
|
|
||||||
init {
|
|
||||||
setTitleTextColor(context.getResourceColor(R.attr.colorAccent))
|
|
||||||
}
|
|
||||||
|
|
||||||
private var mChecked = false
|
private var mChecked = false
|
||||||
|
|
||||||
private var mCheckedSet = false
|
private var mCheckedSet = false
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||||
super.onBindViewHolder(holder)
|
super.onBindViewHolder(holder)
|
||||||
|
val titleView = holder.findViewById(android.R.id.title) as TextView
|
||||||
|
titleView.setTextColor(context.getResourceColor(R.attr.colorAccent))
|
||||||
syncSwitchView(holder)
|
syncSwitchView(holder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,36 +9,19 @@ import eu.kanade.tachiyomi.util.toast
|
|||||||
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
class TrackLoginDialog : LoginDialogPreference() {
|
class TrackLoginDialog(bundle: Bundle? = null) : LoginDialogPreference(bundle) {
|
||||||
|
|
||||||
companion object {
|
private val service = Injekt.get<TrackManager>().getService(args.getInt("key"))!!
|
||||||
|
|
||||||
fun newInstance(sync: TrackService): LoginDialogPreference {
|
constructor(service: TrackService) : this(Bundle().apply { putInt("key", service.id) })
|
||||||
val fragment = TrackLoginDialog()
|
|
||||||
val bundle = Bundle(1)
|
|
||||||
bundle.putInt("key", sync.id)
|
|
||||||
fragment.arguments = bundle
|
|
||||||
return fragment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val trackManager: TrackManager by injectLazy()
|
|
||||||
|
|
||||||
lateinit var sync: TrackService
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
|
|
||||||
val syncId = arguments.getInt("key")
|
|
||||||
sync = trackManager.getService(syncId)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setCredentialsOnView(view: View) = with(view) {
|
override fun setCredentialsOnView(view: View) = with(view) {
|
||||||
dialog_title.text = getString(R.string.login_title, sync.name)
|
dialog_title.text = context.getString(R.string.login_title, service.name)
|
||||||
username.setText(sync.getUsername())
|
username.setText(service.getUsername())
|
||||||
password.setText(sync.getPassword())
|
password.setText(service.getPassword())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun checkLogin() {
|
override fun checkLogin() {
|
||||||
@ -52,11 +35,11 @@ class TrackLoginDialog : LoginDialogPreference() {
|
|||||||
val user = username.text.toString()
|
val user = username.text.toString()
|
||||||
val pass = password.text.toString()
|
val pass = password.text.toString()
|
||||||
|
|
||||||
requestSubscription = sync.login(user, pass)
|
requestSubscription = service.login(user, pass)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe({
|
.subscribe({
|
||||||
dialog.dismiss()
|
dialog?.dismiss()
|
||||||
context.toast(R.string.login_success)
|
context.toast(R.string.login_success)
|
||||||
}, { error ->
|
}, { error ->
|
||||||
login.progress = -1
|
login.progress = -1
|
||||||
@ -67,4 +50,13 @@ class TrackLoginDialog : LoginDialogPreference() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDialogClosed() {
|
||||||
|
super.onDialogClosed()
|
||||||
|
(targetController as? Listener)?.trackDialogClosed(service)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun trackDialogClosed(service: TrackService)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
android:id="@+id/portrait_columns"
|
android:id="@+id/portrait_columns"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:descendantFocusability="blocksDescendants"
|
||||||
app:max="10"
|
app:max="10"
|
||||||
app:min="0"/>
|
app:min="0"/>
|
||||||
|
|
||||||
@ -46,6 +47,7 @@
|
|||||||
android:id="@+id/landscape_columns"
|
android:id="@+id/landscape_columns"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:descendantFocusability="blocksDescendants"
|
||||||
app:max="10"
|
app:max="10"
|
||||||
app:min="0"/>
|
app:min="0"/>
|
||||||
|
|
||||||
|
@ -1,81 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="pref_category_general_key" translatable="false">pref_category_general_key</string>
|
|
||||||
<string name="pref_category_reader_key" translatable="false">pref_category_reader_key</string>
|
|
||||||
<string name="pref_category_tracking_key" translatable="false">pref_category_tracking_key</string>
|
|
||||||
<string name="pref_category_downloads_key" translatable="false">pref_category_downloads_key</string>
|
|
||||||
<string name="pref_category_advanced_key" translatable="false">pref_category_advanced_key</string>
|
|
||||||
<string name="pref_category_about_key" translatable="false">pref_category_about_key</string>
|
|
||||||
<string name="pref_category_sources_key" translatable="false">pref_category_sources_key</string>
|
|
||||||
|
|
||||||
<string name="pref_display_library_as_list" translatable="false">pref_display_library_as_list</string>
|
|
||||||
<string name="pref_library_columns_dialog_key" translatable="false">pref_library_columns_dialog_key</string>
|
|
||||||
<string name="pref_library_columns_portrait_key" translatable="false">pref_library_columns_portrait_key</string>
|
|
||||||
<string name="pref_library_columns_landscape_key" translatable="false">pref_library_columns_landscape_key</string>
|
|
||||||
<string name="pref_library_update_interval_key" translatable="false">pref_library_update_interval_key</string>
|
|
||||||
<string name="pref_library_update_categories_key" translatable="false">library_update_categories</string>
|
|
||||||
<string name="pref_update_only_non_completed_key" translatable="false">pref_update_only_non_completed_key</string>
|
|
||||||
<string name="pref_auto_update_manga_sync_key" translatable="false">pref_auto_update_manga_sync_key</string>
|
|
||||||
<string name="pref_ask_update_manga_sync_key" translatable="false">pref_ask_update_manga_sync_key</string>
|
|
||||||
<string name="pref_theme_key" translatable="false">pref_theme_key</string>
|
|
||||||
<string name="pref_library_update_restriction_key" translatable="false">library_update_restriction</string>
|
|
||||||
<string name="pref_start_screen_key" translatable="false">start_screen</string>
|
|
||||||
<string name="pref_language_key" translatable="false">app_language</string>
|
|
||||||
<string name="default_category_key" translatable="false">default_category</string>
|
|
||||||
|
|
||||||
<string name="pref_default_viewer_key" translatable="false">pref_default_viewer_key</string>
|
|
||||||
<string name="pref_image_scale_type_key" translatable="false">pref_image_scale_type_key</string>
|
|
||||||
<string name="pref_zoom_start_key" translatable="false">pref_zoom_start_key</string>
|
|
||||||
<string name="pref_fullscreen_key" translatable="false">fullscreen</string>
|
|
||||||
<string name="pref_rotation_type_key" translatable="false">pref_rotation_type_key</string>
|
|
||||||
<string name="pref_enable_transitions_key" translatable="false">pref_enable_transitions_key</string>
|
|
||||||
<string name="pref_show_page_number_key" translatable="false">pref_show_page_number_key</string>
|
|
||||||
<string name="pref_keep_screen_on_key" translatable="false">pref_keep_screen_on_key</string>
|
|
||||||
<string name="pref_custom_brightness_key" translatable="false">pref_custom_brightness_key</string>
|
|
||||||
<string name="pref_custom_brightness_value_key" translatable="false">custom_brightness_value</string>
|
|
||||||
<string name="pref_color_filter_key" translatable="false">pref_color_filter_key</string>
|
|
||||||
<string name="pref_color_filter_value_key" translatable="false">color_filter_value</string>
|
|
||||||
<string name="pref_red_filter_value_key" translatable="false">pref_red_filter_value</string>
|
|
||||||
<string name="pref_reader_theme_key" translatable="false">pref_reader_theme_key</string>
|
|
||||||
<string name="pref_image_decoder_key" translatable="false">image_decoder</string>
|
|
||||||
<string name="pref_crop_borders_key" translatable="false">crop_borders</string>
|
|
||||||
<string name="pref_read_with_volume_keys_key" translatable="false">reader_volume_keys</string>
|
|
||||||
<string name="pref_read_with_tapping_key" translatable="false">reader_tap</string>
|
|
||||||
|
|
||||||
<string name="pref_filter_downloaded_key" translatable="false">pref_filter_downloaded_key</string>
|
|
||||||
<string name="pref_filter_unread_key" translatable="false">pref_filter_unread_key</string>
|
|
||||||
<string name="pref_library_sorting_mode_key" translatable="false">library_sorting_mode</string>
|
|
||||||
|
|
||||||
<string name="pref_download_directory_key" translatable="false">download_directory</string>
|
|
||||||
<string name="pref_download_slots_key" translatable="false">pref_download_slots_key</string>
|
|
||||||
<string name="pref_remove_after_read_slots_key" translatable="false">remove_after_read_slots</string>
|
|
||||||
<string name="pref_download_only_over_wifi_key" translatable="false">pref_download_only_over_wifi_key</string>
|
|
||||||
<string name="pref_remove_after_marked_as_read_key" translatable="false">pref_remove_after_marked_as_read_key</string>
|
|
||||||
<string name="pref_last_used_category_key" translatable="false">last_used_category</string>
|
|
||||||
|
|
||||||
<string name="pref_create_local_backup_key" translatable="false">create_local_backup</string>
|
|
||||||
<string name="pref_restore_local_backup_key" translatable="false">restore_local_backup</string>
|
|
||||||
<string name="pref_backup_interval_key" translatable="false">backup_interval</string>
|
|
||||||
<string name="pref_backup_directory_key" translatable="false">backup_directory</string>
|
|
||||||
<string name="pref_backup_slots_key" translatable="false">backup_slots</string>
|
|
||||||
|
|
||||||
<string name="pref_source_languages" translatable="false">source_languages</string>
|
|
||||||
<string name="pref_category_tracking_accounts_key" translatable="false">category_tracking_accounts</string>
|
|
||||||
|
|
||||||
<string name="pref_clear_chapter_cache_key" translatable="false">pref_clear_chapter_cache_key</string>
|
|
||||||
<string name="pref_clear_database_key" translatable="false">pref_clear_database_key</string>
|
|
||||||
<string name="pref_clear_cookies_key" translatable="false">pref_clear_cookies_key</string>
|
|
||||||
<string name="pref_refresh_library_metadata_key" translatable="false">refresh_library_metadata</string>
|
|
||||||
|
|
||||||
<string name="pref_version" translatable="false">pref_version</string>
|
|
||||||
<string name="pref_build_time" translatable="false">pref_build_time</string>
|
|
||||||
<string name="pref_enable_automatic_updates_key" translatable="false">automatic_updates</string>
|
|
||||||
|
|
||||||
<string name="pref_display_catalogue_as_list" translatable="false">pref_display_catalogue_as_list</string>
|
|
||||||
<string name="pref_last_catalogue_source_key" translatable="false">last_catalogue_source</string>
|
|
||||||
|
|
||||||
<string name="pref_download_new_key" translatable="false">download_new</string>
|
|
||||||
<string name="pref_download_new_categories_key" translatable="false">download_new_categories</string>
|
|
||||||
|
|
||||||
<!-- String Fonts -->
|
<!-- String Fonts -->
|
||||||
<string name="font_roboto_medium" translatable="false">sans-serif</string>
|
<string name="font_roboto_medium" translatable="false">sans-serif</string>
|
||||||
|
@ -36,8 +36,6 @@
|
|||||||
<item name="selectable_library_drawable">@drawable/library_item_selector_light</item>
|
<item name="selectable_library_drawable">@drawable/library_item_selector_light</item>
|
||||||
<item name="text_color_primary">@color/textColorPrimaryLight</item>
|
<item name="text_color_primary">@color/textColorPrimaryLight</item>
|
||||||
<item name="background_card">@color/dialogLight</item>
|
<item name="background_card">@color/dialogLight</item>
|
||||||
<item name="asp_preferenceIconTint">?colorAccent</item>
|
|
||||||
<item name="asp_preferenceDialogIconTint">?colorAccent</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Tachiyomi" parent="Theme.Base">
|
<style name="Theme.Tachiyomi" parent="Theme.Base">
|
||||||
@ -76,8 +74,6 @@
|
|||||||
<item name="selectable_library_drawable">@drawable/library_item_selector_dark</item>
|
<item name="selectable_library_drawable">@drawable/library_item_selector_dark</item>
|
||||||
<item name="text_color_primary">@color/textColorPrimaryDark</item>
|
<item name="text_color_primary">@color/textColorPrimaryDark</item>
|
||||||
<item name="background_card">@color/dialogDark</item>
|
<item name="background_card">@color/dialogDark</item>
|
||||||
<item name="asp_preferenceIconTint">?colorAccent</item>
|
|
||||||
<item name="asp_preferenceDialogIconTint">?colorAccent</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Tachiyomi.Dark" parent="Theme.Base.Dark">
|
<style name="Theme.Tachiyomi.Dark" parent="Theme.Base.Dark">
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<PreferenceScreen
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<PreferenceScreen
|
|
||||||
android:icon="@drawable/ic_help_black_24dp"
|
|
||||||
android:key="about_screen"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/pref_category_about"
|
|
||||||
app:asp_tintEnabled="true">
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:defaultValue="true"
|
|
||||||
android:key="acra.enable"
|
|
||||||
android:summary="@string/pref_acra_summary"
|
|
||||||
android:title="@string/pref_enable_acra" />
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="@string/pref_enable_automatic_updates_key"
|
|
||||||
android:summary="@string/pref_enable_automatic_updates_summary"
|
|
||||||
android:title="@string/pref_enable_automatic_updates" />
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="@string/pref_version"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/version"/>
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="@string/pref_build_time"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/build_time"/>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
@ -1,33 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<PreferenceScreen
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<PreferenceScreen
|
|
||||||
android:icon="@drawable/ic_code_black_24dp"
|
|
||||||
android:key="advanced_screen"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/pref_category_advanced"
|
|
||||||
app:asp_tintEnabled="true">
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="@string/pref_clear_chapter_cache_key"
|
|
||||||
android:title="@string/pref_clear_chapter_cache"/>
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="@string/pref_clear_cookies_key"
|
|
||||||
android:title="@string/pref_clear_cookies"/>
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="@string/pref_clear_database_key"
|
|
||||||
android:summary="@string/pref_clear_database_summary"
|
|
||||||
android:title="@string/pref_clear_database"/>
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="@string/pref_refresh_library_metadata_key"
|
|
||||||
android:summary="@string/pref_refresh_library_metadata_summary"
|
|
||||||
android:title="@string/pref_refresh_library_metadata"/>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
@ -1,48 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<PreferenceScreen
|
|
||||||
android:icon="@drawable/ic_backup_black_24dp"
|
|
||||||
android:key="backup_screen"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="Backup"
|
|
||||||
app:asp_tintEnabled="true">
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="@string/pref_create_local_backup_key"
|
|
||||||
android:summary="@string/pref_create_backup_summ"
|
|
||||||
android:title="@string/pref_create_backup" />
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="@string/pref_restore_local_backup_key"
|
|
||||||
android:summary="@string/pref_restore_backup_summ"
|
|
||||||
android:title="@string/pref_restore_backup" />
|
|
||||||
|
|
||||||
<PreferenceCategory
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/pref_backup_service_category" />
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:defaultValue="0"
|
|
||||||
android:entries="@array/backup_update_interval"
|
|
||||||
android:entryValues="@array/backup_update_interval_values"
|
|
||||||
android:key="@string/pref_backup_interval_key"
|
|
||||||
android:summary="%s"
|
|
||||||
android:title="@string/pref_backup_interval"/>
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="@string/pref_backup_directory_key"
|
|
||||||
android:title="@string/pref_backup_directory" />
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:defaultValue="1"
|
|
||||||
android:entries="@array/backup_slots"
|
|
||||||
android:entryValues="@array/backup_slots"
|
|
||||||
android:key="@string/pref_backup_slots_key"
|
|
||||||
android:summary="%s"
|
|
||||||
android:title="@string/pref_backup_slots" />
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
@ -1,62 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<PreferenceScreen
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<PreferenceScreen
|
|
||||||
android:icon="@drawable/ic_file_download_black_24dp"
|
|
||||||
android:key="downloads_screen"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/pref_category_downloads"
|
|
||||||
app:asp_tintEnabled="true">
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="@string/pref_download_directory_key"
|
|
||||||
android:title="@string/pref_download_directory"/>
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:defaultValue="true"
|
|
||||||
android:key="@string/pref_download_only_over_wifi_key"
|
|
||||||
android:title="@string/pref_download_only_over_wifi" />
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:defaultValue="1"
|
|
||||||
android:entries="@array/download_slots"
|
|
||||||
android:entryValues="@array/download_slots"
|
|
||||||
android:key="@string/pref_download_slots_key"
|
|
||||||
android:summary="%s"
|
|
||||||
android:title="@string/pref_download_slots"/>
|
|
||||||
|
|
||||||
<PreferenceCategory
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/pref_remove_after_read" />
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="@string/pref_remove_after_marked_as_read_key"
|
|
||||||
android:title="@string/pref_remove_after_marked_as_read" />
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:defaultValue="-1"
|
|
||||||
android:entries="@array/remove_after_read_slots"
|
|
||||||
android:entryValues="@array/remove_after_read_slots_values"
|
|
||||||
android:key="@string/pref_remove_after_read_slots_key"
|
|
||||||
android:summary="%s"
|
|
||||||
android:title="@string/pref_remove_after_read" />
|
|
||||||
|
|
||||||
<PreferenceCategory
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/pref_download_new" />
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="@string/pref_download_new_key"
|
|
||||||
android:title="@string/pref_download_new"/>
|
|
||||||
|
|
||||||
<MultiSelectListPreference
|
|
||||||
android:key="@string/pref_download_new_categories_key"
|
|
||||||
android:title="@string/pref_download_new_categories" />
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
@ -1,76 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<PreferenceScreen
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<PreferenceScreen
|
|
||||||
android:icon="@drawable/ic_tune_black_24dp"
|
|
||||||
android:key="general_screen"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/pref_category_general"
|
|
||||||
app:asp_tintEnabled="true">
|
|
||||||
|
|
||||||
<ListPreference
|
|
||||||
android:defaultValue=""
|
|
||||||
android:entryValues="@array/languages_values"
|
|
||||||
android:key="@string/pref_language_key"
|
|
||||||
android:summary="%s"
|
|
||||||
android:title="@string/pref_language" />
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:defaultValue="1"
|
|
||||||
android:entries="@array/themes"
|
|
||||||
android:entryValues="@array/themes_values"
|
|
||||||
android:key="@string/pref_theme_key"
|
|
||||||
android:summary="%s"
|
|
||||||
android:title="@string/pref_theme"/>
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:title="@string/pref_start_screen"
|
|
||||||
android:key="@string/pref_start_screen_key"
|
|
||||||
android:entries="@array/start_screen_selection"
|
|
||||||
android:entryValues="@array/start_screen_selection_values"
|
|
||||||
android:defaultValue="1"
|
|
||||||
android:summary="%s"/>
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.SimpleDialogPreference
|
|
||||||
android:dialogLayout="@layout/pref_library_columns"
|
|
||||||
android:key="@string/pref_library_columns_dialog_key"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/pref_library_columns"/>
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:defaultValue="0"
|
|
||||||
android:entries="@array/library_update_interval"
|
|
||||||
android:entryValues="@array/library_update_interval_values"
|
|
||||||
android:key="@string/pref_library_update_interval_key"
|
|
||||||
android:summary="%s"
|
|
||||||
android:title="@string/pref_library_update_interval"/>
|
|
||||||
|
|
||||||
<MultiSelectListPreference
|
|
||||||
android:entries="@array/library_update_restrictions"
|
|
||||||
android:entryValues="@array/library_update_restrictions_values"
|
|
||||||
android:key="@string/pref_library_update_restriction_key"
|
|
||||||
android:summary="@string/pref_library_update_restriction_summary"
|
|
||||||
android:title="@string/pref_library_update_restriction" />
|
|
||||||
|
|
||||||
<MultiSelectListPreference
|
|
||||||
android:key="@string/pref_library_update_categories_key"
|
|
||||||
android:title="@string/pref_library_update_categories"/>
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="@string/pref_update_only_non_completed_key"
|
|
||||||
android:title="@string/pref_update_only_non_completed" />
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:defaultValue="-1"
|
|
||||||
android:entries="@array/default_category_entry"
|
|
||||||
android:entryValues="@array/default_category_entry_value"
|
|
||||||
android:key="@string/default_category_key"
|
|
||||||
android:title="@string/default_category"
|
|
||||||
android:summary="@string/default_category_summary"/>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
@ -1,103 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<PreferenceScreen
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<PreferenceScreen
|
|
||||||
android:icon="@drawable/ic_chrome_reader_mode_black_24dp"
|
|
||||||
android:key="reader_screen"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/pref_category_reader"
|
|
||||||
app:asp_tintEnabled="true">
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:title="@string/pref_viewer_type"
|
|
||||||
android:key="@string/pref_default_viewer_key"
|
|
||||||
android:entries="@array/viewers"
|
|
||||||
android:entryValues="@array/viewers_values"
|
|
||||||
android:defaultValue="1"
|
|
||||||
android:summary="%s"/>
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:title="@string/pref_image_scale_type"
|
|
||||||
android:key="@string/pref_image_scale_type_key"
|
|
||||||
android:entries="@array/image_scale_type"
|
|
||||||
android:entryValues="@array/image_scale_type_values"
|
|
||||||
android:defaultValue="1"
|
|
||||||
android:summary="%s"/>
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:title="@string/pref_zoom_start"
|
|
||||||
android:key="@string/pref_zoom_start_key"
|
|
||||||
android:entries="@array/zoom_start"
|
|
||||||
android:entryValues="@array/zoom_start_values"
|
|
||||||
android:defaultValue="1"
|
|
||||||
android:summary="%s"/>
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:title="@string/pref_rotation_type"
|
|
||||||
android:key="@string/pref_rotation_type_key"
|
|
||||||
android:entries="@array/rotation_type"
|
|
||||||
android:entryValues="@array/rotation_type_values"
|
|
||||||
android:defaultValue="1"
|
|
||||||
android:summary="%s"/>
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:title="@string/pref_reader_theme"
|
|
||||||
android:key="@string/pref_reader_theme_key"
|
|
||||||
android:entries="@array/reader_themes"
|
|
||||||
android:entryValues="@array/reader_themes_values"
|
|
||||||
android:defaultValue="0"
|
|
||||||
android:summary="%s"/>
|
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.preference.IntListPreference
|
|
||||||
android:title="@string/pref_image_decoder"
|
|
||||||
android:key="@string/pref_image_decoder_key"
|
|
||||||
android:entries="@array/image_decoders"
|
|
||||||
android:entryValues="@array/image_decoders_values"
|
|
||||||
android:defaultValue="0"
|
|
||||||
android:summary="%s" />
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:title="@string/pref_fullscreen"
|
|
||||||
android:key="@string/pref_fullscreen_key"
|
|
||||||
android:defaultValue="true" />
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:title="@string/pref_page_transitions"
|
|
||||||
android:key="@string/pref_enable_transitions_key"
|
|
||||||
android:defaultValue="true" />
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:title="@string/pref_show_page_number"
|
|
||||||
android:key="@string/pref_show_page_number_key"
|
|
||||||
android:defaultValue="true" />
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:title="@string/pref_crop_borders"
|
|
||||||
android:key="@string/pref_crop_borders_key"
|
|
||||||
android:defaultValue="false" />
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:title="@string/pref_keep_screen_on"
|
|
||||||
android:key="@string/pref_keep_screen_on_key"
|
|
||||||
android:defaultValue="true" />
|
|
||||||
|
|
||||||
<PreferenceCategory
|
|
||||||
android:title="@string/pref_reader_navigation">
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:title="@string/pref_read_with_tapping"
|
|
||||||
android:key="@string/pref_read_with_tapping_key"
|
|
||||||
android:defaultValue="true" />
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:title="@string/pref_read_with_volume_keys"
|
|
||||||
android:key="@string/pref_read_with_volume_keys_key"
|
|
||||||
android:defaultValue="false" />
|
|
||||||
|
|
||||||
</PreferenceCategory>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<PreferenceScreen
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<PreferenceScreen
|
|
||||||
android:icon="@drawable/ic_language_black_24dp"
|
|
||||||
android:key="sources_screen"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/pref_category_sources"
|
|
||||||
app:asp_tintEnabled="true">
|
|
||||||
|
|
||||||
<!-- Dummy preference, it's needed at least one -->
|
|
||||||
<Preference/>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
@ -1,33 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
|
||||||
|
|
||||||
<PreferenceScreen
|
|
||||||
android:icon="@drawable/ic_sync_black_24dp"
|
|
||||||
android:key="tracking_screen"
|
|
||||||
android:persistent="false"
|
|
||||||
android:title="@string/pref_category_tracking"
|
|
||||||
app:asp_tintEnabled="true">
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:key="@string/pref_auto_update_manga_sync_key"
|
|
||||||
android:title="@string/pref_auto_update_manga_sync"
|
|
||||||
android:defaultValue="true"
|
|
||||||
app:showText="false"/>
|
|
||||||
|
|
||||||
<SwitchPreference
|
|
||||||
android:key="@string/pref_ask_update_manga_sync_key"
|
|
||||||
android:title="@string/pref_ask_update_manga_sync"
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:dependency="@string/pref_auto_update_manga_sync_key"
|
|
||||||
app:showText="false"/>
|
|
||||||
|
|
||||||
<PreferenceCategory
|
|
||||||
android:key="@string/pref_category_tracking_accounts_key"
|
|
||||||
android:title="@string/services"
|
|
||||||
android:persistent="false"
|
|
||||||
app:showText="false"/>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
||||||
|
|
||||||
</PreferenceScreen>
|
|
Loading…
Reference in New Issue
Block a user