Refactor BasePresenter

This commit is contained in:
Koitharu
2020-10-11 13:16:38 +03:00
parent 5293a8d209
commit 693f568b8e
4 changed files with 82 additions and 138 deletions

View File

@@ -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<V : MvpView> : MvpPresenter<V>(), KoinComponent
abstract class BasePresenter<V : BaseMvpView> : MvpPresenter<V>(), 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)
}
}
}

View File

@@ -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<FavouriteCategoriesView>() {
}
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<Long>) {
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)
}
}
}

View File

@@ -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<FavouriteCategory>)
@@ -14,6 +14,6 @@ interface FavouriteCategoriesView : MvpView {
@StateStrategyType(AddToEndSingleStrategy::class)
fun onCheckedCategoriesChanged(checkedIds: Set<Int>)
@StateStrategyType(OneExecutionStateStrategy::class)
fun onError(e: Throwable)
@AddToEndSingle
override fun onLoadingStateChanged(isLoading: Boolean) = Unit
}

View File

@@ -62,8 +62,8 @@ class LocalListPresenter : BasePresenter<MangaListView<File>>() {
}
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<MangaListView<File>>() {
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)
}
}
}