Refactor BasePresenter
This commit is contained in:
@@ -1,7 +1,44 @@
|
|||||||
package org.koitharu.kotatsu.ui.common
|
package org.koitharu.kotatsu.ui.common
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
import moxy.MvpPresenter
|
import moxy.MvpPresenter
|
||||||
import moxy.MvpView
|
import moxy.presenterScope
|
||||||
import org.koin.core.component.KoinComponent
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,8 @@
|
|||||||
package org.koitharu.kotatsu.ui.list.favourites.categories
|
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.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import moxy.InjectViewState
|
import moxy.InjectViewState
|
||||||
import moxy.presenterScope
|
|
||||||
import org.koitharu.kotatsu.BuildConfig
|
|
||||||
import org.koitharu.kotatsu.core.model.Manga
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
|
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
|
||||||
import org.koitharu.kotatsu.ui.common.BasePresenter
|
import org.koitharu.kotatsu.ui.common.BasePresenter
|
||||||
@@ -27,130 +22,59 @@ class FavouriteCategoriesPresenter : BasePresenter<FavouriteCategoriesView>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun loadAllCategories() {
|
fun loadAllCategories() {
|
||||||
presenterScope.launch {
|
launchJob {
|
||||||
try {
|
val categories = repository.getAllCategories()
|
||||||
val categories = withContext(Dispatchers.IO) {
|
viewState.onCategoriesChanged(categories)
|
||||||
repository.getAllCategories()
|
|
||||||
}
|
|
||||||
viewState.onCategoriesChanged(categories)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
viewState.onError(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadMangaCategories(manga: Manga) {
|
fun loadMangaCategories(manga: Manga) {
|
||||||
presenterScope.launch {
|
launchJob {
|
||||||
try {
|
val categories = repository.getCategories(manga.id)
|
||||||
val categories = withContext(Dispatchers.IO) {
|
viewState.onCheckedCategoriesChanged(categories.map { it.id.toInt() }.toSet())
|
||||||
repository.getCategories(manga.id)
|
|
||||||
}
|
|
||||||
viewState.onCheckedCategoriesChanged(categories.map { it.id.toInt() }.toSet())
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
viewState.onError(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createCategory(name: String) {
|
fun createCategory(name: String) {
|
||||||
presenterScope.launch {
|
launchJob {
|
||||||
try {
|
repository.addCategory(name)
|
||||||
val categories = withContext(Dispatchers.IO) {
|
val categories = repository.getAllCategories()
|
||||||
repository.addCategory(name)
|
viewState.onCategoriesChanged(categories)
|
||||||
repository.getAllCategories()
|
|
||||||
}
|
|
||||||
viewState.onCategoriesChanged(categories)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
viewState.onError(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun renameCategory(id: Long, name: String) {
|
fun renameCategory(id: Long, name: String) {
|
||||||
presenterScope.launch {
|
launchJob {
|
||||||
try {
|
repository.renameCategory(id, name)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deleteCategory(id: Long) {
|
fun deleteCategory(id: Long) {
|
||||||
presenterScope.launch {
|
launchJob {
|
||||||
try {
|
repository.removeCategory(id)
|
||||||
val categories = withContext(Dispatchers.IO) {
|
val categories = repository.getAllCategories()
|
||||||
repository.removeCategory(id)
|
viewState.onCategoriesChanged(categories)
|
||||||
repository.getAllCategories()
|
|
||||||
}
|
|
||||||
viewState.onCategoriesChanged(categories)
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
viewState.onError(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun storeCategoriesOrder(orderedIds: List<Long>) {
|
fun storeCategoriesOrder(orderedIds: List<Long>) {
|
||||||
presenterScope.launch {
|
launchJob {
|
||||||
try {
|
reorderMutex.withLock {
|
||||||
reorderMutex.withLock {
|
repository.reorderCategories(orderedIds)
|
||||||
repository.reorderCategories(orderedIds)
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
viewState.onError(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addToCategory(manga: Manga, categoryId: Long) {
|
fun addToCategory(manga: Manga, categoryId: Long) {
|
||||||
presenterScope.launch {
|
launchJob {
|
||||||
try {
|
repository.addToCategory(manga, categoryId)
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
repository.addToCategory(manga,categoryId)
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
viewState.onError(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeFromCategory(manga: Manga, categoryId: Long) {
|
fun removeFromCategory(manga: Manga, categoryId: Long) {
|
||||||
presenterScope.launch {
|
launchJob {
|
||||||
try {
|
repository.removeFromCategory(manga, categoryId)
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
repository.removeFromCategory(manga, categoryId)
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
viewState.onError(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package org.koitharu.kotatsu.ui.list.favourites.categories
|
package org.koitharu.kotatsu.ui.list.favourites.categories
|
||||||
|
|
||||||
import moxy.MvpView
|
|
||||||
import moxy.viewstate.strategy.AddToEndSingleStrategy
|
import moxy.viewstate.strategy.AddToEndSingleStrategy
|
||||||
import moxy.viewstate.strategy.OneExecutionStateStrategy
|
|
||||||
import moxy.viewstate.strategy.StateStrategyType
|
import moxy.viewstate.strategy.StateStrategyType
|
||||||
|
import moxy.viewstate.strategy.alias.AddToEndSingle
|
||||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||||
|
import org.koitharu.kotatsu.ui.common.BaseMvpView
|
||||||
|
|
||||||
interface FavouriteCategoriesView : MvpView {
|
interface FavouriteCategoriesView : BaseMvpView {
|
||||||
|
|
||||||
@StateStrategyType(AddToEndSingleStrategy::class)
|
@StateStrategyType(AddToEndSingleStrategy::class)
|
||||||
fun onCategoriesChanged(categories: List<FavouriteCategory>)
|
fun onCategoriesChanged(categories: List<FavouriteCategory>)
|
||||||
@@ -14,6 +14,6 @@ interface FavouriteCategoriesView : MvpView {
|
|||||||
@StateStrategyType(AddToEndSingleStrategy::class)
|
@StateStrategyType(AddToEndSingleStrategy::class)
|
||||||
fun onCheckedCategoriesChanged(checkedIds: Set<Int>)
|
fun onCheckedCategoriesChanged(checkedIds: Set<Int>)
|
||||||
|
|
||||||
@StateStrategyType(OneExecutionStateStrategy::class)
|
@AddToEndSingle
|
||||||
fun onError(e: Throwable)
|
override fun onLoadingStateChanged(isLoading: Boolean) = Unit
|
||||||
}
|
}
|
||||||
@@ -62,8 +62,8 @@ class LocalListPresenter : BasePresenter<MangaListView<File>>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun importFile(context: Context, uri: Uri) {
|
fun importFile(context: Context, uri: Uri) {
|
||||||
presenterScope.launch(Dispatchers.IO) {
|
launchJob {
|
||||||
try {
|
val list = withContext(Dispatchers.IO) {
|
||||||
val name = MediaStoreCompat.getName(context, uri)
|
val name = MediaStoreCompat.getName(context, uri)
|
||||||
?: throw IOException("Cannot fetch name from uri: $uri")
|
?: throw IOException("Cannot fetch name from uri: $uri")
|
||||||
if (!LocalMangaRepository.isFileSupported(name)) {
|
if (!LocalMangaRepository.isFileSupported(name)) {
|
||||||
@@ -76,42 +76,25 @@ class LocalListPresenter : BasePresenter<MangaListView<File>>() {
|
|||||||
source.copyTo(output)
|
source.copyTo(output)
|
||||||
}
|
}
|
||||||
} ?: throw IOException("Cannot open input stream: $uri")
|
} ?: throw IOException("Cannot open input stream: $uri")
|
||||||
val list = repository.getList(0)
|
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
viewState.onListChanged(list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun delete(manga: Manga) {
|
fun delete(manga: Manga) {
|
||||||
presenterScope.launch {
|
launchJob {
|
||||||
try {
|
withContext(Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
val original = repository.getRemoteManga(manga)
|
||||||
val original = repository.getRemoteManga(manga)
|
repository.delete(manga) || throw IOException("Unable to delete file")
|
||||||
repository.delete(manga) || throw IOException("Unable to delete file")
|
safe {
|
||||||
safe {
|
HistoryRepository().deleteOrSwap(manga, original)
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||||
|
MangaShortcut(manga).removeAppShortcut(get())
|
||||||
|
}
|
||||||
|
viewState.onItemRemoved(manga)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user