Implement new extension install methods (#5904)

* Implement new extension install methods

* Fixes

* Resolve feedback

* Keep pending status when waiting to install

* Cancellable installation

* Remove auto error now that we have cancellable job
This commit is contained in:
Ivan Iskandar
2021-09-26 01:31:52 +07:00
committed by GitHub
parent 1ae0d1b5d0
commit b284384f0a
24 changed files with 738 additions and 61 deletions

View File

@@ -22,5 +22,6 @@ class ExtensionAdapter(controller: ExtensionController) :
interface OnButtonClickListener {
fun onButtonClick(position: Int)
fun onCancelButtonClick(position: Int)
}
}

View File

@@ -119,6 +119,11 @@ open class ExtensionController :
}
}
override fun onCancelButtonClick(position: Int) {
val extension = (adapter?.getItem(position) as? ExtensionItem)?.extension ?: return
presenter.cancelInstallUpdateExtension(extension)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.browse_extensions, menu)

View File

@@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.ui.browse.extension
import android.view.View
import androidx.core.view.isVisible
import coil.clear
import coil.load
import eu.davidea.viewholders.FlexibleViewHolder
@@ -9,7 +10,6 @@ import eu.kanade.tachiyomi.databinding.ExtensionCardItemBinding
import eu.kanade.tachiyomi.extension.model.Extension
import eu.kanade.tachiyomi.extension.model.InstallStep
import eu.kanade.tachiyomi.util.system.LocaleHelper
import uy.kohesive.injekt.api.get
class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
FlexibleViewHolder(view, adapter) {
@@ -20,6 +20,9 @@ class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
binding.extButton.setOnClickListener {
adapter.buttonClickListener.onButtonClick(bindingAdapterPosition)
}
binding.cancelButton.setOnClickListener {
adapter.buttonClickListener.onCancelButtonClick(bindingAdapterPosition)
}
}
fun bind(item: ExtensionItem) {
@@ -42,44 +45,40 @@ class ExtensionHolder(view: View, val adapter: ExtensionAdapter) :
} else {
extension.getApplicationIcon(itemView.context)?.let { binding.image.setImageDrawable(it) }
}
bindButton(item)
bindButtons(item)
}
@Suppress("ResourceType")
fun bindButton(item: ExtensionItem) = with(binding.extButton) {
isEnabled = true
isClickable = true
fun bindButtons(item: ExtensionItem) = with(binding.extButton) {
val extension = item.extension
val installStep = item.installStep
if (installStep != null) {
setText(
when (installStep) {
InstallStep.Pending -> R.string.ext_pending
InstallStep.Downloading -> R.string.ext_downloading
InstallStep.Installing -> R.string.ext_installing
InstallStep.Installed -> R.string.ext_installed
InstallStep.Error -> R.string.action_retry
}
)
if (installStep != InstallStep.Error) {
isEnabled = false
isClickable = false
}
} else if (extension is Extension.Installed) {
when {
extension.hasUpdate -> {
setText(R.string.ext_update)
}
else -> {
setText(R.string.action_settings)
setText(
when (installStep) {
InstallStep.Pending -> R.string.ext_pending
InstallStep.Downloading -> R.string.ext_downloading
InstallStep.Installing -> R.string.ext_installing
InstallStep.Installed -> R.string.ext_installed
InstallStep.Error -> R.string.action_retry
InstallStep.Idle -> {
when (extension) {
is Extension.Installed -> {
if (extension.hasUpdate) {
R.string.ext_update
} else {
R.string.action_settings
}
}
is Extension.Untrusted -> R.string.ext_trust
is Extension.Available -> R.string.ext_install
}
}
}
} else if (extension is Extension.Untrusted) {
setText(R.string.ext_trust)
} else {
setText(R.string.ext_install)
}
)
val isIdle = installStep == InstallStep.Idle || installStep == InstallStep.Error
binding.cancelButton.isVisible = !isIdle
isEnabled = isIdle
isClickable = isIdle
}
}

View File

@@ -19,7 +19,7 @@ import eu.kanade.tachiyomi.source.CatalogueSource
data class ExtensionItem(
val extension: Extension,
val header: ExtensionGroupItem? = null,
val installStep: InstallStep? = null
val installStep: InstallStep = InstallStep.Idle
) :
AbstractSectionableItem<ExtensionHolder, ExtensionGroupItem>(header) {
@@ -49,7 +49,7 @@ data class ExtensionItem(
if (payloads == null || payloads.isEmpty()) {
holder.bind(this)
} else {
holder.bindButton(this)
holder.bindButtons(this)
}
}

View File

@@ -77,14 +77,14 @@ open class ExtensionPresenter(
if (updatesSorted.isNotEmpty()) {
val header = ExtensionGroupItem(context.getString(R.string.ext_updates_pending), updatesSorted.size, true)
items += updatesSorted.map { extension ->
ExtensionItem(extension, header, currentDownloads[extension.pkgName])
ExtensionItem(extension, header, currentDownloads[extension.pkgName] ?: InstallStep.Idle)
}
}
if (installedSorted.isNotEmpty() || untrustedSorted.isNotEmpty()) {
val header = ExtensionGroupItem(context.getString(R.string.ext_installed), installedSorted.size + untrustedSorted.size)
items += installedSorted.map { extension ->
ExtensionItem(extension, header, currentDownloads[extension.pkgName])
ExtensionItem(extension, header, currentDownloads[extension.pkgName] ?: InstallStep.Idle)
}
items += untrustedSorted.map { extension ->
@@ -100,7 +100,7 @@ open class ExtensionPresenter(
.forEach {
val header = ExtensionGroupItem(it.key, it.value.size)
items += it.value.map { extension ->
ExtensionItem(extension, header, currentDownloads[extension.pkgName])
ExtensionItem(extension, header, currentDownloads[extension.pkgName] ?: InstallStep.Idle)
}
}
}
@@ -133,6 +133,10 @@ open class ExtensionPresenter(
extensionManager.updateExtension(extension).subscribeToInstallUpdate(extension)
}
fun cancelInstallUpdateExtension(extension: Extension) {
extensionManager.cancelInstallUpdateExtension(extension)
}
private fun Observable<InstallStep>.subscribeToInstallUpdate(extension: Extension) {
this.doOnNext { currentDownloads[extension.pkgName] = it }
.doOnUnsubscribe { currentDownloads.remove(extension.pkgName) }

View File

@@ -36,6 +36,8 @@ import eu.kanade.tachiyomi.util.preference.preferenceCategory
import eu.kanade.tachiyomi.util.preference.summaryRes
import eu.kanade.tachiyomi.util.preference.switchPreference
import eu.kanade.tachiyomi.util.preference.titleRes
import eu.kanade.tachiyomi.util.system.MiuiUtil
import eu.kanade.tachiyomi.util.system.isPackageInstalled
import eu.kanade.tachiyomi.util.system.isTablet
import eu.kanade.tachiyomi.util.system.powerManager
import eu.kanade.tachiyomi.util.system.toast
@@ -187,6 +189,45 @@ class SettingsAdvancedController : SettingsController() {
}
}
preferenceCategory {
titleRes = R.string.label_extensions
listPreference {
key = Keys.extensionInstaller
titleRes = R.string.ext_installer_pref
summary = "%s"
entriesRes = arrayOf(
R.string.ext_installer_legacy,
R.string.ext_installer_packageinstaller,
R.string.ext_installer_shizuku
)
entryValues = PreferenceValues.ExtensionInstaller.values().map { it.name }.toTypedArray()
defaultValue = if (MiuiUtil.isMiui()) {
PreferenceValues.ExtensionInstaller.LEGACY
} else {
PreferenceValues.ExtensionInstaller.PACKAGEINSTALLER
}.name
onChange {
if (it == PreferenceValues.ExtensionInstaller.SHIZUKU.name &&
!context.isPackageInstalled("moe.shizuku.privileged.api")
) {
MaterialAlertDialogBuilder(context)
.setTitle(R.string.ext_installer_shizuku)
.setMessage(R.string.ext_installer_shizuku_unavailable_dialog)
.setPositiveButton(android.R.string.ok) { _, _ ->
openInBrowser("https://shizuku.rikka.app/download")
}
.setNegativeButton(android.R.string.cancel, null)
.show()
false
} else {
true
}
}
}
}
preferenceCategory {
titleRes = R.string.pref_category_display