SettingsDownloadController.kt 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package eu.kanade.tachiyomi.ui.setting
  2. import android.app.Activity
  3. import android.app.Dialog
  4. import android.content.ActivityNotFoundException
  5. import android.content.Intent
  6. import android.net.Uri
  7. import android.os.Bundle
  8. import android.os.Environment
  9. import androidx.core.content.ContextCompat
  10. import androidx.preference.PreferenceScreen
  11. import com.afollestad.materialdialogs.MaterialDialog
  12. import com.hippo.unifile.UniFile
  13. import eu.kanade.tachiyomi.R
  14. import eu.kanade.tachiyomi.data.database.DatabaseHelper
  15. import eu.kanade.tachiyomi.data.preference.PreferencesHelper
  16. import eu.kanade.tachiyomi.data.preference.getOrDefault
  17. import eu.kanade.tachiyomi.ui.base.controller.DialogController
  18. import eu.kanade.tachiyomi.util.getFilePicker
  19. import uy.kohesive.injekt.Injekt
  20. import uy.kohesive.injekt.api.get
  21. import uy.kohesive.injekt.injectLazy
  22. import java.io.File
  23. import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
  24. class SettingsDownloadController : SettingsController() {
  25. private val db: DatabaseHelper by injectLazy()
  26. override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
  27. titleRes = R.string.pref_category_downloads
  28. preference {
  29. key = Keys.downloadsDirectory
  30. titleRes = R.string.pref_download_directory
  31. onClick {
  32. val ctrl = DownloadDirectoriesDialog()
  33. ctrl.targetController = this@SettingsDownloadController
  34. ctrl.showDialog(router)
  35. }
  36. preferences.downloadsDirectory().asObservable()
  37. .subscribeUntilDestroy { path ->
  38. val dir = UniFile.fromUri(context, Uri.parse(path))
  39. summary = dir.filePath ?: path
  40. }
  41. }
  42. switchPreference {
  43. key = Keys.downloadOnlyOverWifi
  44. titleRes = R.string.pref_download_only_over_wifi
  45. defaultValue = true
  46. }
  47. preferenceCategory {
  48. titleRes = R.string.pref_remove_after_read
  49. switchPreference {
  50. key = Keys.removeAfterMarkedAsRead
  51. titleRes = R.string.pref_remove_after_marked_as_read
  52. defaultValue = false
  53. }
  54. intListPreference {
  55. key = Keys.removeAfterReadSlots
  56. titleRes = R.string.pref_remove_after_read
  57. entriesRes = arrayOf(R.string.disabled, R.string.last_read_chapter,
  58. R.string.second_to_last, R.string.third_to_last, R.string.fourth_to_last,
  59. R.string.fifth_to_last)
  60. entryValues = arrayOf("-1", "0", "1", "2", "3", "4")
  61. defaultValue = "-1"
  62. summary = "%s"
  63. }
  64. }
  65. val dbCategories = db.getCategories().executeAsBlocking()
  66. preferenceCategory {
  67. titleRes = R.string.pref_download_new
  68. switchPreference {
  69. key = Keys.downloadNew
  70. titleRes = R.string.pref_download_new
  71. defaultValue = false
  72. }
  73. multiSelectListPreference {
  74. key = Keys.downloadNewCategories
  75. titleRes = R.string.pref_download_new_categories
  76. entries = dbCategories.map { it.name }.toTypedArray()
  77. entryValues = dbCategories.map { it.id.toString() }.toTypedArray()
  78. preferences.downloadNew().asObservable()
  79. .subscribeUntilDestroy { isVisible = it }
  80. preferences.downloadNewCategories().asObservable()
  81. .subscribeUntilDestroy {
  82. val selectedCategories = it
  83. .mapNotNull { id -> dbCategories.find { it.id == id.toInt() } }
  84. .sortedBy { it.order }
  85. summary = if (selectedCategories.isEmpty())
  86. resources?.getString(R.string.all)
  87. else
  88. selectedCategories.joinToString { it.name }
  89. }
  90. }
  91. }
  92. }
  93. override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
  94. when (requestCode) {
  95. DOWNLOAD_DIR -> if (data != null && resultCode == Activity.RESULT_OK) {
  96. val context = applicationContext ?: return
  97. val uri = data.data
  98. val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
  99. Intent.FLAG_GRANT_WRITE_URI_PERMISSION
  100. @Suppress("NewApi")
  101. context.contentResolver.takePersistableUriPermission(uri, flags)
  102. val file = UniFile.fromUri(context, uri)
  103. preferences.downloadsDirectory().set(file.uri.toString())
  104. }
  105. }
  106. }
  107. fun predefinedDirectorySelected(selectedDir: String) {
  108. val path = Uri.fromFile(File(selectedDir))
  109. preferences.downloadsDirectory().set(path.toString())
  110. }
  111. fun customDirectorySelected(currentDir: String) {
  112. val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
  113. try {
  114. startActivityForResult(intent, DOWNLOAD_DIR)
  115. } catch (e: ActivityNotFoundException) {
  116. startActivityForResult(preferences.context.getFilePicker(currentDir), DOWNLOAD_DIR)
  117. }
  118. }
  119. class DownloadDirectoriesDialog : DialogController() {
  120. private val preferences: PreferencesHelper = Injekt.get()
  121. override fun onCreateDialog(savedViewState: Bundle?): Dialog {
  122. val activity = activity!!
  123. val currentDir = preferences.downloadsDirectory().getOrDefault()
  124. val externalDirs = getExternalDirs() + File(activity.getString(R.string.custom_dir))
  125. val selectedIndex = externalDirs.map(File::toString).indexOfFirst { it in currentDir }
  126. return MaterialDialog.Builder(activity)
  127. .items(externalDirs)
  128. .itemsCallbackSingleChoice(selectedIndex, { _, _, which, text ->
  129. val target = targetController as? SettingsDownloadController
  130. if (which == externalDirs.lastIndex) {
  131. target?.customDirectorySelected(currentDir)
  132. } else {
  133. target?.predefinedDirectorySelected(text.toString())
  134. }
  135. true
  136. })
  137. .build()
  138. }
  139. private fun getExternalDirs(): List<File> {
  140. val defaultDir = Environment.getExternalStorageDirectory().absolutePath +
  141. File.separator + resources?.getString(R.string.app_name) +
  142. File.separator + "downloads"
  143. return mutableListOf(File(defaultDir)) +
  144. ContextCompat.getExternalFilesDirs(activity!!, "").filterNotNull()
  145. }
  146. }
  147. private companion object {
  148. const val DOWNLOAD_DIR = 104
  149. }
  150. }