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 dependencypull/798/head
parent
29fd5747eb
commit
ff190e02d4
@ -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"
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
@ -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