diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt index e23a51ceee..7a50c38730 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/extension/ExtensionManager.kt @@ -15,7 +15,9 @@ import eu.kanade.tachiyomi.extension.util.ExtensionLoader import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.util.system.launchNow +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async +import kotlinx.coroutines.withContext import rx.Observable import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -57,12 +59,28 @@ class ExtensionManager( private set(value) { field = value installedExtensionsRelay.call(value) + listener?.extensionsUpdated() } + private var listener: ExtensionsChangedListener? = null + + fun setListener(listener: ExtensionsChangedListener) { + this.listener = listener + } + + fun removeListener(listener: ExtensionsChangedListener) { + if (this.listener == listener) + this.listener = null + } + fun getAppIconForSource(source: Source): Drawable? { val pkgName = installedExtensions.find { ext -> ext.sources.any { it.id == source.id } }?.pkgName - return if (pkgName != null) context.packageManager.getApplicationIcon(pkgName) + return if (pkgName != null) try { + context.packageManager.getApplicationIcon(pkgName) + } catch (e: Exception) { + null + } else null } @@ -79,6 +97,7 @@ class ExtensionManager( field = value availableExtensionsRelay.call(value) updatedInstalledExtensionsStatuses(value) + listener?.extensionsUpdated() } /** @@ -93,6 +112,7 @@ class ExtensionManager( private set(value) { field = value untrustedExtensionsRelay.call(value) + listener?.extensionsUpdated() } /** @@ -162,6 +182,19 @@ class ExtensionManager( } } + /** + * Finds the available extensions in the [api] and updates [availableExtensions]. + */ + suspend fun findAvailableExtensionsAsync() { + withContext(Dispatchers.IO) { + availableExtensions = try { + api.findExtensions() + } catch (e: Exception) { + emptyList() + } + } + } + /** * Sets the update field of the installed extensions with the given [availableExtensions]. * @@ -352,3 +385,7 @@ class ExtensionManager( return this } } + +interface ExtensionsChangedListener { + fun extensionsUpdated() +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueController.kt index 87c2a8b86b..f5982694f6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueController.kt @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.ui.catalogue import android.Manifest.permission.WRITE_EXTERNAL_STORAGE +import android.app.Activity import android.os.Parcelable import android.view.LayoutInflater import android.view.Menu @@ -33,13 +34,13 @@ import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController import eu.kanade.tachiyomi.util.view.scrollViewWith import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog -import kotlin.math.max import kotlinx.android.parcel.Parcelize import kotlinx.android.synthetic.main.catalogue_main_controller.* import kotlinx.android.synthetic.main.extensions_bottom_sheet.* import kotlinx.android.synthetic.main.main_activity.* import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import kotlin.math.max /** * This controller shows and manages the different catalogues enabled by the user. @@ -180,7 +181,6 @@ class CatalogueController : NucleusController(), fun showExtensions() { ext_bottom_sheet.sheetBehavior?.state = BottomSheetBehavior.STATE_EXPANDED - ext_bottom_sheet.fetchOnlineExtensionsIfNeeded() } fun toggleExtensions() { @@ -188,7 +188,6 @@ class CatalogueController : NucleusController(), ext_bottom_sheet.sheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED } else { ext_bottom_sheet.sheetBehavior?.state = BottomSheetBehavior.STATE_EXPANDED - ext_bottom_sheet.fetchOnlineExtensionsIfNeeded() } } @@ -209,10 +208,15 @@ class CatalogueController : NucleusController(), super.onChangeStarted(handler, type) if (!type.isPush && handler is SettingsSourcesFadeChangeHandler) { ext_bottom_sheet.updateExtTitle() - presenter.updateSources() + ext_bottom_sheet.presenter.refreshExtensions() } } + override fun onActivityResumed(activity: Activity) { + super.onActivityResumed(activity) + ext_bottom_sheet.presenter.refreshExtensions() + } + /** * Called when login dialog is closed, refreshes the adapter. * diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionBottomPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionBottomPresenter.kt index 172d8d8d65..11c2e70d6c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionBottomPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionBottomPresenter.kt @@ -5,17 +5,16 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.extension.ExtensionManager +import eu.kanade.tachiyomi.extension.ExtensionsChangedListener import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.extension.model.InstallStep import eu.kanade.tachiyomi.util.system.LocaleHelper -import java.util.concurrent.TimeUnit -import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import rx.Observable -import rx.Subscription -import rx.android.schedulers.AndroidSchedulers import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -25,36 +24,51 @@ typealias ExtensionTuple = /** * Presenter of [ExtensionBottomSheet]. */ -open class ExtensionBottomPresenter( +class ExtensionBottomPresenter( private val bottomSheet: ExtensionBottomSheet, private val extensionManager: ExtensionManager = Injekt.get(), private val preferences: PreferencesHelper = Injekt.get() -) : CoroutineScope { - - override var coroutineContext: CoroutineContext = Job() + Dispatchers.Default +) : ExtensionsChangedListener { + private var scope = CoroutineScope(Job() + Dispatchers.Default) private var extensions = emptyList() private var currentDownloads = hashMapOf() fun onCreate() { - // extensionManager.findAvailableExtensions() - bindToExtensionsObservable() + scope.launch { + extensionManager.findAvailableExtensionsAsync() + extensions = toItems( + Triple( + extensionManager.installedExtensions, + extensionManager.untrustedExtensions, + extensionManager.availableExtensions + ) + ) + withContext(Dispatchers.Main) { bottomSheet.setExtensions(extensions) } + extensionManager.setListener(this@ExtensionBottomPresenter) + } } - private fun bindToExtensionsObservable(): Subscription { - val installedObservable = extensionManager.getInstalledExtensionsObservable() - val untrustedObservable = extensionManager.getUntrustedExtensionsObservable() - val availableObservable = extensionManager.getAvailableExtensionsObservable() - .startWith(emptyList()) + fun onDestroy() { + extensionManager.removeListener(this) + } - return Observable.combineLatest(installedObservable, untrustedObservable, availableObservable) { installed, untrusted, available -> Triple(installed, untrusted, available) } - .debounce(100, TimeUnit.MILLISECONDS) - .map(::toItems) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - bottomSheet.setExtensions(extensions) - } + fun refreshExtensions() { + scope.launch { + extensions = toItems( + Triple( + extensionManager.installedExtensions, + extensionManager.untrustedExtensions, + extensionManager.availableExtensions + ) + ) + withContext(Dispatchers.Main) { bottomSheet.setExtensions(extensions) } + } + } + + override fun extensionsUpdated() { + refreshExtensions() } @Synchronized diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionBottomSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionBottomSheet.kt index f7845d8ce3..3b1afa2e41 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionBottomSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionBottomSheet.kt @@ -33,7 +33,7 @@ ExtensionAdapter.OnButtonClickListener, var sheetBehavior: BottomSheetBehavior<*>? = null private lateinit var autoCheckItem: AutoCheckItem - var shouldCallApi = true + var shouldCallApi = false /** * Adapter containing the list of manga from the catalogue. @@ -54,6 +54,7 @@ ExtensionAdapter.OnButtonClickListener, // Create recycler and set adapter. ext_recycler.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(context) ext_recycler.adapter = adapter + ext_recycler.setHasFixedSize(true) ext_recycler.addItemDecoration(ExtensionDividerItemDecoration(context)) ext_recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener) this.controller = controller @@ -146,7 +147,6 @@ ExtensionAdapter.OnButtonClickListener, } fun setExtensions(extensions: List) { - // ext_swipe_refresh?.isRefreshing = false this.extensions = extensions controller.presenter.updateSources() drawExtensions() diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt index 4ed51ac4b6..e0f534daf6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/view/ViewExtensions.kt @@ -34,11 +34,11 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.getResourceColor +import kotlin.math.abs +import kotlin.math.min import kotlinx.android.synthetic.main.main_activity.* import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import kotlin.math.abs -import kotlin.math.min /** * Returns coordinates of view.