mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-09 20:15:05 +01:00
Clean up of library presenter
Using progress bar again for when a category is updating and ripple for sort button Fixed #165
This commit is contained in:
parent
55b7b8ca2a
commit
2dd8c8810a
@ -177,17 +177,17 @@ class LibraryController(
|
|||||||
}
|
}
|
||||||
RecyclerView.SCROLL_STATE_IDLE -> {
|
RecyclerView.SCROLL_STATE_IDLE -> {
|
||||||
scrollAnim = fast_scroller.animate().setStartDelay(1000).setDuration(250)
|
scrollAnim = fast_scroller.animate().setStartDelay(1000).setDuration(250)
|
||||||
.translationX(22f.dpToPx)
|
.translationX(25f.dpToPx)
|
||||||
scrollAnim?.start()
|
scrollAnim?.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hideScroller() {
|
private fun hideScroller(duration: Long = 1000) {
|
||||||
if (alwaysShowScroller) return
|
if (alwaysShowScroller) return
|
||||||
scrollAnim =
|
scrollAnim =
|
||||||
fast_scroller.animate().setStartDelay(1000).setDuration(250).translationX(22f.dpToPx)
|
fast_scroller.animate().setStartDelay(duration).setDuration(250).translationX(25f.dpToPx)
|
||||||
scrollAnim?.start()
|
scrollAnim?.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,10 +207,12 @@ class LibraryController(
|
|||||||
super.onViewCreated(view)
|
super.onViewCreated(view)
|
||||||
view.applyWindowInsetsForRootController(activity!!.bottom_nav)
|
view.applyWindowInsetsForRootController(activity!!.bottom_nav)
|
||||||
if (!::presenter.isInitialized) presenter = LibraryPresenter(this)
|
if (!::presenter.isInitialized) presenter = LibraryPresenter(this)
|
||||||
fast_scroller.translationX = 22f.dpToPx
|
fast_scroller.translationX = 25f.dpToPx
|
||||||
setFastScrollBackground()
|
setFastScrollBackground()
|
||||||
|
|
||||||
adapter = LibraryCategoryAdapter(this)
|
adapter = LibraryCategoryAdapter(this)
|
||||||
|
adapter.expandItemsAtStartUp()
|
||||||
|
adapter.isRecursiveCollapse = true
|
||||||
setRecyclerLayout()
|
setRecyclerLayout()
|
||||||
recycler.manager.spanSizeLookup = (object : GridLayoutManager.SpanSizeLookup() {
|
recycler.manager.spanSizeLookup = (object : GridLayoutManager.SpanSizeLookup() {
|
||||||
override fun getSpanSize(position: Int): Int {
|
override fun getSpanSize(position: Int): Int {
|
||||||
@ -238,13 +240,11 @@ class LibraryController(
|
|||||||
itemPosition: Int
|
itemPosition: Int
|
||||||
) {
|
) {
|
||||||
fast_scroller.translationX = 0f
|
fast_scroller.translationX = 0f
|
||||||
hideScroller()
|
hideScroller(2000)
|
||||||
|
|
||||||
textAnim?.cancel()
|
textAnim?.cancel()
|
||||||
textAnim = text_view_m.animate().alpha(0f).setDuration(250L).setStartDelay(1000)
|
textAnim = text_view_m.animate().alpha(0f).setDuration(250L).setStartDelay(2000)
|
||||||
this@LibraryController.view?.post {
|
textAnim?.start()
|
||||||
textAnim?.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
text_view_m.translationY = indicatorCenterY.toFloat() - text_view_m.height / 2
|
text_view_m.translationY = indicatorCenterY.toFloat() - text_view_m.height / 2
|
||||||
text_view_m.alpha = 1f
|
text_view_m.alpha = 1f
|
||||||
@ -324,9 +324,9 @@ class LibraryController(
|
|||||||
recycler.updatePaddingRelative(bottom = height)
|
recycler.updatePaddingRelative(bottom = height)
|
||||||
|
|
||||||
presenter.onRestore()
|
presenter.onRestore()
|
||||||
val library = presenter.getAllManga()
|
if (presenter.libraryItems.isNotEmpty())
|
||||||
if (library != null) presenter.updateViewBlocking()
|
onNextLibraryUpdate(presenter.libraryItems, true)
|
||||||
else {
|
else {
|
||||||
recycler_layout.alpha = 0f
|
recycler_layout.alpha = 0f
|
||||||
presenter.getLibraryBlocking()
|
presenter.getLibraryBlocking()
|
||||||
}
|
}
|
||||||
@ -429,7 +429,7 @@ class LibraryController(
|
|||||||
super.onDestroyView(view)
|
super.onDestroyView(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onNextLibraryUpdate(mangaMap: List<LibraryItem>, freshStart: Boolean) {
|
fun onNextLibraryUpdate(mangaMap: List<LibraryItem>, freshStart: Boolean = false) {
|
||||||
if (view == null) return
|
if (view == null) return
|
||||||
destroyActionModeIfNeeded()
|
destroyActionModeIfNeeded()
|
||||||
if (mangaMap.isNotEmpty()) {
|
if (mangaMap.isNotEmpty()) {
|
||||||
@ -442,6 +442,7 @@ class LibraryController(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
adapter.setItems(mangaMap)
|
adapter.setItems(mangaMap)
|
||||||
|
adapter.collapse(0)
|
||||||
singleCategory = presenter.categories.size <= 1
|
singleCategory = presenter.categories.size <= 1
|
||||||
|
|
||||||
setTitle()
|
setTitle()
|
||||||
@ -452,7 +453,9 @@ class LibraryController(
|
|||||||
} else if (justStarted && freshStart) {
|
} else if (justStarted && freshStart) {
|
||||||
scrollToHeader(activeCategory)
|
scrollToHeader(activeCategory)
|
||||||
fast_scroller.translationX = 0f
|
fast_scroller.translationX = 0f
|
||||||
hideScroller()
|
view?.post {
|
||||||
|
hideScroller(2000)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
adapter.isLongPressDragEnabled = canDrag()
|
adapter.isLongPressDragEnabled = canDrag()
|
||||||
}
|
}
|
||||||
@ -914,7 +917,7 @@ class LibraryController(
|
|||||||
anchorView = bottom_sheet
|
anchorView = bottom_sheet
|
||||||
var undoing = false
|
var undoing = false
|
||||||
setAction(R.string.undo) {
|
setAction(R.string.undo) {
|
||||||
presenter.addMangas(mangas)
|
presenter.reAddMangas(mangas)
|
||||||
undoing = true
|
undoing = true
|
||||||
}
|
}
|
||||||
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||||
|
@ -4,6 +4,7 @@ import android.graphics.drawable.Drawable
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import android.widget.ProgressBar
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.appcompat.view.menu.MenuBuilder
|
import androidx.appcompat.view.menu.MenuBuilder
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
@ -23,6 +24,7 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault
|
|||||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||||
import eu.kanade.tachiyomi.util.view.gone
|
import eu.kanade.tachiyomi.util.view.gone
|
||||||
|
import eu.kanade.tachiyomi.util.view.invisible
|
||||||
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
import eu.kanade.tachiyomi.util.view.updateLayoutParams
|
||||||
import eu.kanade.tachiyomi.util.view.visible
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
import kotlinx.android.synthetic.main.library_category_header_item.view.*
|
import kotlinx.android.synthetic.main.library_category_header_item.view.*
|
||||||
@ -84,6 +86,7 @@ class LibraryHeaderItem(
|
|||||||
private val sortText: TextView = view.findViewById(R.id.category_sort)
|
private val sortText: TextView = view.findViewById(R.id.category_sort)
|
||||||
private val updateButton: ImageView = view.findViewById(R.id.update_button)
|
private val updateButton: ImageView = view.findViewById(R.id.update_button)
|
||||||
private val checkboxImage: ImageView = view.findViewById(R.id.checkbox)
|
private val checkboxImage: ImageView = view.findViewById(R.id.checkbox)
|
||||||
|
private val catProgress: ProgressBar = view.findViewById(R.id.cat_progress)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
sortText.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
sortText.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||||
@ -122,6 +125,7 @@ class LibraryHeaderItem(
|
|||||||
adapter.mode == SelectableAdapter.Mode.MULTI -> {
|
adapter.mode == SelectableAdapter.Mode.MULTI -> {
|
||||||
checkboxImage.visible()
|
checkboxImage.visible()
|
||||||
updateButton.gone()
|
updateButton.gone()
|
||||||
|
catProgress.gone()
|
||||||
setSelection()
|
setSelection()
|
||||||
}
|
}
|
||||||
category.id == -1 -> {
|
category.id == -1 -> {
|
||||||
@ -130,14 +134,12 @@ class LibraryHeaderItem(
|
|||||||
}
|
}
|
||||||
LibraryUpdateService.categoryInQueue(category.id) -> {
|
LibraryUpdateService.categoryInQueue(category.id) -> {
|
||||||
checkboxImage.gone()
|
checkboxImage.gone()
|
||||||
updateButton.drawable.setTint(ContextCompat.getColor(itemView.context,
|
catProgress.visible()
|
||||||
R.color.material_on_surface_disabled))
|
updateButton.invisible()
|
||||||
updateButton.visible()
|
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
catProgress.gone()
|
||||||
checkboxImage.gone()
|
checkboxImage.gone()
|
||||||
updateButton.drawable.setTint(itemView.context.getResourceColor(
|
|
||||||
R.attr.colorAccent))
|
|
||||||
updateButton.visible()
|
updateButton.visible()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,8 +147,8 @@ class LibraryHeaderItem(
|
|||||||
|
|
||||||
private fun addCategoryToUpdate() {
|
private fun addCategoryToUpdate() {
|
||||||
if (adapter.libraryListener.updateCategory(adapterPosition)) {
|
if (adapter.libraryListener.updateCategory(adapterPosition)) {
|
||||||
updateButton.drawable.setTint(ContextCompat.getColor(itemView.context,
|
catProgress.visible()
|
||||||
R.color.material_on_surface_disabled))
|
updateButton.invisible()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun showCatSortOptions() {
|
private fun showCatSortOptions() {
|
||||||
|
@ -13,14 +13,10 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.source.Source
|
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.ui.library.filter.FilterBottomSheet
|
import eu.kanade.tachiyomi.ui.library.filter.FilterBottomSheet
|
||||||
import eu.kanade.tachiyomi.ui.migration.MigrationFlags
|
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
|
||||||
import eu.kanade.tachiyomi.util.lang.removeArticles
|
import eu.kanade.tachiyomi.util.lang.removeArticles
|
||||||
import eu.kanade.tachiyomi.util.system.launchUI
|
import eu.kanade.tachiyomi.util.system.launchUI
|
||||||
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_EXCLUDE
|
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_EXCLUDE
|
||||||
@ -32,25 +28,12 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import rx.Observable
|
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
|
||||||
import rx.schedulers.Schedulers
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import java.util.Comparator
|
import java.util.Comparator
|
||||||
|
|
||||||
/**
|
|
||||||
* Class containing library information.
|
|
||||||
*/
|
|
||||||
private data class Library(val categories: List<Category>, val mangaMap: LibraryMap)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Typealias for the library manga, using the category as keys, and list of manga as values.
|
|
||||||
*/
|
|
||||||
private typealias LibraryMap = Map<Int, List<LibraryItem>>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Presenter of [LibraryController].
|
* Presenter of [LibraryController].
|
||||||
*/
|
*/
|
||||||
@ -66,6 +49,7 @@ class LibraryPresenter(
|
|||||||
private val context = preferences.context
|
private val context = preferences.context
|
||||||
|
|
||||||
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLogged } }
|
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLogged } }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Categories of the library.
|
* Categories of the library.
|
||||||
*/
|
*/
|
||||||
@ -74,26 +58,28 @@ class LibraryPresenter(
|
|||||||
|
|
||||||
var allCategories: List<Category> = emptyList()
|
var allCategories: List<Category> = emptyList()
|
||||||
private set
|
private set
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of all manga to update the
|
* List of all manga to update the
|
||||||
*/
|
*/
|
||||||
private var rawMangaMap: LibraryMap? = null
|
// private var rawMangaMap: LibraryMap? = null
|
||||||
|
var libraryItems: List<LibraryItem> = emptyList()
|
||||||
|
private var allLibraryItems: List<LibraryItem> = emptyList()
|
||||||
|
|
||||||
private var currentMangaMap: LibraryMap? = null
|
// private var currentMangaMap: LibraryMap? = null
|
||||||
|
|
||||||
private var totalChapters: Map<Long, Int>? = null
|
private var totalChapters: Map<Long, Int>? = null
|
||||||
|
|
||||||
fun isDownloading() = downloadManager.hasQueue()
|
|
||||||
|
|
||||||
fun onDestroy() {
|
fun onDestroy() {
|
||||||
if (currentMangaMap != null)
|
lastLibraryItems = libraryItems
|
||||||
currentLibrary = Library(categories, currentMangaMap!!)
|
lastCategories = categories
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onRestore() {
|
fun onRestore() {
|
||||||
categories = currentLibrary?.categories ?: return
|
libraryItems = lastLibraryItems ?: return
|
||||||
currentMangaMap = currentLibrary?.mangaMap
|
categories = lastCategories ?: return
|
||||||
currentLibrary = null
|
lastCategories = null
|
||||||
|
lastLibraryItems = null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLibrary() {
|
fun getLibrary() {
|
||||||
@ -101,15 +87,15 @@ class LibraryPresenter(
|
|||||||
totalChapters = null
|
totalChapters = null
|
||||||
val mangaMap = withContext(Dispatchers.IO) {
|
val mangaMap = withContext(Dispatchers.IO) {
|
||||||
val library = getLibraryFromDB()
|
val library = getLibraryFromDB()
|
||||||
library.apply { setDownloadCount(library.mangaMap) }
|
library.apply { setDownloadCount(library) }
|
||||||
rawMangaMap = library.mangaMap
|
allLibraryItems = library
|
||||||
var mangaMap = library.mangaMap
|
var mangaMap = library
|
||||||
mangaMap = applyFilters(mangaMap)
|
mangaMap = applyFilters(mangaMap)
|
||||||
mangaMap = applySort(mangaMap)
|
mangaMap = applySort(mangaMap)
|
||||||
mangaMap
|
mangaMap
|
||||||
}
|
}
|
||||||
currentMangaMap = mangaMap
|
libraryItems = mangaMap
|
||||||
updateView(categories, mangaMap)
|
view.onNextLibraryUpdate(libraryItems)
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
setTotalChapters()
|
setTotalChapters()
|
||||||
}
|
}
|
||||||
@ -119,34 +105,25 @@ class LibraryPresenter(
|
|||||||
fun getLibraryBlocking() {
|
fun getLibraryBlocking() {
|
||||||
val mangaMap = {
|
val mangaMap = {
|
||||||
val library = getLibraryFromDB()
|
val library = getLibraryFromDB()
|
||||||
library.apply { setDownloadCount(library.mangaMap) }
|
library.apply { setDownloadCount(library) }
|
||||||
rawMangaMap = library.mangaMap
|
allLibraryItems = library
|
||||||
var mangaMap = library.mangaMap
|
var mangaMap = library
|
||||||
mangaMap = applyFilters(mangaMap)
|
mangaMap = applyFilters(mangaMap)
|
||||||
mangaMap = applySort(mangaMap)
|
mangaMap = applySort(mangaMap)
|
||||||
mangaMap
|
mangaMap
|
||||||
}()
|
}()
|
||||||
currentMangaMap = mangaMap
|
libraryItems = mangaMap
|
||||||
launchUI {
|
launchUI {
|
||||||
updateView(categories, mangaMap, true)
|
view.onNextLibraryUpdate(libraryItems)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAllManga(): LibraryMap? {
|
|
||||||
return currentMangaMap
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getMangaInCategory(catId: Int?): List<LibraryItem>? {
|
|
||||||
val categoryId = catId ?: return null
|
|
||||||
return currentMangaMap?.get(categoryId)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies library filters to the given map of manga.
|
* Applies library filters to the given map of manga.
|
||||||
*
|
*
|
||||||
* @param map the map to filter.
|
* @param map the map to filter.
|
||||||
*/
|
*/
|
||||||
private fun applyFilters(map: LibraryMap): LibraryMap {
|
private fun applyFilters(map: List<LibraryItem>): List<LibraryItem> {
|
||||||
val filterDownloaded = preferences.filterDownloaded().getOrDefault()
|
val filterDownloaded = preferences.filterDownloaded().getOrDefault()
|
||||||
|
|
||||||
val filterUnread = preferences.filterUnread().getOrDefault()
|
val filterUnread = preferences.filterUnread().getOrDefault()
|
||||||
@ -159,36 +136,29 @@ class LibraryPresenter(
|
|||||||
|
|
||||||
val filterTrackers = FilterBottomSheet.FILTER_TRACKER
|
val filterTrackers = FilterBottomSheet.FILTER_TRACKER
|
||||||
|
|
||||||
val filterFn: (LibraryItem) -> Boolean = f@{ item ->
|
return map.filter f@{ item ->
|
||||||
if (item.manga.isBlank()) {
|
if (item.manga.isBlank()) {
|
||||||
return@f filterDownloaded == 0 &&
|
return@f filterDownloaded == 0 && filterUnread == 0 && filterCompleted == 0 &&
|
||||||
filterUnread == 0 &&
|
filterTracked == 0 && filterMangaType == 0
|
||||||
filterCompleted == 0 &&
|
|
||||||
filterTracked == 0 &&
|
|
||||||
filterMangaType == 0
|
|
||||||
}
|
}
|
||||||
// Filter for unread chapters
|
// Filter for unread chapters
|
||||||
if (filterUnread == STATE_INCLUDE &&
|
if (filterUnread == STATE_INCLUDE && (item.manga.unread == 0 || db.getChapters(item.manga)
|
||||||
(item.manga.unread == 0 || db.getChapters(item.manga).executeAsBlocking()
|
.executeAsBlocking().size != item.manga.unread)
|
||||||
.size != item.manga.unread)) return@f false
|
) return@f false
|
||||||
if (filterUnread == STATE_EXCLUDE &&
|
if (filterUnread == STATE_EXCLUDE && (item.manga.unread == 0 || db.getChapters(item.manga)
|
||||||
(item.manga.unread == 0 ||
|
.executeAsBlocking().size == item.manga.unread)
|
||||||
db.getChapters(item.manga).executeAsBlocking().size == item.manga.unread))
|
) return@f false
|
||||||
return@f false
|
|
||||||
if (filterUnread == STATE_REALLY_EXCLUDE && item.manga.unread > 0) return@f false
|
if (filterUnread == STATE_REALLY_EXCLUDE && item.manga.unread > 0) return@f false
|
||||||
|
|
||||||
if (filterMangaType > 0) {
|
if (filterMangaType > 0) {
|
||||||
if (if (filterMangaType == Manga.TYPE_MANHWA)
|
if (if (filterMangaType == Manga.TYPE_MANHWA) (filterMangaType != item.manga.mangaType() && filterMangaType != Manga.TYPE_WEBTOON)
|
||||||
(filterMangaType != item.manga.mangaType() &&
|
else filterMangaType != item.manga.mangaType()
|
||||||
filterMangaType != Manga.TYPE_WEBTOON)
|
) return@f false
|
||||||
else filterMangaType != item.manga.mangaType()) return@f false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter for completed status of manga
|
// Filter for completed status of manga
|
||||||
if (filterCompleted == STATE_INCLUDE && item.manga.status != SManga.COMPLETED)
|
if (filterCompleted == STATE_INCLUDE && item.manga.status != SManga.COMPLETED) return@f false
|
||||||
return@f false
|
if (filterCompleted == STATE_EXCLUDE && item.manga.status == SManga.COMPLETED) return@f false
|
||||||
if (filterCompleted == STATE_EXCLUDE && item.manga.status == SManga.COMPLETED)
|
|
||||||
return@f false
|
|
||||||
|
|
||||||
// Filter for tracked (or per tracked service)
|
// Filter for tracked (or per tracked service)
|
||||||
if (filterTracked != STATE_IGNORE) {
|
if (filterTracked != STATE_IGNORE) {
|
||||||
@ -230,8 +200,6 @@ class LibraryPresenter(
|
|||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
return map.mapValues { entry -> entry.value.filter(filterFn) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -239,72 +207,33 @@ class LibraryPresenter(
|
|||||||
*
|
*
|
||||||
* @param map the map of manga.
|
* @param map the map of manga.
|
||||||
*/
|
*/
|
||||||
private fun setDownloadCount(map: LibraryMap) {
|
private fun setDownloadCount(itemList: List<LibraryItem>) {
|
||||||
if (!preferences.downloadBadge().getOrDefault()) {
|
if (!preferences.downloadBadge().getOrDefault()) {
|
||||||
// Unset download count if the preference is not enabled.
|
// Unset download count if the preference is not enabled.
|
||||||
for ((_, itemList) in map) {
|
for (item in itemList) {
|
||||||
for (item in itemList) {
|
item.downloadCount = -1
|
||||||
item.downloadCount = -1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((_, itemList) in map) {
|
for (item in itemList) {
|
||||||
for (item in itemList) {
|
item.downloadCount = downloadManager.getDownloadCount(item.manga)
|
||||||
item.downloadCount = downloadManager.getDownloadCount(item.manga)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUnreadBadge(map: LibraryMap) {
|
private fun setUnreadBadge(itemList: List<LibraryItem>) {
|
||||||
val unreadType = preferences.unreadBadgeType().getOrDefault()
|
val unreadType = preferences.unreadBadgeType().getOrDefault()
|
||||||
for ((_, itemList) in map) {
|
for (item in itemList) {
|
||||||
for (item in itemList) {
|
item.unreadType = unreadType
|
||||||
item.unreadType = unreadType
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun applyCatSort(map: LibraryMap, catId: Int?): LibraryMap {
|
|
||||||
if (catId == null) return map
|
|
||||||
val categoryManga = map[catId] ?: return map
|
|
||||||
val catSorted = applySort(mapOf(catId to categoryManga), catId)
|
|
||||||
val mutableMap = map.toMutableMap()
|
|
||||||
mutableMap[catId] = catSorted.values.first()
|
|
||||||
return mutableMap
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun applySort(map: LibraryMap, catId: Int?): LibraryMap {
|
|
||||||
if (catId == null) return map
|
|
||||||
val category = if (catId == 0) createDefaultCategory() else
|
|
||||||
db.getCategories().executeAsBlocking().find { it.id == catId } ?: return map
|
|
||||||
allCategories.find { it.id == catId }?.apply {
|
|
||||||
mangaOrder = category.mangaOrder
|
|
||||||
mangaSort = category.mangaSort
|
|
||||||
}
|
|
||||||
|
|
||||||
val lastReadManga by lazy {
|
|
||||||
var counter = 0
|
|
||||||
db.getLastReadManga().executeAsBlocking().associate { it.id!! to counter++ }
|
|
||||||
}
|
|
||||||
|
|
||||||
val sortFn: (LibraryItem, LibraryItem) -> Int = { i1, i2 ->
|
|
||||||
i1.chapterCount = -1
|
|
||||||
i2.chapterCount = -1
|
|
||||||
sortCategory(i1, i2, lastReadManga, category)
|
|
||||||
}
|
|
||||||
val comparator = Comparator(sortFn)
|
|
||||||
|
|
||||||
return map.mapValues { entry -> entry.value.sortedWith(comparator) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies library sorting to the given map of manga.
|
* Applies library sorting to the given map of manga.
|
||||||
*
|
*
|
||||||
* @param map the map to sort.
|
* @param map the map to sort.
|
||||||
*/
|
*/
|
||||||
private fun applySort(map: LibraryMap): LibraryMap {
|
private fun applySort(map: List<LibraryItem>): List<LibraryItem> {
|
||||||
val sortingMode = preferences.librarySortingMode().getOrDefault()
|
val sortingMode = preferences.librarySortingMode().getOrDefault()
|
||||||
|
|
||||||
val lastReadManga by lazy {
|
val lastReadManga by lazy {
|
||||||
@ -316,8 +245,10 @@ class LibraryPresenter(
|
|||||||
val useDnD = !preferences.hideCategories().getOrDefault()
|
val useDnD = !preferences.hideCategories().getOrDefault()
|
||||||
|
|
||||||
val sortFn: (LibraryItem, LibraryItem) -> Int = { i1, i2 ->
|
val sortFn: (LibraryItem, LibraryItem) -> Int = { i1, i2 ->
|
||||||
i1.chapterCount = -1
|
if (!(sortingMode == LibrarySort.DRAG_AND_DROP || useDnD)) {
|
||||||
i2.chapterCount = -1
|
i1.chapterCount = -1
|
||||||
|
i2.chapterCount = -1
|
||||||
|
}
|
||||||
val compare = when {
|
val compare = when {
|
||||||
sortingMode == LibrarySort.DRAG_AND_DROP || useDnD ->
|
sortingMode == LibrarySort.DRAG_AND_DROP || useDnD ->
|
||||||
sortCategory(i1, i2, lastReadManga)
|
sortCategory(i1, i2, lastReadManga)
|
||||||
@ -361,17 +292,15 @@ class LibraryPresenter(
|
|||||||
else
|
else
|
||||||
Collections.reverseOrder(sortFn)
|
Collections.reverseOrder(sortFn)
|
||||||
|
|
||||||
return map.mapValues { entry -> entry.value.sortedWith(comparator) }
|
return map.sortedWith(comparator)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setTotalChapters() {
|
private fun setTotalChapters() {
|
||||||
if (totalChapters != null) return
|
if (totalChapters != null) return
|
||||||
val mangaMap = rawMangaMap ?: return
|
val mangaMap = allLibraryItems
|
||||||
totalChapters = mangaMap.flatMap {
|
totalChapters = mangaMap.map {
|
||||||
it.value
|
|
||||||
}.associate {
|
|
||||||
it.manga.id!! to db.getChapters(it.manga).executeAsBlocking().size
|
it.manga.id!! to db.getChapters(it.manga).executeAsBlocking().size
|
||||||
}
|
}.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCategory(categoryId: Int): Category {
|
private fun getCategory(categoryId: Int): Category {
|
||||||
@ -394,9 +323,12 @@ class LibraryPresenter(
|
|||||||
val category = initCat ?: allCategories.find { it.id == i1.manga.category } ?: return 0
|
val category = initCat ?: allCategories.find { it.id == i1.manga.category } ?: return 0
|
||||||
if (category.mangaOrder.isNullOrEmpty() && category.mangaSort == null) {
|
if (category.mangaOrder.isNullOrEmpty() && category.mangaSort == null) {
|
||||||
category.changeSortTo(preferences.librarySortingMode().getOrDefault())
|
category.changeSortTo(preferences.librarySortingMode().getOrDefault())
|
||||||
if (category.id == 0) preferences.defaultMangaOrder().set(category.mangaSort.toString())
|
if (category.id == 0) preferences.defaultMangaOrder()
|
||||||
|
.set(category.mangaSort.toString())
|
||||||
else db.insertCategory(category).asRxObservable().subscribe()
|
else db.insertCategory(category).asRxObservable().subscribe()
|
||||||
}
|
}
|
||||||
|
i1.chapterCount = -1
|
||||||
|
i2.chapterCount = -1
|
||||||
val compare = when {
|
val compare = when {
|
||||||
category.mangaSort != null -> {
|
category.mangaSort != null -> {
|
||||||
var sort = when (category.sortingMode()) {
|
var sort = when (category.sortingMode()) {
|
||||||
@ -462,11 +394,10 @@ class LibraryPresenter(
|
|||||||
*
|
*
|
||||||
* @return an observable of the categories and its manga.
|
* @return an observable of the categories and its manga.
|
||||||
*/
|
*/
|
||||||
private fun getLibraryFromDB(): Library {
|
private fun getLibraryFromDB(): List<LibraryItem> {
|
||||||
val categories = db.getCategories().executeAsBlocking().toMutableList()
|
val categories = db.getCategories().executeAsBlocking().toMutableList()
|
||||||
val libraryLayout = preferences.libraryLayout()
|
val libraryLayout = preferences.libraryLayout()
|
||||||
val showCategories = !preferences.hideCategories().getOrDefault()
|
val showCategories = !preferences.hideCategories().getOrDefault()
|
||||||
val unreadBadgeType = preferences.unreadBadgeType().getOrDefault()
|
|
||||||
var libraryManga = db.getLibraryMangas().executeAsBlocking()
|
var libraryManga = db.getLibraryMangas().executeAsBlocking()
|
||||||
val seekPref = preferences.alwaysShowSeeker()
|
val seekPref = preferences.alwaysShowSeeker()
|
||||||
if (!showCategories)
|
if (!showCategories)
|
||||||
@ -475,54 +406,46 @@ class LibraryPresenter(
|
|||||||
preferences.librarySortingMode().getOrDefault(),
|
preferences.librarySortingMode().getOrDefault(),
|
||||||
preferences.librarySortingAscending().getOrDefault())
|
preferences.librarySortingAscending().getOrDefault())
|
||||||
val catItemAll = LibraryHeaderItem({ categoryAll }, -1, seekPref)
|
val catItemAll = LibraryHeaderItem({ categoryAll }, -1, seekPref)
|
||||||
val libraryMap =
|
val categorySet = mutableSetOf<Int>()
|
||||||
libraryManga.groupBy { manga ->
|
val headerItems = (categories.mapNotNull { category ->
|
||||||
if (showCategories) manga.category else -1
|
val id = category.id
|
||||||
// LibraryItem(manga, libraryLayout).apply { unreadType = unreadBadgeType }
|
if (id == null) null
|
||||||
}.map { entry ->
|
else id to LibraryHeaderItem({ getCategory(id) }, id, seekPref)
|
||||||
val categoryItem =
|
} + (-1 to catItemAll) +
|
||||||
if (!showCategories) catItemAll else
|
(0 to LibraryHeaderItem({ getCategory(0) }, 0, seekPref))).toMap()
|
||||||
(LibraryHeaderItem({ getCategory(it) }, entry.key, seekPref))
|
val items = libraryManga.map {
|
||||||
entry.value.map {
|
val headerItem = if (!showCategories) catItemAll else
|
||||||
LibraryItem(
|
headerItems[it.category]
|
||||||
it, libraryLayout, preferences.uniformGrid(), seekPref, categoryItem
|
categorySet.add(it.category)
|
||||||
).apply { unreadType = unreadBadgeType }
|
LibraryItem(it, libraryLayout, preferences.uniformGrid(), seekPref, headerItem)
|
||||||
}
|
}.toMutableList()
|
||||||
}.map {
|
|
||||||
val cat = if (showCategories) it.firstOrNull()?.manga?.category ?: 0 else -1
|
|
||||||
cat to it
|
|
||||||
// LibraryItem(manga, libraryLayout).apply { unreadType = unreadBadgeType }
|
|
||||||
}.toMap().toMutableMap()
|
|
||||||
|
|
||||||
if (showCategories) {
|
if (showCategories) {
|
||||||
categories.forEach { category ->
|
categories.forEach { category ->
|
||||||
if (category.id ?: 0 <= 0 && !libraryMap.containsKey(category.id)) {
|
if (category.id ?: 0 <= 0 && !categorySet.contains(category.id)) {
|
||||||
val headerItem =
|
val headerItem = headerItems[category.id ?: 0]
|
||||||
LibraryHeaderItem({ getCategory(category.id!!) }, category.id!!, seekPref)
|
items.add(LibraryItem(
|
||||||
libraryMap[category.id!!] = listOf(
|
LibraryManga.createBlank(category.id!!),
|
||||||
LibraryItem(
|
libraryLayout,
|
||||||
LibraryManga.createBlank(category.id!!),
|
preferences.uniformGrid(),
|
||||||
libraryLayout,
|
preferences.alwaysShowSeeker(),
|
||||||
preferences.uniformGrid(),
|
headerItem
|
||||||
preferences.alwaysShowSeeker(),
|
))
|
||||||
headerItem
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (libraryMap.containsKey(0))
|
if (categories.size == 1 && showCategories) categories.first().name =
|
||||||
categories.add(0, createDefaultCategory())
|
context.getString(R.string.library)
|
||||||
|
|
||||||
if (categories.size == 1 && showCategories)
|
if (categorySet.contains(0))
|
||||||
categories.first().name = context.getString(R.string.library)
|
categories.add(0, createDefaultCategory())
|
||||||
|
|
||||||
this.allCategories = categories
|
this.allCategories = categories
|
||||||
this.categories = if (!showCategories) arrayListOf(categoryAll)
|
this.categories = if (!showCategories) arrayListOf(categoryAll)
|
||||||
else categories
|
else categories
|
||||||
|
|
||||||
return Library(this.categories, libraryMap)
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDefaultCategory(): Category {
|
private fun createDefaultCategory(): Category {
|
||||||
@ -539,65 +462,26 @@ class LibraryPresenter(
|
|||||||
*/
|
*/
|
||||||
fun requestFilterUpdate() {
|
fun requestFilterUpdate() {
|
||||||
launchUI {
|
launchUI {
|
||||||
var mangaMap = rawMangaMap ?: return@launchUI
|
var mangaMap = allLibraryItems
|
||||||
mangaMap = withContext(Dispatchers.IO) { applyFilters(mangaMap) }
|
mangaMap = withContext(Dispatchers.IO) { applyFilters(mangaMap) }
|
||||||
mangaMap = withContext(Dispatchers.IO) { applySort(mangaMap) }
|
mangaMap = withContext(Dispatchers.IO) { applySort(mangaMap) }
|
||||||
currentMangaMap = mangaMap
|
libraryItems = mangaMap
|
||||||
updateView(categories, mangaMap)
|
view.onNextLibraryUpdate(libraryItems)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun updateView(
|
|
||||||
categories: List<Category>,
|
|
||||||
mangaMap: LibraryMap,
|
|
||||||
freshStart: Boolean =
|
|
||||||
false
|
|
||||||
) {
|
|
||||||
val mangaList = withContext(Dispatchers.IO) {
|
|
||||||
val list = mutableListOf<LibraryItem>()
|
|
||||||
for (element in mangaMap.toSortedMap(compareBy { entry ->
|
|
||||||
categories.find { it.id == entry }?.order ?: -1
|
|
||||||
})) {
|
|
||||||
list.addAll(element.value)
|
|
||||||
}
|
|
||||||
list
|
|
||||||
}
|
|
||||||
view.onNextLibraryUpdate(mangaList, freshStart)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getList(): List<LibraryItem> {
|
|
||||||
val list = mutableListOf<LibraryItem>()
|
|
||||||
for (element in currentMangaMap!!.toSortedMap(compareBy { entry ->
|
|
||||||
categories.find { it.id == entry }?.order ?: -1
|
|
||||||
})) {
|
|
||||||
list.addAll(element.value)
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateViewBlocking() {
|
|
||||||
val mangaMap = currentMangaMap ?: return
|
|
||||||
val list = mutableListOf<LibraryItem>()
|
|
||||||
for (element in mangaMap.toSortedMap(compareBy { entry ->
|
|
||||||
categories.find { it.id == entry }?.order ?: -1
|
|
||||||
})) {
|
|
||||||
list.addAll(element.value)
|
|
||||||
}
|
|
||||||
view.onNextLibraryUpdate(list, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests the library to have download badges added/removed.
|
* Requests the library to have download badges added/removed.
|
||||||
*/
|
*/
|
||||||
fun requestDownloadBadgesUpdate() {
|
fun requestDownloadBadgesUpdate() {
|
||||||
launchUI {
|
launchUI {
|
||||||
val mangaMap = rawMangaMap ?: return@launchUI
|
val mangaMap = allLibraryItems
|
||||||
withContext(Dispatchers.IO) { setDownloadCount(mangaMap) }
|
withContext(Dispatchers.IO) { setDownloadCount(mangaMap) }
|
||||||
rawMangaMap = mangaMap
|
allLibraryItems = mangaMap
|
||||||
val current = currentMangaMap ?: return@launchUI
|
val current = libraryItems
|
||||||
withContext(Dispatchers.IO) { setDownloadCount(current) }
|
withContext(Dispatchers.IO) { setDownloadCount(current) }
|
||||||
currentMangaMap = current
|
libraryItems = current
|
||||||
updateView(categories, current)
|
view.onNextLibraryUpdate(libraryItems)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,36 +489,26 @@ class LibraryPresenter(
|
|||||||
* Requests the library to have unread badges changed.
|
* Requests the library to have unread badges changed.
|
||||||
*/
|
*/
|
||||||
fun requestUnreadBadgesUpdate() {
|
fun requestUnreadBadgesUpdate() {
|
||||||
// getLibrary()
|
|
||||||
launchUI {
|
launchUI {
|
||||||
val mangaMap = rawMangaMap ?: return@launchUI
|
val mangaMap = allLibraryItems
|
||||||
withContext(Dispatchers.IO) { setUnreadBadge(mangaMap) }
|
withContext(Dispatchers.IO) { setUnreadBadge(mangaMap) }
|
||||||
rawMangaMap = mangaMap
|
libraryItems = mangaMap
|
||||||
val current = currentMangaMap ?: return@launchUI
|
val current = libraryItems
|
||||||
withContext(Dispatchers.IO) { setUnreadBadge(current) }
|
withContext(Dispatchers.IO) { setUnreadBadge(current) }
|
||||||
currentMangaMap = current
|
libraryItems = current
|
||||||
updateView(categories, current)
|
view.onNextLibraryUpdate(libraryItems)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests the library to be sorted.
|
* Requests the library to be sorted.
|
||||||
*/
|
*/
|
||||||
fun requestSortUpdate() {
|
private fun requestSortUpdate() {
|
||||||
launchUI {
|
launchUI {
|
||||||
var mangaMap = currentMangaMap ?: return@launchUI
|
var mangaMap = libraryItems
|
||||||
mangaMap = withContext(Dispatchers.IO) { applySort(mangaMap) }
|
mangaMap = withContext(Dispatchers.IO) { applySort(mangaMap) }
|
||||||
currentMangaMap = mangaMap
|
libraryItems = mangaMap
|
||||||
updateView(categories, mangaMap)
|
view.onNextLibraryUpdate(libraryItems)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun requestCatSortUpdate(catId: Int) {
|
|
||||||
launchUI {
|
|
||||||
var mangaMap = currentMangaMap ?: return@launchUI
|
|
||||||
mangaMap = withContext(Dispatchers.IO) { applyCatSort(mangaMap, catId) }
|
|
||||||
currentMangaMap = mangaMap
|
|
||||||
updateView(categories, mangaMap)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,10 +528,8 @@ class LibraryPresenter(
|
|||||||
* Remove the selected manga from the library.
|
* Remove the selected manga from the library.
|
||||||
*
|
*
|
||||||
* @param mangas the list of manga to delete.
|
* @param mangas the list of manga to delete.
|
||||||
* @param deleteChapters whether to also delete downloaded chapters.
|
|
||||||
*/
|
*/
|
||||||
fun removeMangaFromLibrary(mangas: List<Manga>) {
|
fun removeMangaFromLibrary(mangas: List<Manga>) {
|
||||||
|
|
||||||
GlobalScope.launch(Dispatchers.IO, CoroutineStart.DEFAULT) {
|
GlobalScope.launch(Dispatchers.IO, CoroutineStart.DEFAULT) {
|
||||||
// Create a set of the list
|
// Create a set of the list
|
||||||
val mangaToDelete = mangas.distinctBy { it.id }
|
val mangaToDelete = mangas.distinctBy { it.id }
|
||||||
@ -683,19 +555,15 @@ class LibraryPresenter(
|
|||||||
|
|
||||||
fun updateManga(manga: LibraryManga) {
|
fun updateManga(manga: LibraryManga) {
|
||||||
GlobalScope.launch(Dispatchers.IO, CoroutineStart.DEFAULT) {
|
GlobalScope.launch(Dispatchers.IO, CoroutineStart.DEFAULT) {
|
||||||
val rawMap = rawMangaMap ?: return@launch
|
val rawMap = allLibraryItems ?: return@launch
|
||||||
val currentMap = currentMangaMap ?: return@launch
|
val currentMap = libraryItems ?: return@launch
|
||||||
val id = manga.id ?: return@launch
|
val id = manga.id ?: return@launch
|
||||||
val dbManga = db.getLibraryManga(id).executeAsBlocking() ?: return@launch
|
val dbManga = db.getLibraryManga(id).executeAsBlocking() ?: return@launch
|
||||||
arrayOf(rawMap, currentMap).forEach { map ->
|
arrayOf(rawMap, currentMap).forEach { map ->
|
||||||
map.apply {
|
map.forEach { item ->
|
||||||
forEach { entry ->
|
if (item.manga.id == dbManga.id) {
|
||||||
entry.value.forEach { item ->
|
item.manga.last_update = dbManga.last_update
|
||||||
if (item.manga.id == dbManga.id) {
|
item.manga.unread = dbManga.unread
|
||||||
item.manga.last_update = dbManga.last_update
|
|
||||||
item.manga.unread = dbManga.unread
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -703,8 +571,7 @@ class LibraryPresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addMangas(mangas: List<Manga>) {
|
fun reAddMangas(mangas: List<Manga>) {
|
||||||
|
|
||||||
GlobalScope.launch(Dispatchers.IO, CoroutineStart.DEFAULT) {
|
GlobalScope.launch(Dispatchers.IO, CoroutineStart.DEFAULT) {
|
||||||
val mangaToAdd = mangas.distinctBy { it.id }
|
val mangaToAdd = mangas.distinctBy { it.id }
|
||||||
mangaToAdd.forEach { it.favorite = true }
|
mangaToAdd.forEach { it.favorite = true }
|
||||||
@ -728,86 +595,8 @@ class LibraryPresenter(
|
|||||||
mc.add(MangaCategory.create(manga, cat))
|
mc.add(MangaCategory.create(manga, cat))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db.setMangaCategories(mc, mangas)
|
db.setMangaCategories(mc, mangas)
|
||||||
}
|
getLibrary()
|
||||||
|
|
||||||
fun migrateManga(prevManga: Manga, manga: Manga, replace: Boolean) {
|
|
||||||
val source = sourceManager.get(manga.source) ?: return
|
|
||||||
|
|
||||||
// state = state.copy(isReplacingManga = true)
|
|
||||||
|
|
||||||
Observable.defer { source.fetchChapterList(manga) }
|
|
||||||
.onErrorReturn { emptyList() }
|
|
||||||
.doOnNext { migrateMangaInternal(source, it, prevManga, manga, replace) }
|
|
||||||
.onErrorReturn { emptyList() }
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
// .doOnUnsubscribe { state = state.copy(isReplacingManga = false) }
|
|
||||||
.subscribe()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun migrateMangaInternal(
|
|
||||||
source: Source,
|
|
||||||
sourceChapters: List<SChapter>,
|
|
||||||
prevManga: Manga,
|
|
||||||
manga: Manga,
|
|
||||||
replace: Boolean
|
|
||||||
) {
|
|
||||||
|
|
||||||
val flags = preferences.migrateFlags().getOrDefault()
|
|
||||||
val migrateChapters = MigrationFlags.hasChapters(flags)
|
|
||||||
val migrateCategories = MigrationFlags.hasCategories(flags)
|
|
||||||
val migrateTracks = MigrationFlags.hasTracks(flags)
|
|
||||||
|
|
||||||
db.inTransaction {
|
|
||||||
// Update chapters read
|
|
||||||
if (migrateChapters) {
|
|
||||||
try {
|
|
||||||
syncChaptersWithSource(db, sourceChapters, manga, source)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
// Worst case, chapters won't be synced
|
|
||||||
}
|
|
||||||
|
|
||||||
val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking()
|
|
||||||
val maxChapterRead =
|
|
||||||
prevMangaChapters.filter { it.read }.maxBy { it.chapter_number }?.chapter_number
|
|
||||||
if (maxChapterRead != null) {
|
|
||||||
val dbChapters = db.getChapters(manga).executeAsBlocking()
|
|
||||||
for (chapter in dbChapters) {
|
|
||||||
if (chapter.isRecognizedNumber && chapter.chapter_number <= maxChapterRead) {
|
|
||||||
chapter.read = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
db.insertChapters(dbChapters).executeAsBlocking()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update categories
|
|
||||||
if (migrateCategories) {
|
|
||||||
val categories = db.getCategoriesForManga(prevManga).executeAsBlocking()
|
|
||||||
val mangaCategories = categories.map { MangaCategory.create(manga, it) }
|
|
||||||
db.setMangaCategories(mangaCategories, listOf(manga))
|
|
||||||
}
|
|
||||||
// Update track
|
|
||||||
if (migrateTracks) {
|
|
||||||
val tracks = db.getTracks(prevManga).executeAsBlocking()
|
|
||||||
for (track in tracks) {
|
|
||||||
track.id = null
|
|
||||||
track.manga_id = manga.id!!
|
|
||||||
}
|
|
||||||
db.insertTracks(tracks).executeAsBlocking()
|
|
||||||
}
|
|
||||||
// Update favorite status
|
|
||||||
if (replace) {
|
|
||||||
prevManga.favorite = false
|
|
||||||
db.updateMangaFavorite(prevManga).executeAsBlocking()
|
|
||||||
}
|
|
||||||
manga.favorite = true
|
|
||||||
db.updateMangaFavorite(manga).executeAsBlocking()
|
|
||||||
|
|
||||||
// SearchPresenter#networkToLocalManga may have updated the manga title, so ensure db gets updated title
|
|
||||||
db.updateMangaTitle(manga).executeAsBlocking()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFirstUnread(manga: Manga): Chapter? {
|
fun getFirstUnread(manga: Manga): Chapter? {
|
||||||
@ -826,7 +615,7 @@ class LibraryPresenter(
|
|||||||
} else {
|
} else {
|
||||||
if (category.id == 0) preferences.defaultMangaOrder().set(category.mangaSort.toString())
|
if (category.id == 0) preferences.defaultMangaOrder().set(category.mangaSort.toString())
|
||||||
else Injekt.get<DatabaseHelper>().insertCategory(category).executeAsBlocking()
|
else Injekt.get<DatabaseHelper>().insertCategory(category).executeAsBlocking()
|
||||||
requestCatSortUpdate(category.id!!)
|
requestSortUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -837,7 +626,7 @@ class LibraryPresenter(
|
|||||||
category.mangaOrder = mangaIds
|
category.mangaOrder = mangaIds
|
||||||
if (category.id == 0) preferences.defaultMangaOrder().set(mangaIds.joinToString("/"))
|
if (category.id == 0) preferences.defaultMangaOrder().set(mangaIds.joinToString("/"))
|
||||||
else db.insertCategory(category).executeAsBlocking()
|
else db.insertCategory(category).executeAsBlocking()
|
||||||
requestCatSortUpdate(category.id!!)
|
requestSortUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -884,7 +673,8 @@ class LibraryPresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private var currentLibrary: Library? = null
|
private var lastLibraryItems: List<LibraryItem>? = null
|
||||||
|
private var lastCategories: List<Category>? = null
|
||||||
|
|
||||||
fun updateDB() {
|
fun updateDB() {
|
||||||
val db: DatabaseHelper = Injekt.get()
|
val db: DatabaseHelper = Injekt.get()
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.library
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.widget.ArrayAdapter
|
|
||||||
import android.widget.Spinner
|
|
||||||
|
|
||||||
class ReSpinner : Spinner {
|
|
||||||
constructor(context: Context?) : super(context) {}
|
|
||||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) {}
|
|
||||||
constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : super(
|
|
||||||
context, attrs, defStyle
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun setSelection(position: Int, animate: Boolean) {
|
|
||||||
val sameSelected = position == selectedItemPosition
|
|
||||||
super.setSelection(position, animate)
|
|
||||||
if (sameSelected) { // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
|
|
||||||
onItemSelectedListener?.onItemSelected(
|
|
||||||
this, selectedView, position, selectedItemId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setSelection(position: Int) {
|
|
||||||
val sameSelected = position == selectedItemPosition
|
|
||||||
super.setSelection(position)
|
|
||||||
if (sameSelected) { // Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
|
|
||||||
onItemSelectedListener?.onItemSelected(
|
|
||||||
this, selectedView, position, selectedItemId
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SpinnerAdapter(context: Context, layoutId: Int, val array: Array<String>) :
|
|
||||||
ArrayAdapter<String>
|
|
||||||
(context, layoutId, array)
|
|
@ -62,7 +62,7 @@
|
|||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
tools:tint="?attr/colorAccent"
|
android:tint="?attr/colorAccent"
|
||||||
android:src="@drawable/ic_refresh_white_24dp"
|
android:src="@drawable/ic_refresh_white_24dp"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/category_title"
|
app:layout_constraintBottom_toBottomOf="@id/category_title"
|
||||||
app:layout_constraintTop_toTopOf="@id/category_title"
|
app:layout_constraintTop_toTopOf="@id/category_title"
|
||||||
@ -70,6 +70,18 @@
|
|||||||
app:layout_constraintStart_toEndOf="@id/category_title"
|
app:layout_constraintStart_toEndOf="@id/category_title"
|
||||||
app:rippleColor="@color/fullRippleColor" />
|
app:rippleColor="@color/fullRippleColor" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/cat_progress"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/update_button"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/update_button"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/update_button"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/update_button"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/category_sort"
|
android:id="@+id/category_sort"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -82,6 +94,7 @@
|
|||||||
android:ellipsize="start"
|
android:ellipsize="start"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:gravity="center|end"
|
android:gravity="center|end"
|
||||||
|
android:background="@drawable/square_ripple"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:padding="6dp"
|
android:padding="6dp"
|
||||||
android:textAlignment="textEnd"
|
android:textAlignment="textEnd"
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<com.reddit.indicatorfastscroll.FastScrollerView
|
<com.reddit.indicatorfastscroll.FastScrollerView
|
||||||
android:id="@+id/fast_scroller"
|
android:id="@+id/fast_scroller"
|
||||||
android:textColor="?android:attr/textColorPrimaryInverse"
|
android:textColor="?android:attr/textColorPrimaryInverse"
|
||||||
android:layout_width="22dp"
|
android:layout_width="25dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:elevation="10dp"
|
android:elevation="10dp"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
|
Loading…
Reference in New Issue
Block a user