Option to reverse chapters order
This commit is contained in:
@@ -8,5 +8,5 @@ class CloudFlareProtectedException(
|
||||
val url: String
|
||||
) : IOException("Protected by CloudFlare"), ResolvableException {
|
||||
|
||||
override val resolveTextId: Int = R.string.resolve
|
||||
override val resolveTextId: Int = R.string.captcha_solve
|
||||
}
|
||||
@@ -74,6 +74,8 @@ class AppSettings private constructor(private val prefs: SharedPreferences) :
|
||||
|
||||
var historyGrouping by BoolPreferenceDelegate(KEY_HISTORY_GROUPING, true)
|
||||
|
||||
var chaptersReverse by BoolPreferenceDelegate(KEY_REVERSE_CHAPTERS, false)
|
||||
|
||||
val zoomMode by EnumPreferenceDelegate(
|
||||
ZoomMode::class.java,
|
||||
KEY_ZOOM_MODE,
|
||||
@@ -175,5 +177,6 @@ class AppSettings private constructor(private val prefs: SharedPreferences) :
|
||||
const val KEY_RESTORE = "restore"
|
||||
const val KEY_HISTORY_GROUPING = "history_grouping"
|
||||
const val KEY_DOZE_WHITELIST = "doze_whitelist"
|
||||
const val KEY_REVERSE_CHAPTERS = "reverse_chapters"
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,6 @@ val detailsModule
|
||||
get() = module {
|
||||
|
||||
viewModel { (intent: MangaIntent) ->
|
||||
DetailsViewModel(intent, get(), get(), get(), get(), get())
|
||||
DetailsViewModel(intent, get(), get(), get(), get(), get(), get())
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,11 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||
private var actionMode: ActionMode? = null
|
||||
private var selectionDecoration: ChaptersSelectionDecoration? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onInflateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?
|
||||
@@ -51,6 +56,9 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||
|
||||
viewModel.isLoading.observe(viewLifecycleOwner, this::onLoadingStateChanged)
|
||||
viewModel.chapters.observe(viewLifecycleOwner, this::onChaptersChanged)
|
||||
viewModel.isChaptersReversed.observe(viewLifecycleOwner) {
|
||||
activity?.invalidateOptionsMenu()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
@@ -59,12 +67,22 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun onChaptersChanged(list: List<ChapterListItem>) {
|
||||
chaptersAdapter?.items = list
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater.inflate(R.menu.opt_chapters, menu)
|
||||
}
|
||||
|
||||
private fun onLoadingStateChanged(isLoading: Boolean) {
|
||||
binding.progressBar.isVisible = isLoading
|
||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
menu.findItem(R.id.action_reversed).isChecked = viewModel.isChaptersReversed.value == true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
|
||||
R.id.action_reversed -> {
|
||||
viewModel.setChaptersReversed(!item.isChecked)
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onItemClick(item: MangaChapter, view: View) {
|
||||
@@ -159,4 +177,12 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
|
||||
bottom = insets.bottom
|
||||
)
|
||||
}
|
||||
|
||||
private fun onChaptersChanged(list: List<ChapterListItem>) {
|
||||
chaptersAdapter?.items = list
|
||||
}
|
||||
|
||||
private fun onLoadingStateChanged(isLoading: Boolean) {
|
||||
binding.progressBar.isVisible = isLoading
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import org.koitharu.kotatsu.base.domain.MangaIntent
|
||||
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.core.exceptions.MangaNotFoundException
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.details.ui.model.toListItem
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.history.domain.ChapterExtra
|
||||
@@ -25,7 +26,8 @@ class DetailsViewModel(
|
||||
private val favouritesRepository: FavouritesRepository,
|
||||
private val localMangaRepository: LocalMangaRepository,
|
||||
private val trackingRepository: TrackingRepository,
|
||||
private val mangaDataRepository: MangaDataRepository
|
||||
private val mangaDataRepository: MangaDataRepository,
|
||||
private val settings: AppSettings
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val mangaData = MutableStateFlow<Manga?>(intent.manga)
|
||||
@@ -48,6 +50,12 @@ class DetailsViewModel(
|
||||
trackingRepository.getNewChaptersCount(mangaId)
|
||||
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, 0)
|
||||
|
||||
private val chaptersReversed = settings.observe()
|
||||
.filter { it == AppSettings.KEY_REVERSE_CHAPTERS }
|
||||
.map { settings.chaptersReverse }
|
||||
.onStart { emit(settings.chaptersReverse) }
|
||||
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false)
|
||||
|
||||
val manga = mangaData.filterNotNull()
|
||||
.asLiveData(viewModelScope.coroutineContext)
|
||||
val favouriteCategories = favourite
|
||||
@@ -56,17 +64,20 @@ class DetailsViewModel(
|
||||
.asLiveData(viewModelScope.coroutineContext)
|
||||
val readingHistory = history
|
||||
.asLiveData(viewModelScope.coroutineContext)
|
||||
val isChaptersReversed = chaptersReversed
|
||||
.asLiveData(viewModelScope.coroutineContext)
|
||||
|
||||
val onMangaRemoved = SingleLiveEvent<Manga>()
|
||||
|
||||
val chapters = combine(
|
||||
mangaData.map { it?.chapters.orEmpty() },
|
||||
history.map { it?.chapterId },
|
||||
newChapters
|
||||
) { chapters, currentId, newCount ->
|
||||
newChapters,
|
||||
chaptersReversed
|
||||
) { chapters, currentId, newCount, reversed ->
|
||||
val currentIndex = chapters.indexOfFirst { it.id == currentId }
|
||||
val firstNewIndex = chapters.size - newCount
|
||||
chapters.mapIndexed { index, chapter ->
|
||||
val res = chapters.mapIndexed { index, chapter ->
|
||||
chapter.toListItem(
|
||||
when {
|
||||
index >= firstNewIndex -> ChapterExtra.NEW
|
||||
@@ -76,6 +87,7 @@ class DetailsViewModel(
|
||||
}
|
||||
)
|
||||
}
|
||||
if (reversed) res.asReversed() else res
|
||||
}.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default)
|
||||
|
||||
init {
|
||||
@@ -98,4 +110,8 @@ class DetailsViewModel(
|
||||
onMangaRemoved.postCall(manga)
|
||||
}
|
||||
}
|
||||
|
||||
fun setChaptersReversed(newValue: Boolean) {
|
||||
settings.chaptersReverse = newValue
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.list.ui.model
|
||||
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.ResolvableException
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.prefs.ListMode
|
||||
@@ -46,7 +47,7 @@ fun <C : MutableCollection<ListModel>> List<Manga>.toUi(destination: C, mode: Li
|
||||
|
||||
fun Throwable.toErrorState(canRetry: Boolean = true) = ErrorState(
|
||||
exception = this,
|
||||
icon = R.drawable.ic_error_large,
|
||||
icon = getErrorIcon(this),
|
||||
canRetry = canRetry,
|
||||
buttonText = (this as? ResolvableException)?.resolveTextId ?: R.string.try_again
|
||||
)
|
||||
@@ -54,4 +55,9 @@ fun Throwable.toErrorState(canRetry: Boolean = true) = ErrorState(
|
||||
fun Throwable.toErrorFooter() = ErrorFooter(
|
||||
exception = this,
|
||||
icon = R.drawable.ic_alert_outline
|
||||
)
|
||||
)
|
||||
|
||||
private fun getErrorIcon(error: Throwable) = when (error) {
|
||||
is CloudFlareProtectedException -> R.drawable.ic_denied_large
|
||||
else -> R.drawable.ic_error_large
|
||||
}
|
||||
Reference in New Issue
Block a user