Bundles for library

Saving and restoring from config changes now keeps the library position and manga in place, using a static value for when the tachi is closed via the back button
Added blocking method in library presenter so we can stay on the splash screen while the library loads
This commit is contained in:
Jay 2020-02-10 00:59:57 -08:00
parent 4d1623a812
commit 580b2a5778
13 changed files with 163 additions and 81 deletions

View File

@ -107,8 +107,6 @@ object PreferenceKeys {
const val automaticExtUpdates = "automatic_ext_updates"
const val startScreen = "start_screen"
const val downloadNew = "download_new"
const val downloadNewCategories = "download_new_categories"

View File

@ -53,8 +53,6 @@ class PreferencesHelper(val context: Context) {
fun getStringPref(key: String, default: String?) = rxPrefs.getString(key, default)
fun getStringSet(key: String, default: Set<String>) = rxPrefs.getStringSet(key, default)
fun startScreen() = prefs.getInt(Keys.startScreen, 1)
fun clear() = prefs.edit().clear().apply()
fun theme() = prefs.getInt(Keys.theme, 5)

View File

@ -3,6 +3,8 @@ package eu.kanade.tachiyomi.ui.base.controller
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
@ -10,6 +12,7 @@ import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType
import com.bluelinelabs.conductor.RestoreViewOnCreateController
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.*
import timber.log.Timber
@ -64,6 +67,8 @@ abstract class BaseController(bundle: Bundle? = null) : RestoreViewOnCreateContr
super.onChangeStarted(handler, type)
}
open fun handleRootBack(): Boolean = false
open fun getTitle(): String? {
return null
}

View File

@ -18,17 +18,13 @@ import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.category.CategoryAdapter
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.lang.plusAssign
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
import eu.kanade.tachiyomi.util.view.inflate
import eu.kanade.tachiyomi.util.view.snack
import eu.kanade.tachiyomi.util.view.updateLayoutParams
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import kotlinx.android.synthetic.main.filter_bottom_sheet.*
import kotlinx.android.synthetic.main.library_category.view.*
import kotlinx.android.synthetic.main.library_controller.*
import kotlinx.coroutines.delay
@ -101,6 +97,11 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
swipe_refresh.addView(recycler)
adapter.fastScroller = fast_scroller
if (::category.isInitialized) {
val mangaForCategory = controller.presenter.getMangaInCategory(category.id)
if (mangaForCategory != null)
adapter.setItems(mangaForCategory)
}
val config = resources?.configuration
val phoneLandscape = (config?.orientation == Configuration.ORIENTATION_LANDSCAPE &&

View File

@ -16,8 +16,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.SearchView
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import androidx.viewpager.widget.ViewPager
import com.afollestad.materialdialogs.MaterialDialog
import com.bluelinelabs.conductor.ControllerChangeHandler
@ -40,7 +38,6 @@ import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.SecondaryDrawerController
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.category.CategoryController
@ -55,14 +52,8 @@ import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.view.gone
import eu.kanade.tachiyomi.util.view.inflate
import eu.kanade.tachiyomi.util.view.marginBottom
import eu.kanade.tachiyomi.util.view.marginTop
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
import eu.kanade.tachiyomi.util.view.snack
import eu.kanade.tachiyomi.util.view.updatePaddingRelative
import eu.kanade.tachiyomi.util.view.visible
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
import kotlinx.android.synthetic.main.filter_bottom_sheet.*
import kotlinx.android.synthetic.main.library_controller.*
import kotlinx.android.synthetic.main.main_activity.*
@ -152,7 +143,9 @@ class LibraryController(
var snack: Snackbar? = null
private var presenter = LibraryPresenter(this)
var presenter = LibraryPresenter(this)
private set
init {
setHasOptionsMenu(true)
@ -177,29 +170,26 @@ class LibraryController(
activeCategory = position
}
override fun onPageScrollStateChanged(state: Int) { }
override fun onPageScrollStateChanged(state: Int) {}
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) { }
position: Int, positionOffset: Float, positionOffsetPixels: Int
) {
}
})
library_pager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
override fun onPageSelected(position: Int) {
bottom_sheet.lastCategory = adapter?.categories?.getOrNull(position)
if (preferences.librarySortingMode().getOrDefault() == LibrarySort.DRAG_AND_DROP)
bottom_sheet.updateTitle()
if (preferences.librarySortingMode().getOrDefault() == LibrarySort.DRAG_AND_DROP) bottom_sheet.updateTitle()
}
override fun onPageScrolled(
position: Int,
positionOffset: Float,
positionOffsetPixels: Int
) { }
position: Int, positionOffset: Float, positionOffsetPixels: Int
) {
}
override fun onPageScrollStateChanged(state: Int) { }
override fun onPageScrollStateChanged(state: Int) {}
})
mangaPerRow = getColumnsPreferenceForCurrentOrientation().getOrDefault()
@ -225,6 +215,12 @@ class LibraryController(
fab.setOnClickListener {
router.pushController(DownloadController().withFadeTransaction())
}
presenter.onRestore()
val library = presenter.getAllManga()
if (library != null) onNextLibraryUpdate(presenter.categories, library)
else {
presenter.getLibraryBlocking()
}
}
override fun onChangeStarted(handler: ControllerChangeHandler, type: ControllerChangeType) {
@ -238,6 +234,11 @@ class LibraryController(
}
}
override fun onDestroy() {
presenter.onDestroy()
super.onDestroy()
}
override fun onDestroyView(view: View) {
adapter?.onDestroy()
DownloadService.removeListener(this)
@ -429,19 +430,11 @@ class LibraryController(
// Mutate the filter icon because it needs to be tinted and the resource is shared.
menu.findItem(R.id.action_library_filter).icon.mutate()
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextChange(newText: String?): Boolean {
if (router.backstack.lastOrNull()?.controller() == this@LibraryController) {
query = newText ?: ""
searchRelay.call(query)
}
return true
}
override fun onQueryTextSubmit(query: String?): Boolean {
return true
}
})
setOnQueryTextChangeListener(searchView) {
query = it ?: ""
searchRelay.call(query)
true
}
searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() })
}
@ -449,13 +442,13 @@ class LibraryController(
this.query = query
}
override fun handleBack(): Boolean {
override fun handleRootBack(): Boolean {
val sheetBehavior = BottomSheetBehavior.from(bottom_sheet)
if (sheetBehavior.state != BottomSheetBehavior.STATE_COLLAPSED) {
sheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
return true
}
return super.handleBack()
return false
}
override fun onPrepareOptionsMenu(menu: Menu) {

View File

@ -18,6 +18,7 @@ import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import kotlinx.android.synthetic.main.catalogue_grid_item.view.*
import uy.kohesive.injekt.injectLazy
import java.io.Serializable
class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference<Boolean>) :
AbstractFlexibleItem<LibraryHolder>(), IFilterable<String> {

View File

@ -17,8 +17,6 @@ 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.online.HttpSource
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.migration.MigrationFlags
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.lang.removeArticles
@ -37,6 +35,7 @@ import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.Serializable
import java.util.ArrayList
import java.util.Collections
import java.util.Comparator
@ -44,12 +43,12 @@ import java.util.Comparator
/**
* Class containing library information.
*/
private data class Library(val categories: List<Category>, val mangaMap: LibraryMap)
private data class Library(val categories: List<Category>, val mangaMap: LibraryMap): Serializable
/**
* Typealias for the library manga, using the category as keys, and list of manga as values.
*/
private typealias LibraryMap = Map<Int, List<LibraryItem>>
private typealias LibraryMap = HashMap<Int, List<LibraryItem>>
/**
* Presenter of [LibraryController].
@ -81,6 +80,21 @@ class LibraryPresenter(
private var currentMangaMap:LibraryMap? = null
private companion object {
var currentLibrary:Library? = null
}
fun onDestroy() {
if (currentMangaMap != null)
currentLibrary = Library(categories, currentMangaMap!!)
}
fun onRestore() {
categories = currentLibrary?.categories ?: return
currentMangaMap = currentLibrary?.mangaMap
currentLibrary = null
}
fun getLibrary() {
launchUI {
val mangaMap = withContext(Dispatchers.IO) {
@ -97,6 +111,29 @@ class LibraryPresenter(
}
}
fun getLibraryBlocking() {
val mangaMap = {
val library = getLibraryFromDB()
library.apply { setDownloadCount(library.mangaMap) }
rawMangaMap = library.mangaMap
var mangaMap = library.mangaMap
mangaMap = applyFilters(mangaMap)
mangaMap = applySort(mangaMap)
mangaMap
}()
currentMangaMap = mangaMap
view.onNextLibraryUpdate(categories, mangaMap)
}
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.
*
@ -158,7 +195,13 @@ class LibraryPresenter(
true
}
return map.mapValues { entry -> entry.value.filter(filterFn) }
val filterMap = map.mapValues { entry -> entry.value.filter(filterFn) }
val hashMap = hashMapOf<Int, List<LibraryItem>>()
filterMap.map {
hashMap.put(it.key, it.value)
}
return hashMap
}
/**
@ -196,10 +239,9 @@ class LibraryPresenter(
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
val catSorted = applySort(hashMapOf(catId to categoryManga), catId)
map[catId] = catSorted.values.first()
return map
}
private fun applySort(map: LibraryMap, catId: Int?): LibraryMap {
@ -254,7 +296,13 @@ class LibraryPresenter(
}
val comparator = Comparator(sortFn)
return map.mapValues { entry -> entry.value.sortedWith(comparator) }
val sortedMap = map.mapValues { entry -> entry.value.sortedWith(comparator) }
val hashMap = hashMapOf<Int, List<LibraryItem>>()
sortedMap.map {
hashMap.put(it.key, it.value)
}
return hashMap
}
/**
@ -362,7 +410,13 @@ class LibraryPresenter(
else
Collections.reverseOrder(sortFn)
return map.mapValues { entry -> entry.value.sortedWith(comparator) }
val sortedMap = map.mapValues { entry -> entry.value.sortedWith(comparator) }
val hashMap = hashMapOf<Int, List<LibraryItem>>()
sortedMap.map {
hashMap.put(it.key, it.value)
}
return hashMap
}
private fun sortAlphabetical(i1: LibraryItem, i2: LibraryItem): Int {
@ -396,7 +450,11 @@ class LibraryPresenter(
this.categories = if (preferences.hideCategories().getOrDefault())
arrayListOf(createDefaultCategory())
else categories
return Library(this.categories, libraryMap)
val hashMap = hashMapOf<Int, List<LibraryItem>>()
libraryMap.map {
hashMap.put(it.key, it.value)
}
return Library(this.categories, hashMap)
}
private fun createDefaultCategory(): Category {

View File

@ -3,6 +3,8 @@ package eu.kanade.tachiyomi.ui.library.filter
import android.content.Context
import android.content.res.Configuration
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.os.Parcelable
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
@ -69,6 +71,10 @@ class SortFilterBottomSheet @JvmOverloads constructor(context: Context, attrs: A
var sheetBehavior:BottomSheetBehavior<View>? = null
var peekHeight = 0
var startingTitle = ""
private lateinit var clearButton:ImageView
private val filterItems:MutableList<FilterTagGroup> by lazy {
@ -109,7 +115,7 @@ class SortFilterBottomSheet @JvmOverloads constructor(context: Context, attrs: A
sheetBehavior?.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
title.text = startingTitle
pager = pagerView
updateTitle()
val shadow2:View = (pagerView.parent as ViewGroup).findViewById(R.id.shadow2)
@ -146,10 +152,16 @@ class SortFilterBottomSheet @JvmOverloads constructor(context: Context, attrs: A
if (phoneLandscape && shadow2.visibility != View.GONE) {
shadow2.gone()
}
sheetBehavior?.peekHeight = peekHeight
top_bar.viewTreeObserver.addOnGlobalLayoutListener {
sheetBehavior?.peekHeight = if (phoneLandscape) 0
val peekingHeight = if (phoneLandscape) 0
else if (!title.text.isNullOrBlank()) top_bar.height
else if (peekHeight != 0) -1
else 0
if (peekingHeight > -1 && (peekHeight == 0 || peekingHeight > 0)) {
sheetBehavior?.peekHeight = peekingHeight
peekHeight = peekingHeight
}
if (sheetBehavior?.state == BottomSheetBehavior.STATE_COLLAPSED) {
val height = context.resources.getDimensionPixelSize(R.dimen.rounder_radius)
pager?.setPadding(0, 0, 0, if (phoneLandscape) 0 else
@ -178,6 +190,31 @@ class SortFilterBottomSheet @JvmOverloads constructor(context: Context, attrs: A
display_group.bindToPreference(preferences.libraryAsList())
}
override fun onSaveInstanceState(): Parcelable? {
val bundle = Bundle()
bundle.putParcelable("superState", super.onSaveInstanceState())
bundle.putInt("peek", sheetBehavior?.peekHeight ?: 0)
bundle.putString("title", title.text.toString())
return bundle
}
override fun onRestoreInstanceState(state: Parcelable?) {
if (state is Bundle) // implicit null check
{
this.peekHeight = state.getInt("peek")
this.startingTitle = state.getString("title") ?: ""
val sheet = BottomSheetBehavior.from(this)
sheet.peekHeight = peekHeight
title.text = startingTitle
super.onRestoreInstanceState( state.getParcelable("superState"))
top_bar.alpha =
if (sheet.state == BottomSheetBehavior.STATE_COLLAPSED) 1f
else 0f
}
else
super.onRestoreInstanceState(state)
}
private fun isLandscape(): Boolean {
return context.resources.configuration?.orientation == Configuration.ORIENTATION_LANDSCAPE
}

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.ui.main
import android.animation.ObjectAnimator
import android.app.SearchManager
import android.content.Intent
import android.content.res.Configuration
@ -36,6 +35,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.base.controller.NoToolbarElevationController
import eu.kanade.tachiyomi.ui.base.controller.SecondaryDrawerController
@ -92,14 +92,6 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
extraViewForUndo = extraViewToCheck
}
private val startScreenId by lazy {
when (preferences.startScreen()) {
2 -> R.id.nav_drawer_recently_read
3 -> R.id.nav_drawer_recent_updates
else -> R.id.nav_drawer_library
}
}
lateinit var tabAnimator: TabsAnimator
override fun onCreate(savedInstanceState: Bundle?) {
@ -240,7 +232,7 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
if (!router.hasRootController()) {
// Set start screen
if (!handleIntentAction(intent)) {
setSelectedDrawerItem(startScreenId)
setSelectedDrawerItem(R.id.nav_drawer_library)
}
}
@ -420,9 +412,13 @@ open class MainActivity : BaseActivity(), DownloadServiceListener {
}
if (drawer.isDrawerOpen(GravityCompat.START) || drawer.isDrawerOpen(GravityCompat.END)) {
drawer.closeDrawers()
} else if (!router.handleBack()) {
unlocked = false
super.onBackPressed()
} else {
val baseController = router.backstack.last().controller() as BaseController
if (if (router.backstackSize == 1) !baseController.handleRootBack()
else !router.handleBack()) {
unlocked = false
super.onBackPressed()
}
}
}

View File

@ -76,14 +76,6 @@ class SettingsGeneralController : SettingsController() {
summary = "%s"
}
intListPreference(activity) {
key = Keys.startScreen
titleRes = R.string.pref_start_screen
entriesRes = arrayOf(R.string.label_library, R.string.label_recent_manga,
R.string.label_recent_updates)
entryRange = 1..3
defaultValue = 1
}
switchPreference {
key = Keys.automaticUpdates
titleRes = R.string.pref_enable_automatic_updates

View File

@ -2,6 +2,7 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:id="@+id/library_layout"
android:layout_height="match_parent">
<androidx.coordinatorlayout.widget.CoordinatorLayout

View File

@ -2,6 +2,7 @@
<eu.kanade.tachiyomi.widget.AutofitRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
style="@style/Theme.Widget.GridView.Catalogue"
android:id="@+id/grid_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="140dp"

View File

@ -2,6 +2,7 @@
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"