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 {
|
||||
|
||||
compile "com.bluelinelabs:conductor:2.1.3"
|
||||
compile 'com.github.inorichi:conductor-support-preference:master-SNAPSHOT'
|
||||
|
||||
final rxbindings_version = '1.0.1'
|
||||
compile "com.jakewharton.rxbinding:rxbinding-kotlin:$rxbindings_version"
|
||||
@ -204,7 +205,6 @@ dependencies {
|
||||
compile 'com.nononsenseapps:filepicker:2.5.2'
|
||||
compile 'com.github.amulyakhare:TextDrawable:558677e'
|
||||
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 'de.hdodenhof:circleimageview:2.1.0'
|
||||
|
||||
|
@ -35,10 +35,6 @@
|
||||
<activity
|
||||
android:name=".ui.reader.ReaderActivity"
|
||||
android:theme="@style/Theme.Reader" />
|
||||
<activity
|
||||
android:name=".ui.setting.SettingsActivity"
|
||||
android:label="@string/label_settings"
|
||||
android:parentActivityName=".ui.main.MainActivity" />
|
||||
<activity
|
||||
android:name=".widget.CustomLayoutPickerActivity"
|
||||
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.VERSION
|
||||
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.sendLocalBroadcast
|
||||
import timber.log.Timber
|
||||
@ -28,8 +27,6 @@ class BackupCreateService : IntentService(NAME) {
|
||||
// Name of class
|
||||
private const val NAME = "BackupCreateService"
|
||||
|
||||
// Uri as string
|
||||
private const val EXTRA_URI = "$ID.$NAME.EXTRA_URI"
|
||||
// Backup called from job
|
||||
private const val EXTRA_IS_JOB = "$ID.$NAME.EXTRA_IS_JOB"
|
||||
// Options for backup
|
||||
@ -56,7 +53,7 @@ class BackupCreateService : IntentService(NAME) {
|
||||
*/
|
||||
fun makeBackup(context: Context, path: String, flags: Int, isJob: Boolean = false) {
|
||||
val intent = Intent(context, BackupCreateService::class.java).apply {
|
||||
putExtra(EXTRA_URI, path)
|
||||
putExtra(BackupConst.EXTRA_URI, path)
|
||||
putExtra(EXTRA_IS_JOB, isJob)
|
||||
putExtra(EXTRA_FLAGS, flags)
|
||||
}
|
||||
@ -74,7 +71,7 @@ class BackupCreateService : IntentService(NAME) {
|
||||
if (intent == null) return
|
||||
|
||||
// Get values
|
||||
val uri = intent.getStringExtra(EXTRA_URI)
|
||||
val uri = intent.getStringExtra(BackupConst.EXTRA_URI)
|
||||
val isJob = intent.getBooleanExtra(EXTRA_IS_JOB, false)
|
||||
val flags = intent.getIntExtra(EXTRA_FLAGS, 0)
|
||||
// Create backup
|
||||
@ -150,9 +147,9 @@ class BackupCreateService : IntentService(NAME) {
|
||||
}
|
||||
|
||||
// Show completed dialog
|
||||
val intent = Intent(SettingsBackupFragment.INTENT_FILTER).apply {
|
||||
putExtra(SettingsBackupFragment.ACTION, SettingsBackupFragment.ACTION_BACKUP_COMPLETED_DIALOG)
|
||||
putExtra(SettingsBackupFragment.EXTRA_URI, file.uri.toString())
|
||||
val intent = Intent(BackupConst.INTENT_FILTER).apply {
|
||||
putExtra(BackupConst.ACTION, BackupConst.ACTION_BACKUP_COMPLETED_DIALOG)
|
||||
putExtra(BackupConst.EXTRA_URI, file.uri.toString())
|
||||
}
|
||||
sendLocalBroadcast(intent)
|
||||
}
|
||||
@ -160,9 +157,9 @@ class BackupCreateService : IntentService(NAME) {
|
||||
Timber.e(e)
|
||||
if (!isJob) {
|
||||
// Show error dialog
|
||||
val intent = Intent(SettingsBackupFragment.INTENT_FILTER).apply {
|
||||
putExtra(SettingsBackupFragment.ACTION, SettingsBackupFragment.ACTION_ERROR_BACKUP_DIALOG)
|
||||
putExtra(SettingsBackupFragment.EXTRA_ERROR_MESSAGE, e.message)
|
||||
val intent = Intent(BackupConst.INTENT_FILTER).apply {
|
||||
putExtra(BackupConst.ACTION, BackupConst.ACTION_ERROR_BACKUP_DIALOG)
|
||||
putExtra(BackupConst.EXTRA_ERROR_MESSAGE, e.message)
|
||||
}
|
||||
sendLocalBroadcast(intent)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ class BackupCreatorJob : Job() {
|
||||
val preferences = Injekt.get<PreferencesHelper>()
|
||||
val path = preferences.backupsDirectory().getOrDefault()
|
||||
val flags = BackupCreateService.BACKUP_ALL
|
||||
BackupCreateService.makeBackup(context,path,flags,true)
|
||||
BackupCreateService.makeBackup(context, path, flags, true)
|
||||
return Result.SUCCESS
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,6 @@ import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.util.syncChaptersWithSource
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.*
|
||||
|
||||
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.models.*
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsBackupFragment
|
||||
import eu.kanade.tachiyomi.util.AndroidComponentUtil
|
||||
import eu.kanade.tachiyomi.util.chop
|
||||
import eu.kanade.tachiyomi.util.sendLocalBroadcast
|
||||
@ -36,7 +35,6 @@ import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
||||
|
||||
/**
|
||||
* Restores backup from json file
|
||||
@ -44,11 +42,6 @@ import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID
|
||||
class BackupRestoreService : Service() {
|
||||
|
||||
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.
|
||||
@ -69,7 +62,7 @@ class BackupRestoreService : Service() {
|
||||
fun start(context: Context, uri: Uri) {
|
||||
if (!isRunning(context)) {
|
||||
val intent = Intent(context, BackupRestoreService::class.java).apply {
|
||||
putExtra(EXTRA_URI, uri)
|
||||
putExtra(BackupConst.EXTRA_URI, uri)
|
||||
}
|
||||
context.startService(intent)
|
||||
}
|
||||
@ -164,7 +157,7 @@ class BackupRestoreService : Service() {
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
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.
|
||||
subscription?.unsubscribe()
|
||||
@ -236,12 +229,12 @@ class BackupRestoreService : Service() {
|
||||
val endTime = System.currentTimeMillis()
|
||||
val time = endTime - startTime
|
||||
val logFile = writeErrorLog()
|
||||
val completeIntent = Intent(SettingsBackupFragment.INTENT_FILTER).apply {
|
||||
putExtra(SettingsBackupFragment.EXTRA_TIME, time)
|
||||
putExtra(SettingsBackupFragment.EXTRA_ERRORS, errors.size)
|
||||
putExtra(SettingsBackupFragment.EXTRA_ERROR_FILE_PATH, logFile.parent)
|
||||
putExtra(SettingsBackupFragment.EXTRA_ERROR_FILE, logFile.name)
|
||||
putExtra(SettingsBackupFragment.ACTION, SettingsBackupFragment.ACTION_RESTORE_COMPLETED_DIALOG)
|
||||
val completeIntent = Intent(BackupConst.INTENT_FILTER).apply {
|
||||
putExtra(BackupConst.EXTRA_TIME, time)
|
||||
putExtra(BackupConst.EXTRA_ERRORS, errors.size)
|
||||
putExtra(BackupConst.EXTRA_ERROR_FILE_PATH, logFile.parent)
|
||||
putExtra(BackupConst.EXTRA_ERROR_FILE, logFile.name)
|
||||
putExtra(BackupConst.ACTION, BackupConst.ACTION_RESTORE_COMPLETED_DIALOG)
|
||||
}
|
||||
sendLocalBroadcast(completeIntent)
|
||||
|
||||
@ -249,9 +242,9 @@ class BackupRestoreService : Service() {
|
||||
.doOnError { error ->
|
||||
Timber.e(error)
|
||||
writeErrorLog()
|
||||
val errorIntent = Intent(SettingsBackupFragment.INTENT_FILTER).apply {
|
||||
putExtra(SettingsBackupFragment.ACTION, SettingsBackupFragment.ACTION_ERROR_RESTORE_DIALOG)
|
||||
putExtra(SettingsBackupFragment.EXTRA_ERROR_MESSAGE, error.message)
|
||||
val errorIntent = Intent(BackupConst.INTENT_FILTER).apply {
|
||||
putExtra(BackupConst.ACTION, BackupConst.ACTION_ERROR_RESTORE_DIALOG)
|
||||
putExtra(BackupConst.EXTRA_ERROR_MESSAGE, error.message)
|
||||
}
|
||||
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 amount total restoreAmount of manga
|
||||
@ -400,12 +393,12 @@ class BackupRestoreService : Service() {
|
||||
*/
|
||||
private fun showRestoreProgress(progress: Int, amount: Int, title: String, errors: Int,
|
||||
content: String = getString(R.string.dialog_restoring_backup, title.chop(15))) {
|
||||
val intent = Intent(SettingsBackupFragment.INTENT_FILTER).apply {
|
||||
putExtra(SettingsBackupFragment.EXTRA_PROGRESS, progress)
|
||||
putExtra(SettingsBackupFragment.EXTRA_AMOUNT, amount)
|
||||
putExtra(SettingsBackupFragment.EXTRA_CONTENT, content)
|
||||
putExtra(SettingsBackupFragment.EXTRA_ERRORS, errors)
|
||||
putExtra(SettingsBackupFragment.ACTION, SettingsBackupFragment.ACTION_SET_PROGRESS_DIALOG)
|
||||
val intent = Intent(BackupConst.INTENT_FILTER).apply {
|
||||
putExtra(BackupConst.EXTRA_PROGRESS, progress)
|
||||
putExtra(BackupConst.EXTRA_AMOUNT, amount)
|
||||
putExtra(BackupConst.EXTRA_CONTENT, content)
|
||||
putExtra(BackupConst.EXTRA_ERRORS, errors)
|
||||
putExtra(BackupConst.ACTION, BackupConst.ACTION_SET_PROGRESS_DIALOG)
|
||||
}
|
||||
sendLocalBroadcast(intent)
|
||||
}
|
||||
|
@ -1,105 +1,105 @@
|
||||
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
|
||||
* in the file "keys.xml". By using this class we can define preferences in one place and get them
|
||||
* referenced here.
|
||||
* This class stores the keys for the preferences in the application.
|
||||
*/
|
||||
@Suppress("HasPlatformType")
|
||||
class PreferenceKeys(context: Context) {
|
||||
object PreferenceKeys {
|
||||
|
||||
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"
|
||||
|
||||
@ -111,10 +111,4 @@ class PreferenceKeys(context: Context) {
|
||||
|
||||
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.source.Source
|
||||
import java.io.File
|
||||
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
|
||||
|
||||
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) {
|
||||
|
||||
val keys = PreferenceKeys(context)
|
||||
|
||||
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
private val rxPrefs = RxSharedPreferences.create(prefs)
|
||||
|
||||
@ -30,134 +29,134 @@ class PreferencesHelper(val context: Context) {
|
||||
File(Environment.getExternalStorageDirectory().absolutePath + File.separator +
|
||||
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 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 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) {
|
||||
prefs.edit()
|
||||
.putString(keys.sourceUsername(source.id), username)
|
||||
.putString(keys.sourcePassword(source.id), password)
|
||||
.putString(Keys.sourceUsername(source.id), username)
|
||||
.putString(Keys.sourcePassword(source.id), password)
|
||||
.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) {
|
||||
prefs.edit()
|
||||
.putString(keys.trackUsername(sync.id), username)
|
||||
.putString(keys.trackPassword(sync.id), password)
|
||||
.putString(Keys.trackUsername(sync.id), username)
|
||||
.putString(Keys.trackPassword(sync.id), password)
|
||||
.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 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 automaticUpdates() = prefs.getBoolean(keys.automaticUpdates, false)
|
||||
fun automaticUpdates() = prefs.getBoolean(Keys.automaticUpdates, false)
|
||||
|
||||
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.ControllerChangeType
|
||||
import com.bluelinelabs.conductor.RestoreViewOnCreateController
|
||||
import com.bluelinelabs.conductor.Router
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.app.TaskStackBuilder
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
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.recent_updates.RecentChaptersController
|
||||
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.toolbar.*
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
@ -85,10 +84,10 @@ class MainActivity : BaseActivity() {
|
||||
R.id.nav_drawer_downloads -> {
|
||||
startActivity(Intent(this, DownloadActivity::class.java))
|
||||
}
|
||||
R.id.nav_drawer_settings -> {
|
||||
val intent = Intent(this, SettingsActivity::class.java)
|
||||
startActivityForResult(intent, REQUEST_OPEN_SETTINGS)
|
||||
}
|
||||
R.id.nav_drawer_settings ->
|
||||
router.pushController(RouterTransaction.with(SettingsMainController())
|
||||
.pushChangeHandler(FadeChangeHandler())
|
||||
.popChangeHandler(FadeChangeHandler()))
|
||||
}
|
||||
}
|
||||
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 {
|
||||
private const val REQUEST_OPEN_SETTINGS = 200
|
||||
// Shortcut actions
|
||||
private const val SHORTCUT_LIBRARY = "eu.kanade.tachiyomi.SHOW_LIBRARY"
|
||||
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.download.model.Download
|
||||
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.reader.ReaderActivity
|
||||
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.ui.base.controller.NoToolbarElevationController
|
||||
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.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.util.toast
|
||||
|
@ -8,6 +8,7 @@ import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ProgressBar
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
@ -41,7 +42,7 @@ class AnilistLoginActivity : AppCompatActivity() {
|
||||
private fun returnToSettings() {
|
||||
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)
|
||||
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
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.support.v7.preference.XpPreferenceFragment
|
||||
import android.view.View
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import android.support.v7.preference.PreferenceGroup
|
||||
import android.support.v7.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
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.SourceLoginDialog
|
||||
import eu.kanade.tachiyomi.widget.preference.SwitchPreferenceCategory
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.*
|
||||
|
||||
class SettingsSourcesFragment : SettingsFragment() {
|
||||
|
||||
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()
|
||||
class SettingsSourcesController : SettingsController(),
|
||||
SourceLoginDialog.Listener {
|
||||
|
||||
private val onlineSources by lazy { Injekt.get<SourceManager>().getOnlineSources() }
|
||||
|
||||
override fun setDivider(divider: Drawable?) {
|
||||
super.setDivider(null)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
||||
super.onViewCreated(view, savedState)
|
||||
|
||||
// Remove dummy preference
|
||||
preferenceScreen.removeAll()
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||
titleRes = R.string.pref_category_sources
|
||||
|
||||
// Get the list of active language codes.
|
||||
val activeLangsCodes = preferences.enabledLanguages().getOrDefault()
|
||||
@ -66,8 +46,8 @@ class SettingsSourcesFragment : SettingsFragment() {
|
||||
addLanguageSources(this, sources)
|
||||
}
|
||||
|
||||
setOnPreferenceChangeListener { preference, any ->
|
||||
val checked = any as Boolean
|
||||
onChange { newValue ->
|
||||
val checked = newValue as Boolean
|
||||
val current = preferences.enabledLanguages().getOrDefault()
|
||||
if (!checked) {
|
||||
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).
|
||||
*
|
||||
* @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()
|
||||
|
||||
sources.forEach { source ->
|
||||
val sourcePreference = LoginCheckBoxPreference(context, source).apply {
|
||||
val sourcePreference = LoginCheckBoxPreference(group.context, source).apply {
|
||||
val id = source.id.toString()
|
||||
title = source.name
|
||||
key = getSourceKey(source.id)
|
||||
isPersistent = false
|
||||
isChecked = id !in hiddenCatalogues
|
||||
|
||||
setOnPreferenceChangeListener { preference, any ->
|
||||
val checked = any as Boolean
|
||||
onChange { newValue ->
|
||||
val checked = newValue as Boolean
|
||||
val current = preferences.hiddenCatalogues().getOrDefault()
|
||||
|
||||
preferences.hiddenCatalogues().set(if (checked)
|
||||
@ -111,24 +95,20 @@ class SettingsSourcesFragment : SettingsFragment() {
|
||||
}
|
||||
|
||||
setOnLoginClickListener {
|
||||
val fragment = SourceLoginDialog.newInstance(source)
|
||||
fragment.setTargetFragment(this@SettingsSourcesFragment, SOURCE_CHANGE_REQUEST)
|
||||
fragment.show(fragmentManager, null)
|
||||
val dialog = SourceLoginDialog(source)
|
||||
dialog.targetController = this@SettingsSourcesController
|
||||
dialog.showDialog(router)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
group.addPreference(sourcePreference)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == SOURCE_CHANGE_REQUEST && data != null) {
|
||||
val sourceId = data.getLongExtra("key", -1L)
|
||||
val pref = findPreference(getSourceKey(sourceId)) as? LoginCheckBoxPreference
|
||||
override fun loginDialogClosed(source: LoginSource) {
|
||||
val pref = findPreference(getSourceKey(source.id)) as? LoginCheckBoxPreference
|
||||
pref?.notifyChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSourceKey(sourceId: Long): String {
|
||||
return "source_$sourceId"
|
@ -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.
|
||||
*/
|
||||
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) {
|
||||
Intent.ACTION_MEDIA_MOUNTED
|
||||
} else {
|
||||
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE
|
||||
}
|
||||
val mediaScanIntent = Intent(action)
|
||||
mediaScanIntent.data = Uri.fromFile(file)
|
||||
mediaScanIntent.data = uri
|
||||
context.sendBroadcast(mediaScanIntent)
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.widget.preference
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.support.v7.preference.CheckBoxPreference
|
||||
import android.support.v7.preference.PreferenceViewHolder
|
||||
import android.util.AttributeSet
|
||||
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.setVectorCompat
|
||||
import kotlinx.android.synthetic.main.pref_item_source.view.*
|
||||
import net.xpece.android.support.preference.CheckBoxPreference
|
||||
|
||||
class LoginCheckBoxPreference @JvmOverloads constructor(
|
||||
context: Context,
|
||||
|
@ -1,23 +1,22 @@
|
||||
package eu.kanade.tachiyomi.widget.preference
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.text.method.PasswordTransformationMethod
|
||||
import android.view.View
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.dd.processbutton.iml.ActionProcessButton
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
import eu.kanade.tachiyomi.widget.SimpleTextWatcher
|
||||
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
||||
import rx.Subscription
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
|
||||
abstract class LoginDialogPreference : DialogFragment() {
|
||||
abstract class LoginDialogPreference(bundle: Bundle? = null) : DialogController(bundle) {
|
||||
|
||||
var v: View? = null
|
||||
private set
|
||||
@ -27,7 +26,7 @@ abstract class LoginDialogPreference : DialogFragment() {
|
||||
var requestSubscription: Subscription? = null
|
||||
|
||||
override fun onCreateDialog(savedState: Bundle?): Dialog {
|
||||
val dialog = MaterialDialog.Builder(activity)
|
||||
val dialog = MaterialDialog.Builder(activity!!)
|
||||
.customView(R.layout.pref_account_login, false)
|
||||
.negativeText(android.R.string.cancel)
|
||||
.build()
|
||||
@ -37,7 +36,7 @@ abstract class LoginDialogPreference : DialogFragment() {
|
||||
return dialog
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedState: Bundle?) {
|
||||
fun onViewCreated(view: View, savedState: Bundle?) {
|
||||
v = view.apply {
|
||||
show_password.setOnCheckedChangeListener { v, isChecked ->
|
||||
if (isChecked)
|
||||
@ -55,7 +54,7 @@ abstract class LoginDialogPreference : DialogFragment() {
|
||||
|
||||
password.addTextChangedListener(object : SimpleTextWatcher() {
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
if (s.length == 0) {
|
||||
if (s.isEmpty()) {
|
||||
show_password.isEnabled = true
|
||||
}
|
||||
}
|
||||
@ -64,15 +63,15 @@ abstract class LoginDialogPreference : DialogFragment() {
|
||||
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
requestSubscription?.unsubscribe()
|
||||
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
||||
super.onChangeStarted(handler, type)
|
||||
if (!type.isEnter) {
|
||||
onDialogClosed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
val intent = Intent().putExtras(arguments)
|
||||
targetFragment?.onActivityResult(targetRequestCode, Activity.RESULT_OK, intent)
|
||||
open fun onDialogClosed() {
|
||||
requestSubscription?.unsubscribe()
|
||||
}
|
||||
|
||||
protected abstract fun checkLogin()
|
||||
|
@ -10,34 +10,17 @@ import eu.kanade.tachiyomi.util.toast
|
||||
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
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 {
|
||||
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
|
||||
}
|
||||
constructor(source: Source) : this(Bundle().apply { putLong("key", source.id) })
|
||||
|
||||
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))
|
||||
password.setText(preferences.sourcePassword(source))
|
||||
}
|
||||
@ -60,7 +43,7 @@ class SourceLoginDialog : LoginDialogPreference() {
|
||||
username.text.toString(),
|
||||
password.text.toString())
|
||||
|
||||
dialog.dismiss()
|
||||
dialog?.dismiss()
|
||||
context.toast(R.string.login_success)
|
||||
} else {
|
||||
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.res.TypedArray
|
||||
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.widget.SwitchCompat
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.Checkable
|
||||
import android.widget.CompoundButton
|
||||
import android.widget.TextView
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.getResourceColor
|
||||
import net.xpece.android.support.preference.PreferenceCategory
|
||||
import net.xpece.android.support.preference.R
|
||||
|
||||
class SwitchPreferenceCategory @JvmOverloads constructor(
|
||||
context: Context,
|
||||
@ -20,20 +21,17 @@ class SwitchPreferenceCategory @JvmOverloads constructor(
|
||||
: PreferenceCategory(
|
||||
context,
|
||||
attrs,
|
||||
R.attr.switchPreferenceCompatStyle,
|
||||
R.style.Preference_Material_SwitchPreferenceCompat),
|
||||
R.attr.switchPreferenceCompatStyle),
|
||||
CompoundButton.OnCheckedChangeListener {
|
||||
|
||||
init {
|
||||
setTitleTextColor(context.getResourceColor(R.attr.colorAccent))
|
||||
}
|
||||
|
||||
private var mChecked = false
|
||||
|
||||
private var mCheckedSet = false
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
super.onBindViewHolder(holder)
|
||||
val titleView = holder.findViewById(android.R.id.title) as TextView
|
||||
titleView.setTextColor(context.getResourceColor(R.attr.colorAccent))
|
||||
syncSwitchView(holder)
|
||||
}
|
||||
|
||||
|
@ -9,36 +9,19 @@ import eu.kanade.tachiyomi.util.toast
|
||||
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
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 {
|
||||
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)!!
|
||||
}
|
||||
constructor(service: TrackService) : this(Bundle().apply { putInt("key", service.id) })
|
||||
|
||||
override fun setCredentialsOnView(view: View) = with(view) {
|
||||
dialog_title.text = getString(R.string.login_title, sync.name)
|
||||
username.setText(sync.getUsername())
|
||||
password.setText(sync.getPassword())
|
||||
dialog_title.text = context.getString(R.string.login_title, service.name)
|
||||
username.setText(service.getUsername())
|
||||
password.setText(service.getPassword())
|
||||
}
|
||||
|
||||
override fun checkLogin() {
|
||||
@ -52,11 +35,11 @@ class TrackLoginDialog : LoginDialogPreference() {
|
||||
val user = username.text.toString()
|
||||
val pass = password.text.toString()
|
||||
|
||||
requestSubscription = sync.login(user, pass)
|
||||
requestSubscription = service.login(user, pass)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
dialog.dismiss()
|
||||
dialog?.dismiss()
|
||||
context.toast(R.string.login_success)
|
||||
}, { error ->
|
||||
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:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
app:max="10"
|
||||
app:min="0"/>
|
||||
|
||||
@ -46,6 +47,7 @@
|
||||
android:id="@+id/landscape_columns"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
app:max="10"
|
||||
app:min="0"/>
|
||||
|
||||
|
@ -1,81 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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 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="text_color_primary">@color/textColorPrimaryLight</item>
|
||||
<item name="background_card">@color/dialogLight</item>
|
||||
<item name="asp_preferenceIconTint">?colorAccent</item>
|
||||
<item name="asp_preferenceDialogIconTint">?colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Tachiyomi" parent="Theme.Base">
|
||||
@ -76,8 +74,6 @@
|
||||
<item name="selectable_library_drawable">@drawable/library_item_selector_dark</item>
|
||||
<item name="text_color_primary">@color/textColorPrimaryDark</item>
|
||||
<item name="background_card">@color/dialogDark</item>
|
||||
<item name="asp_preferenceIconTint">?colorAccent</item>
|
||||
<item name="asp_preferenceDialogIconTint">?colorAccent</item>
|
||||
</style>
|
||||
|
||||
<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