ExtensionPresenter.kt 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package eu.kanade.tachiyomi.ui.extension
  2. import android.os.Bundle
  3. import eu.kanade.tachiyomi.extension.ExtensionManager
  4. import eu.kanade.tachiyomi.extension.model.Extension
  5. import eu.kanade.tachiyomi.extension.model.InstallStep
  6. import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
  7. import rx.Observable
  8. import rx.Subscription
  9. import rx.android.schedulers.AndroidSchedulers
  10. import uy.kohesive.injekt.Injekt
  11. import uy.kohesive.injekt.api.get
  12. import java.util.concurrent.TimeUnit
  13. private typealias ExtensionTuple
  14. = Triple<List<Extension.Installed>, List<Extension.Untrusted>, List<Extension.Available>>
  15. /**
  16. * Presenter of [ExtensionController].
  17. */
  18. open class ExtensionPresenter(
  19. private val extensionManager: ExtensionManager = Injekt.get()
  20. ) : BasePresenter<ExtensionController>() {
  21. private var extensions = emptyList<ExtensionItem>()
  22. private var currentDownloads = hashMapOf<String, InstallStep>()
  23. override fun onCreate(savedState: Bundle?) {
  24. super.onCreate(savedState)
  25. bindToExtensionsObservable()
  26. }
  27. private fun bindToExtensionsObservable(): Subscription {
  28. val installedObservable = extensionManager.getInstalledExtensionsObservable()
  29. val untrustedObservable = extensionManager.getUntrustedExtensionsObservable()
  30. val availableObservable = extensionManager.getAvailableExtensionsObservable()
  31. .startWith(emptyList<Extension.Available>())
  32. return Observable.combineLatest(installedObservable, untrustedObservable, availableObservable)
  33. { installed, untrusted, available -> Triple(installed, untrusted, available) }
  34. .debounce(100, TimeUnit.MILLISECONDS)
  35. .map(::toItems)
  36. .observeOn(AndroidSchedulers.mainThread())
  37. .subscribeLatestCache({ view, _ -> view.setExtensions(extensions) })
  38. }
  39. @Synchronized
  40. private fun toItems(tuple: ExtensionTuple): List<ExtensionItem> {
  41. val (installed, untrusted, available) = tuple
  42. val items = mutableListOf<ExtensionItem>()
  43. val installedSorted = installed.sortedWith(compareBy({ !it.hasUpdate }, { it.name }))
  44. val untrustedSorted = untrusted.sortedBy { it.name }
  45. val availableSorted = available
  46. // Filter out already installed extensions
  47. .filter { avail -> installed.none { it.pkgName == avail.pkgName }
  48. && untrusted.none { it.pkgName == avail.pkgName } }
  49. .sortedBy { it.name }
  50. if (installedSorted.isNotEmpty() || untrustedSorted.isNotEmpty()) {
  51. val header = ExtensionGroupItem(true, installedSorted.size + untrustedSorted.size)
  52. items += installedSorted.map { extension ->
  53. ExtensionItem(extension, header, currentDownloads[extension.pkgName])
  54. }
  55. items += untrustedSorted.map { extension ->
  56. ExtensionItem(extension, header)
  57. }
  58. }
  59. if (availableSorted.isNotEmpty()) {
  60. val header = ExtensionGroupItem(false, availableSorted.size)
  61. items += availableSorted.map { extension ->
  62. ExtensionItem(extension, header, currentDownloads[extension.pkgName])
  63. }
  64. }
  65. this.extensions = items
  66. return items
  67. }
  68. @Synchronized
  69. private fun updateInstallStep(extension: Extension, state: InstallStep): ExtensionItem? {
  70. val extensions = extensions.toMutableList()
  71. val position = extensions.indexOfFirst { it.extension.pkgName == extension.pkgName }
  72. return if (position != -1) {
  73. val item = extensions[position].copy(installStep = state)
  74. extensions[position] = item
  75. this.extensions = extensions
  76. item
  77. } else {
  78. null
  79. }
  80. }
  81. fun installExtension(extension: Extension.Available) {
  82. extensionManager.installExtension(extension).subscribeToInstallUpdate(extension)
  83. }
  84. fun updateExtension(extension: Extension.Installed) {
  85. extensionManager.updateExtension(extension).subscribeToInstallUpdate(extension)
  86. }
  87. private fun Observable<InstallStep>.subscribeToInstallUpdate(extension: Extension) {
  88. this.doOnNext { currentDownloads[extension.pkgName] = it }
  89. .doOnUnsubscribe { currentDownloads.remove(extension.pkgName) }
  90. .map { state -> updateInstallStep(extension, state) }
  91. .subscribeWithView({ view, item ->
  92. if (item != null) {
  93. view.downloadUpdate(item)
  94. }
  95. })
  96. }
  97. fun uninstallExtension(pkgName: String) {
  98. extensionManager.uninstallExtension(pkgName)
  99. }
  100. fun findAvailableExtensions() {
  101. extensionManager.findAvailableExtensions()
  102. }
  103. fun trustSignature(signatureHash: String) {
  104. extensionManager.trustSignature(signatureHash)
  105. }
  106. }