From 693f568b8e8ac5321bcf055fe2e7d81b9794dd8b Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sun, 11 Oct 2020 13:16:38 +0300 Subject: [PATCH] Refactor BasePresenter --- .../kotatsu/ui/common/BasePresenter.kt | 41 +++++- .../FavouriteCategoriesPresenter.kt | 124 ++++-------------- .../categories/FavouriteCategoriesView.kt | 10 +- .../ui/list/local/LocalListPresenter.kt | 45 ++----- 4 files changed, 82 insertions(+), 138 deletions(-) diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/common/BasePresenter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/common/BasePresenter.kt index f41d77eb2..087a6bd70 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/common/BasePresenter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/common/BasePresenter.kt @@ -1,7 +1,44 @@ package org.koitharu.kotatsu.ui.common +import kotlinx.coroutines.* import moxy.MvpPresenter -import moxy.MvpView +import moxy.presenterScope import org.koin.core.component.KoinComponent +import org.koitharu.kotatsu.BuildConfig +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext -abstract class BasePresenter : MvpPresenter(), KoinComponent \ No newline at end of file +abstract class BasePresenter : MvpPresenter(), KoinComponent { + + protected fun launchJob( + context: CoroutineContext = EmptyCoroutineContext, + start: CoroutineStart = CoroutineStart.DEFAULT, + block: suspend CoroutineScope.() -> Unit + ) { + presenterScope.launch(context + createErrorHandler(), start, block) + } + + protected fun launchLoadingJob( + context: CoroutineContext = EmptyCoroutineContext, + start: CoroutineStart = CoroutineStart.DEFAULT, + block: suspend CoroutineScope.() -> Unit + ) { + presenterScope.launch(context + createErrorHandler(), start) { + viewState.onLoadingStateChanged(isLoading = true) + try { + block() + } finally { + viewState.onLoadingStateChanged(isLoading = false) + } + } + } + + private fun createErrorHandler() = CoroutineExceptionHandler { _, throwable -> + if (BuildConfig.DEBUG) { + throwable.printStackTrace() + } + if (throwable !is CancellationException) { + viewState.onError(throwable) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/list/favourites/categories/FavouriteCategoriesPresenter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/list/favourites/categories/FavouriteCategoriesPresenter.kt index 48ae65554..cfc90e07f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/list/favourites/categories/FavouriteCategoriesPresenter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/list/favourites/categories/FavouriteCategoriesPresenter.kt @@ -1,13 +1,8 @@ package org.koitharu.kotatsu.ui.list.favourites.categories -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -import kotlinx.coroutines.withContext import moxy.InjectViewState -import moxy.presenterScope -import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.domain.favourites.FavouritesRepository import org.koitharu.kotatsu.ui.common.BasePresenter @@ -27,130 +22,59 @@ class FavouriteCategoriesPresenter : BasePresenter() { } fun loadAllCategories() { - presenterScope.launch { - try { - val categories = withContext(Dispatchers.IO) { - repository.getAllCategories() - } - viewState.onCategoriesChanged(categories) - } catch (e: Throwable) { - if (BuildConfig.DEBUG) { - e.printStackTrace() - } - viewState.onError(e) - } + launchJob { + val categories = repository.getAllCategories() + viewState.onCategoriesChanged(categories) } } fun loadMangaCategories(manga: Manga) { - presenterScope.launch { - try { - val categories = withContext(Dispatchers.IO) { - repository.getCategories(manga.id) - } - viewState.onCheckedCategoriesChanged(categories.map { it.id.toInt() }.toSet()) - } catch (e: Throwable) { - if (BuildConfig.DEBUG) { - e.printStackTrace() - } - viewState.onError(e) - } + launchJob { + val categories = repository.getCategories(manga.id) + viewState.onCheckedCategoriesChanged(categories.map { it.id.toInt() }.toSet()) } } fun createCategory(name: String) { - presenterScope.launch { - try { - val categories = withContext(Dispatchers.IO) { - repository.addCategory(name) - repository.getAllCategories() - } - viewState.onCategoriesChanged(categories) - } catch (e: Throwable) { - if (BuildConfig.DEBUG) { - e.printStackTrace() - } - viewState.onError(e) - } + launchJob { + repository.addCategory(name) + val categories = repository.getAllCategories() + viewState.onCategoriesChanged(categories) } } fun renameCategory(id: Long, name: String) { - presenterScope.launch { - try { - val categories = withContext(Dispatchers.IO) { - repository.renameCategory(id, name) - repository.getAllCategories() - } - viewState.onCategoriesChanged(categories) - } catch (e: Throwable) { - if (BuildConfig.DEBUG) { - e.printStackTrace() - } - viewState.onError(e) - } + launchJob { + repository.renameCategory(id, name) + } } fun deleteCategory(id: Long) { - presenterScope.launch { - try { - val categories = withContext(Dispatchers.IO) { - repository.removeCategory(id) - repository.getAllCategories() - } - viewState.onCategoriesChanged(categories) - } catch (e: Throwable) { - if (BuildConfig.DEBUG) { - e.printStackTrace() - } - viewState.onError(e) - } + launchJob { + repository.removeCategory(id) + val categories = repository.getAllCategories() + viewState.onCategoriesChanged(categories) } } fun storeCategoriesOrder(orderedIds: List) { - presenterScope.launch { - try { - reorderMutex.withLock { - repository.reorderCategories(orderedIds) - } - } catch (e: Throwable) { - if (BuildConfig.DEBUG) { - e.printStackTrace() - } - viewState.onError(e) + launchJob { + reorderMutex.withLock { + repository.reorderCategories(orderedIds) } } } fun addToCategory(manga: Manga, categoryId: Long) { - presenterScope.launch { - try { - withContext(Dispatchers.IO) { - repository.addToCategory(manga,categoryId) - } - } catch (e: Throwable) { - if (BuildConfig.DEBUG) { - e.printStackTrace() - } - viewState.onError(e) - } + launchJob { + repository.addToCategory(manga, categoryId) } } fun removeFromCategory(manga: Manga, categoryId: Long) { - presenterScope.launch { - try { - withContext(Dispatchers.IO) { - repository.removeFromCategory(manga, categoryId) - } - } catch (e: Throwable) { - if (BuildConfig.DEBUG) { - e.printStackTrace() - } - viewState.onError(e) - } + launchJob { + repository.removeFromCategory(manga, categoryId) } } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/list/favourites/categories/FavouriteCategoriesView.kt b/app/src/main/java/org/koitharu/kotatsu/ui/list/favourites/categories/FavouriteCategoriesView.kt index 484d3d54b..4c0d80a63 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/list/favourites/categories/FavouriteCategoriesView.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/list/favourites/categories/FavouriteCategoriesView.kt @@ -1,12 +1,12 @@ package org.koitharu.kotatsu.ui.list.favourites.categories -import moxy.MvpView import moxy.viewstate.strategy.AddToEndSingleStrategy -import moxy.viewstate.strategy.OneExecutionStateStrategy import moxy.viewstate.strategy.StateStrategyType +import moxy.viewstate.strategy.alias.AddToEndSingle import org.koitharu.kotatsu.core.model.FavouriteCategory +import org.koitharu.kotatsu.ui.common.BaseMvpView -interface FavouriteCategoriesView : MvpView { +interface FavouriteCategoriesView : BaseMvpView { @StateStrategyType(AddToEndSingleStrategy::class) fun onCategoriesChanged(categories: List) @@ -14,6 +14,6 @@ interface FavouriteCategoriesView : MvpView { @StateStrategyType(AddToEndSingleStrategy::class) fun onCheckedCategoriesChanged(checkedIds: Set) - @StateStrategyType(OneExecutionStateStrategy::class) - fun onError(e: Throwable) + @AddToEndSingle + override fun onLoadingStateChanged(isLoading: Boolean) = Unit } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/list/local/LocalListPresenter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/list/local/LocalListPresenter.kt index 3c99e52c6..2f14836af 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/list/local/LocalListPresenter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/list/local/LocalListPresenter.kt @@ -62,8 +62,8 @@ class LocalListPresenter : BasePresenter>() { } fun importFile(context: Context, uri: Uri) { - presenterScope.launch(Dispatchers.IO) { - try { + launchJob { + val list = withContext(Dispatchers.IO) { val name = MediaStoreCompat.getName(context, uri) ?: throw IOException("Cannot fetch name from uri: $uri") if (!LocalMangaRepository.isFileSupported(name)) { @@ -76,42 +76,25 @@ class LocalListPresenter : BasePresenter>() { source.copyTo(output) } } ?: throw IOException("Cannot open input stream: $uri") - val list = repository.getList(0) - withContext(Dispatchers.Main) { - viewState.onListChanged(list) - } - } catch (e: CancellationException) { - } catch (e: Throwable) { - if (BuildConfig.DEBUG) { - e.printStackTrace() - } - withContext(Dispatchers.Main) { - viewState.onError(e) - } + repository.getList(0) } + viewState.onListChanged(list) } } fun delete(manga: Manga) { - presenterScope.launch { - try { - withContext(Dispatchers.IO) { - val original = repository.getRemoteManga(manga) - repository.delete(manga) || throw IOException("Unable to delete file") - safe { - HistoryRepository().deleteOrSwap(manga, original) - } - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { - MangaShortcut(manga).removeAppShortcut(get()) - } - viewState.onItemRemoved(manga) - } catch (e: CancellationException) { - } catch (e: Throwable) { - if (BuildConfig.DEBUG) { - e.printStackTrace() + launchJob { + withContext(Dispatchers.IO) { + val original = repository.getRemoteManga(manga) + repository.delete(manga) || throw IOException("Unable to delete file") + safe { + HistoryRepository().deleteOrSwap(manga, original) } } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { + MangaShortcut(manga).removeAppShortcut(get()) + } + viewState.onItemRemoved(manga) } } } \ No newline at end of file