From cbba4a850c100a5a9099ef5095bd718abee0d89e Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 9 Mar 2020 11:20:15 +0200 Subject: [PATCH] Add Resume reading fab --- .../core/exceptions/EmptyHistoryException.kt | 3 ++ .../domain/history/HistoryRepository.kt | 4 +- .../koitharu/kotatsu/ui/main/MainActivity.kt | 46 ++++++++++++++++++- .../koitharu/kotatsu/ui/main/MainPresenter.kt | 41 +++++++++++++++++ .../org/koitharu/kotatsu/ui/main/MainView.kt | 12 +++++ .../main/list/history/HistoryListFragment.kt | 5 ++ .../koitharu/kotatsu/utils/ext/CommonExt.kt | 2 + app/src/main/res/drawable/ic_read_fill.xml | 12 +++++ app/src/main/res/layout/activity_main.xml | 14 ++++++ app/src/main/res/layout/fragment_list.xml | 5 +- 10 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/org/koitharu/kotatsu/core/exceptions/EmptyHistoryException.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/ui/main/MainPresenter.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/ui/main/MainView.kt create mode 100644 app/src/main/res/drawable/ic_read_fill.xml diff --git a/app/src/main/java/org/koitharu/kotatsu/core/exceptions/EmptyHistoryException.kt b/app/src/main/java/org/koitharu/kotatsu/core/exceptions/EmptyHistoryException.kt new file mode 100644 index 000000000..e16b2bf17 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/exceptions/EmptyHistoryException.kt @@ -0,0 +1,3 @@ +package org.koitharu.kotatsu.core.exceptions + +class EmptyHistoryException : RuntimeException() \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/domain/history/HistoryRepository.kt b/app/src/main/java/org/koitharu/kotatsu/domain/history/HistoryRepository.kt index 7573b821f..6bd1a280b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/domain/history/HistoryRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/domain/history/HistoryRepository.kt @@ -16,8 +16,8 @@ class HistoryRepository : KoinComponent { private val db: MangaDatabase by inject() - suspend fun getList(offset: Int): List { - val entities = db.historyDao().findAll(offset, 20) + suspend fun getList(offset: Int, limit: Int = 20): List { + val entities = db.historyDao().findAll(offset, limit) return entities.map { it.manga.toManga(it.tags.map(TagEntity::toMangaTag).toSet()) } } diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/MainActivity.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/MainActivity.kt index 5cc2595a9..5be3bd96a 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/MainActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/MainActivity.kt @@ -1,14 +1,20 @@ package org.koitharu.kotatsu.ui.main import android.content.SharedPreferences +import android.content.res.ColorStateList import android.content.res.Configuration +import android.graphics.Color import android.os.Bundle import android.view.Menu import android.view.MenuItem import androidx.appcompat.app.ActionBarDrawerToggle +import androidx.core.view.isVisible import androidx.fragment.app.Fragment +import androidx.swiperefreshlayout.widget.CircularProgressDrawable import com.google.android.material.navigation.NavigationView +import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.activity_main.* +import moxy.ktx.moxyPresenter import org.koin.core.inject import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.model.MangaSource @@ -19,10 +25,16 @@ import org.koitharu.kotatsu.ui.main.list.favourites.FavouritesListFragment import org.koitharu.kotatsu.ui.main.list.history.HistoryListFragment import org.koitharu.kotatsu.ui.main.list.local.LocalListFragment import org.koitharu.kotatsu.ui.main.list.remote.RemoteListFragment +import org.koitharu.kotatsu.ui.reader.ReaderActivity +import org.koitharu.kotatsu.ui.reader.ReaderState import org.koitharu.kotatsu.ui.settings.SettingsActivity +import org.koitharu.kotatsu.utils.ext.getDisplayMessage +import org.koitharu.kotatsu.utils.ext.resolveDp class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener, - SharedPreferences.OnSharedPreferenceChangeListener { + SharedPreferences.OnSharedPreferenceChangeListener, MainView { + + private val presenter by moxyPresenter(factory = ::MainPresenter) private val settings by inject() private lateinit var drawerToggle: ActionBarDrawerToggle @@ -40,7 +52,15 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList navigationView.setNavigationItemSelectedListener(this) settings.subscribe(this) - if (supportFragmentManager.findFragmentById(R.id.container) == null) { + fab.imageTintList = ColorStateList.valueOf(Color.WHITE) + fab.isVisible = true + fab.setOnClickListener { + presenter.openLastReader() + } + + supportFragmentManager.findFragmentById(R.id.container)?.let { + fab.isVisible = it is HistoryListFragment + } ?: run { navigationView.setCheckedItem(R.id.nav_history) setPrimaryFragment(HistoryListFragment.newInstance()) } @@ -91,6 +111,27 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList return true } + override fun onOpenReader(state: ReaderState) { + startActivity(ReaderActivity.newIntent(this, state)) + } + + override fun onError(e: Throwable) { + Snackbar.make(container, e.getDisplayMessage(resources), Snackbar.LENGTH_SHORT).show() + } + + override fun onLoadingStateChanged(isLoading: Boolean) { + fab.isEnabled = !isLoading + if (isLoading) { + fab.setImageDrawable(CircularProgressDrawable(this).also { + it.setColorSchemeColors(Color.WHITE) + it.strokeWidth = resources.resolveDp(2f) + it.start() + }) + } else { + fab.setImageResource(R.drawable.ic_read_fill) + } + } + private fun initSideMenu(remoteSources: List) { val submenu = navigationView.menu.findItem(R.id.nav_remote_sources).subMenu submenu.removeGroup(R.id.group_remote_sources) @@ -110,5 +151,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList supportFragmentManager.beginTransaction() .replace(R.id.container, fragment) .commit() + fab.isVisible = fragment is HistoryListFragment } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/MainPresenter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/MainPresenter.kt new file mode 100644 index 000000000..954736685 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/MainPresenter.kt @@ -0,0 +1,41 @@ +package org.koitharu.kotatsu.ui.main + +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import moxy.InjectViewState +import moxy.presenterScope +import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException +import org.koitharu.kotatsu.domain.MangaProviderFactory +import org.koitharu.kotatsu.domain.history.HistoryRepository +import org.koitharu.kotatsu.ui.common.BasePresenter +import org.koitharu.kotatsu.ui.reader.ReaderState + +@InjectViewState +class MainPresenter : BasePresenter() { + + fun openLastReader() { + presenterScope.launch { + viewState.onLoadingStateChanged(isLoading = true) + try { + val state = withContext(Dispatchers.IO) { + val repo = HistoryRepository() + val manga = repo.getList(0, 1).firstOrNull() + ?: throw EmptyHistoryException() + val history = repo.getOne(manga) ?: throw EmptyHistoryException() + ReaderState( + MangaProviderFactory.create(manga.source).getDetails(manga), + history.chapterId, history.page + ) + } + viewState.onOpenReader(state) + } catch (_: CancellationException) { + } catch (e: Throwable) { + viewState.onError(e) + } finally { + viewState.onLoadingStateChanged(isLoading = false) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/MainView.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/MainView.kt new file mode 100644 index 000000000..8d39aeb5e --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/MainView.kt @@ -0,0 +1,12 @@ +package org.koitharu.kotatsu.ui.main + +import moxy.viewstate.strategy.alias.OneExecution +import org.koitharu.kotatsu.core.model.MangaState +import org.koitharu.kotatsu.ui.common.BaseMvpView +import org.koitharu.kotatsu.ui.reader.ReaderState + +interface MainView : BaseMvpView { + + @OneExecution + fun onOpenReader(state: ReaderState) +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/history/HistoryListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/history/HistoryListFragment.kt index 3849565bf..4f8ca3e96 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/history/HistoryListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/history/HistoryListFragment.kt @@ -1,9 +1,14 @@ package org.koitharu.kotatsu.ui.main.list.history +import android.content.res.ColorStateList +import android.graphics.Color +import android.os.Bundle import android.view.Menu import android.view.MenuInflater import android.view.MenuItem +import android.view.View import androidx.appcompat.app.AlertDialog +import androidx.core.view.isVisible import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.fragment_list.* import moxy.ktx.moxyPresenter diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt index e325b972d..5e939bd0a 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt @@ -4,6 +4,7 @@ import android.content.res.Resources import kotlinx.coroutines.delay import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException import java.io.IOException @@ -35,6 +36,7 @@ suspend inline fun T.retryUntilSuccess(maxAttempts: Int, action: T.() -> fun Throwable.getDisplayMessage(resources: Resources) = when (this) { is UnsupportedOperationException -> resources.getString(R.string.operation_not_supported) is UnsupportedFileException -> resources.getString(R.string.text_file_not_supported) + is EmptyHistoryException -> resources.getString(R.string.history_is_empty) is IOException -> resources.getString(R.string.network_error) else -> if (BuildConfig.DEBUG) { message ?: resources.getString(R.string.error_occurred) diff --git a/app/src/main/res/drawable/ic_read_fill.xml b/app/src/main/res/drawable/ic_read_fill.xml new file mode 100644 index 000000000..f0a3f2efb --- /dev/null +++ b/app/src/main/res/drawable/ic_read_fill.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index f1f68935e..72cab7463 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -34,6 +34,20 @@ android:layout_height="match_parent" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" /> + + + android:layout_height="match_parent">