Ability to order sources by library count when migrating (#6000)
* order sources by library count when migrating (closes #4703) * Use plain menu instead of full-on sheet
This commit is contained in:
parent
c6d4e4c15f
commit
ba8abd94a8
6 changed files with 118 additions and 2 deletions
|
@ -151,6 +151,9 @@ object PreferenceKeys {
|
||||||
const val librarySortingMode = "library_sorting_mode"
|
const val librarySortingMode = "library_sorting_mode"
|
||||||
const val librarySortingDirection = "library_sorting_ascending"
|
const val librarySortingDirection = "library_sorting_ascending"
|
||||||
|
|
||||||
|
const val migrationSortingMode = "pref_migration_sorting"
|
||||||
|
const val migrationSortingDirection = "pref_migration_direction"
|
||||||
|
|
||||||
const val automaticExtUpdates = "automatic_ext_updates"
|
const val automaticExtUpdates = "automatic_ext_updates"
|
||||||
|
|
||||||
const val showNsfwSource = "show_nsfw_source"
|
const val showNsfwSource = "show_nsfw_source"
|
||||||
|
|
|
@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.ThemeMode.system
|
import eu.kanade.tachiyomi.data.preference.PreferenceValues.ThemeMode.system
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
import eu.kanade.tachiyomi.data.track.TrackService
|
||||||
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
||||||
|
import eu.kanade.tachiyomi.ui.browse.migration.sources.MigrationSourcesController
|
||||||
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
|
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
|
||||||
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
|
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
|
||||||
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
|
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
|
||||||
|
@ -267,6 +268,9 @@ class PreferencesHelper(val context: Context) {
|
||||||
fun librarySortingMode() = flowPrefs.getEnum(Keys.librarySortingMode, SortModeSetting.ALPHABETICAL)
|
fun librarySortingMode() = flowPrefs.getEnum(Keys.librarySortingMode, SortModeSetting.ALPHABETICAL)
|
||||||
fun librarySortingAscending() = flowPrefs.getEnum(Keys.librarySortingDirection, SortDirectionSetting.ASCENDING)
|
fun librarySortingAscending() = flowPrefs.getEnum(Keys.librarySortingDirection, SortDirectionSetting.ASCENDING)
|
||||||
|
|
||||||
|
fun migrationSortingMode() = flowPrefs.getEnum(Keys.migrationSortingMode, MigrationSourcesController.SortSetting.ALPHABETICAL)
|
||||||
|
fun migrationSortingDirection() = flowPrefs.getEnum(Keys.migrationSortingDirection, MigrationSourcesController.DirectionSetting.ASCENDING)
|
||||||
|
|
||||||
fun automaticExtUpdates() = flowPrefs.getBoolean(Keys.automaticExtUpdates, true)
|
fun automaticExtUpdates() = flowPrefs.getBoolean(Keys.automaticExtUpdates, true)
|
||||||
|
|
||||||
fun showNsfwSource() = flowPrefs.getBoolean(Keys.showNsfwSource, true)
|
fun showNsfwSource() = flowPrefs.getBoolean(Keys.showNsfwSource, true)
|
||||||
|
|
|
@ -9,16 +9,20 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import dev.chrisbanes.insetter.applyInsetter
|
import dev.chrisbanes.insetter.applyInsetter
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.databinding.MigrationSourcesControllerBinding
|
import eu.kanade.tachiyomi.databinding.MigrationSourcesControllerBinding
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrationMangaController
|
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrationMangaController
|
||||||
import eu.kanade.tachiyomi.util.system.openInBrowser
|
import eu.kanade.tachiyomi.util.system.openInBrowser
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
class MigrationSourcesController :
|
class MigrationSourcesController :
|
||||||
NucleusController<MigrationSourcesControllerBinding, MigrationSourcesPresenter>(),
|
NucleusController<MigrationSourcesControllerBinding, MigrationSourcesPresenter>(),
|
||||||
FlexibleAdapter.OnItemClickListener {
|
FlexibleAdapter.OnItemClickListener {
|
||||||
|
|
||||||
|
private val preferences: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
private var adapter: SourceAdapter? = null
|
private var adapter: SourceAdapter? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -56,12 +60,31 @@ class MigrationSourcesController :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (val itemId = item.itemId) {
|
||||||
R.id.action_source_migration_help -> activity?.openInBrowser(HELP_URL)
|
R.id.action_source_migration_help -> activity?.openInBrowser(HELP_URL)
|
||||||
|
R.id.asc_alphabetical, R.id.desc_alphabetical -> {
|
||||||
|
setSortingDirection(SortSetting.ALPHABETICAL, itemId == R.id.asc_alphabetical)
|
||||||
|
}
|
||||||
|
R.id.asc_count, R.id.desc_count -> {
|
||||||
|
setSortingDirection(SortSetting.TOTAL, itemId == R.id.asc_count)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item)
|
return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setSortingDirection(sortSetting: SortSetting, isAscending: Boolean) {
|
||||||
|
val direction = if (isAscending) {
|
||||||
|
DirectionSetting.ASCENDING
|
||||||
|
} else {
|
||||||
|
DirectionSetting.DESCENDING
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences.migrationSortingDirection().set(direction)
|
||||||
|
preferences.migrationSortingMode().set(sortSetting)
|
||||||
|
|
||||||
|
presenter.requestSortUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
fun setSources(sourcesWithManga: List<SourceItem>) {
|
fun setSources(sourcesWithManga: List<SourceItem>) {
|
||||||
// Show empty view if needed
|
// Show empty view if needed
|
||||||
if (sourcesWithManga.isNotEmpty()) {
|
if (sourcesWithManga.isNotEmpty()) {
|
||||||
|
@ -79,6 +102,16 @@ class MigrationSourcesController :
|
||||||
parentController!!.router.pushController(controller.withFadeTransaction())
|
parentController!!.router.pushController(controller.withFadeTransaction())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum class DirectionSetting {
|
||||||
|
ASCENDING,
|
||||||
|
DESCENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class SortSetting {
|
||||||
|
ALPHABETICAL,
|
||||||
|
TOTAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val HELP_URL = "https://tachiyomi.org/help/guides/source-migration/"
|
private const val HELP_URL = "https://tachiyomi.org/help/guides/source-migration/"
|
||||||
|
|
|
@ -1,25 +1,38 @@
|
||||||
package eu.kanade.tachiyomi.ui.browse.migration.sources
|
package eu.kanade.tachiyomi.ui.browse.migration.sources
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import com.jakewharton.rxrelay.BehaviorRelay
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
|
import eu.kanade.tachiyomi.util.lang.combineLatest
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
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 uy.kohesive.injekt.injectLazy
|
||||||
|
import java.text.Collator
|
||||||
|
import java.util.Collections
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class MigrationSourcesPresenter(
|
class MigrationSourcesPresenter(
|
||||||
private val sourceManager: SourceManager = Injekt.get(),
|
private val sourceManager: SourceManager = Injekt.get(),
|
||||||
private val db: DatabaseHelper = Injekt.get()
|
private val db: DatabaseHelper = Injekt.get()
|
||||||
) : BasePresenter<MigrationSourcesController>() {
|
) : BasePresenter<MigrationSourcesController>() {
|
||||||
|
|
||||||
|
private val preferences: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
|
private val sortRelay = BehaviorRelay.create(Unit)
|
||||||
|
|
||||||
override fun onCreate(savedState: Bundle?) {
|
override fun onCreate(savedState: Bundle?) {
|
||||||
super.onCreate(savedState)
|
super.onCreate(savedState)
|
||||||
|
|
||||||
db.getFavoriteMangas()
|
db.getFavoriteMangas()
|
||||||
.asRxObservable()
|
.asRxObservable()
|
||||||
|
.combineLatest(sortRelay.observeOn(Schedulers.io())) { sources, _ -> sources }
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.map { findSourcesWithManga(it) }
|
.map { findSourcesWithManga(it) }
|
||||||
.subscribeLatestCache(MigrationSourcesController::setSources)
|
.subscribeLatestCache(MigrationSourcesController::setSources)
|
||||||
|
@ -34,7 +47,36 @@ class MigrationSourcesPresenter(
|
||||||
val source = sourceManager.getOrStub(it.key)
|
val source = sourceManager.getOrStub(it.key)
|
||||||
SourceItem(source, it.value.size, header)
|
SourceItem(source, it.value.size, header)
|
||||||
}
|
}
|
||||||
.sortedBy { it.source.name.lowercase() }
|
.sortedWith(sortFn())
|
||||||
.toList()
|
.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun sortFn(): java.util.Comparator<SourceItem> {
|
||||||
|
val sort by lazy {
|
||||||
|
preferences.migrationSortingMode().get()
|
||||||
|
}
|
||||||
|
val direction by lazy {
|
||||||
|
preferences.migrationSortingDirection().get()
|
||||||
|
}
|
||||||
|
|
||||||
|
val locale = Locale.getDefault()
|
||||||
|
val collator = Collator.getInstance(locale).apply {
|
||||||
|
strength = Collator.PRIMARY
|
||||||
|
}
|
||||||
|
val sortFn: (SourceItem, SourceItem) -> Int = { a, b ->
|
||||||
|
when (sort) {
|
||||||
|
MigrationSourcesController.SortSetting.ALPHABETICAL -> collator.compare(a.source.name.lowercase(locale), b.source.name.lowercase(locale))
|
||||||
|
MigrationSourcesController.SortSetting.TOTAL -> a.mangaCount.compareTo(b.mangaCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return when (direction) {
|
||||||
|
MigrationSourcesController.DirectionSetting.ASCENDING -> Comparator(sortFn)
|
||||||
|
MigrationSourcesController.DirectionSetting.DESCENDING -> Collections.reverseOrder(sortFn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun requestSortUpdate() {
|
||||||
|
sortRelay.call(Unit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,5 +7,38 @@
|
||||||
android:title="@string/migration_help_guide"
|
android:title="@string/migration_help_guide"
|
||||||
app:iconTint="?attr/colorOnToolbar"
|
app:iconTint="?attr/colorOnToolbar"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sort"
|
||||||
|
android:title="@string/action_sort"
|
||||||
|
app:showAsAction="never">
|
||||||
|
<menu>
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sort_alphabetical"
|
||||||
|
android:title="@string/action_sort_alpha"
|
||||||
|
app:showAsAction="never">
|
||||||
|
<menu>
|
||||||
|
<item
|
||||||
|
android:id="@+id/asc_alphabetical"
|
||||||
|
android:title="@string/action_asc" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/desc_alphabetical"
|
||||||
|
android:title="@string/action_desc" />
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sort_count"
|
||||||
|
android:title="@string/action_sort_count"
|
||||||
|
app:showAsAction="never">
|
||||||
|
<menu>
|
||||||
|
<item
|
||||||
|
android:id="@+id/asc_count"
|
||||||
|
android:title="@string/action_asc" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/desc_count"
|
||||||
|
android:title="@string/action_desc" />
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
<string name="action_filter_unread">Unread</string>
|
<string name="action_filter_unread">Unread</string>
|
||||||
<string name="action_filter_empty">Remove filter</string>
|
<string name="action_filter_empty">Remove filter</string>
|
||||||
<string name="action_sort_alpha">Alphabetically</string>
|
<string name="action_sort_alpha">Alphabetically</string>
|
||||||
|
<string name="action_sort_count">Total manga</string>
|
||||||
<string name="action_sort_total">Total chapters</string>
|
<string name="action_sort_total">Total chapters</string>
|
||||||
<string name="action_sort_last_read">Last read</string>
|
<string name="action_sort_last_read">Last read</string>
|
||||||
<string name="action_sort_last_checked">Last checked</string>
|
<string name="action_sort_last_checked">Last checked</string>
|
||||||
|
|
Reference in a new issue