瀏覽代碼

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
Andreas 3 年之前
父節點
當前提交
ba8abd94a8

+ 3 - 0
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt

@@ -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"

+ 4 - 0
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt

@@ -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)

+ 34 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrationSourcesController.kt

@@ -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/"

+ 43 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/sources/MigrationSourcesPresenter.kt

@@ -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)
+    }
 }
 }

+ 33 - 0
app/src/main/res/menu/browse_migrate.xml

@@ -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>

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -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>