Merge remote-tracking branch 'upstream/master'

TODO: fix sorting in anime library
This commit is contained in:
jmir1 2021-06-27 01:58:10 +02:00
commit 267b68b7d9
57 changed files with 873 additions and 504 deletions

View file

@ -1,43 +0,0 @@
---
name: "🐞 Bug report"
about: Report a bug
title: "[Bug] <Write short description here>"
labels: "bug"
---
**PLEASE READ THIS**
I acknowledge that:
- I have updated:
- To the latest version of the app
- All extensions
- If this is an issue with an extension, that I should be opening an issue in https://github.com/jmir1/aniyomi-extensions
- I have searched the existing issues and this is new ticket **NOT** a duplicate or related to another open issue
- I will fill out the title and the information in this template
Note that the issue will be automatically closed if you do not fill out the title or requested information.
**DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT**
---
## Device information
* Aniyomi version: ?
* Android version: ?
* Device: ?
## Steps to reproduce
1. First step
2. Second step
### Expected behavior
This should happen.
### Actual behavior
This happened instead.
## Other details
Additional details and attachments.
If you're experiencing crashes, share the crash logs from More → Settings → Advanced → Dump crash logs.

106
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View file

@ -0,0 +1,106 @@
name: 🐞 Bug report
description: Report a bug in Aniyomi
labels: [Bug]
body:
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Read this carefully, we will close and ignore your issue if you skimmed through this.
options:
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.
required: true
- label: I have written a short but informative title.
required: true
- label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/jmir1/aniyomi-extensions/issues/new/choose).
required: true
- label: I have tried the [troubleshooting guide](https://tachiyomi.org/help/guides/troubleshooting/).
required: true
- label: I have updated the app to the **[latest version](https://github.com/jmir1/aniyomi/releases)**.
required: true
- label: I have updated all installed extensions.
required: true
- label: I will fill out all of the requested information in this form.
required: true
- type: input
id: aniyomi-version
attributes:
label: Aniyomi version
description: You can find your Aniyomi version in **More → About**.
placeholder: |
Example: "0.11.1.7"
validations:
required: true
- type: input
id: android-version
attributes:
label: Android version
description: You can find this somewhere in your Android settings.
placeholder: |
Example: "Android 11"
validations:
required: true
- type: input
id: device
attributes:
label: Device
description: List your device and model.
placeholder: |
Example: "Google Pixel 5"
validations:
required: true
- type: textarea
id: reproduce-steps
attributes:
label: Steps to reproduce
description: Provide an example of how to trigger the bug.
placeholder: |
Example:
1. First step
2. Second step
3. Bug occurs
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected behavior
description: Explain what you should expect to happen.
placeholder: |
Example:
"This should happen..."
validations:
required: true
- type: textarea
id: actual-behavior
attributes:
label: Actual behavior
description: Explain what actually happens.
placeholder: |
Example:
"This happened instead..."
validations:
required: true
- type: textarea
id: crash-logs
attributes:
label: Crash logs
description: |
If you're experiencing crashes, share the crash logs from **More → Settings → Advanced** then press **Dump crash logs**.
placeholder: |
You can paste the crash logs in pure text or upload it as an attachment.
- type: textarea
id: other-details
attributes:
label: Other details
placeholder: |
Additional details and attachments.

View file

@ -1,8 +1,11 @@
blank_issues_enabled: false blank_issues_enabled: false
contact_links: contact_links:
- name: Aniyomi help discord - name: ⚠️ Anime extension/source issue
url: https://github.com/jmir1/aniyomi-extensions/issues/new/choose
about: Issues and requests for extensions and sources should be opened in the aniyomi-extensions repository instead.
- name: 📦 Aniyomi extensions
url: https://github.com/jmir1/aniyomi-extensions
about: Anime extensions and sources.
- name: Aniyomi help discord
url: https://discord.gg/F32UjdJZrR url: https://discord.gg/F32UjdJZrR
about: Common questions are answered here. about: Common questions are answered here.
- name: Aniyomi extensions GitHub repository
url: https://github.com/jmir1/aniyomi-extensions
about: Issues about an anime extension/source/catalogue should be opened here instead.

View file

@ -1,29 +0,0 @@
---
name: "🌟 Feature request"
about: Suggest a feature to improve Aniyomi
title: "[Feature Request] <Write short description here>"
labels: "feature"
---
**PLEASE READ THIS**
I acknowledge that:
- I have updated:
- To the latest version of the app
- All extensions
- If this is an issue with an anime extension, that I should be opening an issue in https://github.com/jmir1/aniyomi-extensions
- I have searched the existing issues and this is new ticket **NOT** a duplicate or related to another open issue
- I will fill out the title and the information in this template
Note that the issue will be automatically closed if you do not fill out the title or requested information.
**DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT**
---
## Why/User Benefit/User Problem
(explain why this feature should be added)
## What/Requirements
(explain how this feature would behave)

View file

@ -0,0 +1,39 @@
name: ⭐ Feature request
description: Suggest a feature for Aniyomi
labels: [Feature request]
body:
- type: checkboxes
id: acknowledgements
attributes:
label: Acknowledgements
description: Read this carefully, we will close and ignore your issue if you skimmed through this.
options:
- label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.
required: true
- label: I have written a short but informative title.
required: true
- label: If this is an issue with an extension, I should be opening an issue in the [extensions repository](https://github.com/jmir1/aniyomi-extensions/issues/new/choose).
required: true
- label: I have updated the app to the **[latest version](https://github.com/jmir1/aniyomi/releases)**.
required: true
- label: I will fill out all of the requested information in this form.
required: true
- type: textarea
id: feature-description
attributes:
label: Describe your suggested feature
description: How can an existing extension be improved?
placeholder: |
Example:
"It should work like this..."
validations:
required: true
- type: textarea
id: other-details
attributes:
label: Other details
placeholder: |
Additional details and attachments.

View file

@ -1,8 +0,0 @@
---
name: "Extension/source/catalogue issue"
about: "Do not open an issue here. See https://github.com/jmir1/aniyomi-extensions"
title: "THIS ISSUE IS IN THE WRONG REPO; SEE https://github.com/jmir1/aniyomi-extensions"
labels: "catalog, invalid"
---
DO NOT OPEN AN ISSUE IN THIS REPO. SEE https://github.com/jmir1/aniyomi-extensions

View file

@ -22,7 +22,6 @@ jobs:
build: build:
name: Build app name: Build app
needs: check_wrapper needs: check_wrapper
if: "!startsWith(github.event.head_commit.message, '[SKIP CI]')"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View file

@ -13,16 +13,6 @@ jobs:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
rules: | rules: |
[ [
{
"type": "title",
"regex": ".*THIS ISSUE IS IN THE WRONG REPO.*",
"message": "It was not opened in the correct repo, as the template mentioned."
},
{
"type": "title",
"regex": ".*<Write short description here>*",
"message": "The description in the title was not filled out."
},
{ {
"type": "body", "type": "body",
"regex": ".*DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT.*", "regex": ".*DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT.*",

View file

@ -9,6 +9,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Moderate issues - name: Moderate issues
uses: tachiyomiorg/issue-moderator-action@v1.0 uses: tachiyomiorg/issue-moderator-action@v1.1
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}

View file

@ -221,7 +221,7 @@ dependencies {
implementation("com.github.tachiyomiorg:subsampling-scale-image-view:846abe0") { implementation("com.github.tachiyomiorg:subsampling-scale-image-view:846abe0") {
exclude(module = "image-decoder") exclude(module = "image-decoder")
} }
implementation("com.github.tachiyomiorg:image-decoder:ac5f65c") implementation("com.github.tachiyomiorg:image-decoder:0e91111")
// Logging // Logging
implementation("com.jakewharton.timber:timber:4.7.1") implementation("com.jakewharton.timber:timber:4.7.1")

View file

@ -13,7 +13,10 @@ import eu.kanade.tachiyomi.data.updater.UpdaterJob
import eu.kanade.tachiyomi.extension.AnimeExtensionUpdateJob import eu.kanade.tachiyomi.extension.AnimeExtensionUpdateJob
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
import eu.kanade.tachiyomi.ui.animelib.AnimelibSort
import eu.kanade.tachiyomi.ui.library.LibrarySort import eu.kanade.tachiyomi.ui.library.LibrarySort
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.widget.ExtendedNavigationView import eu.kanade.tachiyomi.widget.ExtendedNavigationView
@ -100,9 +103,15 @@ object Migrations {
} }
if (oldVersion < 44) { if (oldVersion < 44) {
// Reset sorting preference if using removed sort by source // Reset sorting preference if using removed sort by source
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val oldSortingMode = prefs.getInt(PreferenceKeys.librarySortingMode, 0)
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
if (preferences.librarySortingMode().get() == LibrarySort.SOURCE) { if (oldSortingMode == LibrarySort.SOURCE) {
preferences.librarySortingMode().set(LibrarySort.ALPHA) prefs.edit {
putInt(PreferenceKeys.librarySortingMode, LibrarySort.ALPHA)
}
} }
} }
if (oldVersion < 52) { if (oldVersion < 52) {
@ -209,6 +218,65 @@ object Migrations {
LibraryUpdateJob.setupTask(context) LibraryUpdateJob.setupTask(context)
AnimelibUpdateJob.setupTask(context) AnimelibUpdateJob.setupTask(context)
} }
if (oldVersion < 64) {
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
val oldSortingMode = prefs.getInt(PreferenceKeys.librarySortingMode, 0)
val oldSortingDirection = prefs.getBoolean(PreferenceKeys.librarySortingDirection, true)
@Suppress("DEPRECATION")
val newSortingMode = when (oldSortingMode) {
LibrarySort.ALPHA -> SortModeSetting.ALPHABETICAL
LibrarySort.LAST_READ -> SortModeSetting.LAST_READ
LibrarySort.LAST_CHECKED -> SortModeSetting.LAST_CHECKED
LibrarySort.UNREAD -> SortModeSetting.UNREAD
LibrarySort.TOTAL -> SortModeSetting.TOTAL_CHAPTERS
LibrarySort.LATEST_CHAPTER -> SortModeSetting.LATEST_CHAPTER
LibrarySort.CHAPTER_FETCH_DATE -> SortModeSetting.DATE_FETCHED
LibrarySort.DATE_ADDED -> SortModeSetting.DATE_ADDED
else -> SortModeSetting.ALPHABETICAL
}
val newSortingDirection = when (oldSortingDirection) {
true -> SortDirectionSetting.ASCENDING
else -> SortDirectionSetting.DESCENDING
}
val oldSortingModeAnime = prefs.getInt(PreferenceKeys.animelibSortingMode, 0)
val oldSortingDirectionAnime = prefs.getBoolean(PreferenceKeys.animelibSortingDirection, true)
@Suppress("DEPRECATION")
val newSortingModeAnime = when (oldSortingModeAnime) {
AnimelibSort.ALPHA -> SortModeSetting.ALPHABETICAL
AnimelibSort.LAST_READ -> SortModeSetting.LAST_READ
AnimelibSort.LAST_CHECKED -> SortModeSetting.LAST_CHECKED
AnimelibSort.UNREAD -> SortModeSetting.UNREAD
AnimelibSort.TOTAL -> SortModeSetting.TOTAL_CHAPTERS
AnimelibSort.LATEST_CHAPTER -> SortModeSetting.LATEST_CHAPTER
AnimelibSort.CHAPTER_FETCH_DATE -> SortModeSetting.DATE_FETCHED
AnimelibSort.DATE_ADDED -> SortModeSetting.DATE_ADDED
else -> SortModeSetting.ALPHABETICAL
}
val newSortingDirectionAnime = when (oldSortingDirectionAnime) {
true -> SortDirectionSetting.ASCENDING
else -> SortDirectionSetting.DESCENDING
}
prefs.edit(commit = true) {
remove(PreferenceKeys.librarySortingMode)
remove(PreferenceKeys.librarySortingDirection)
remove(PreferenceKeys.animelibSortingMode)
remove(PreferenceKeys.animelibSortingDirection)
}
prefs.edit {
putString(PreferenceKeys.librarySortingMode, newSortingMode.name)
putString(PreferenceKeys.librarySortingDirection, newSortingDirection.name)
putString(PreferenceKeys.animelibSortingMode, newSortingModeAnime.name)
putString(PreferenceKeys.animelibSortingDirection, newSortingDirectionAnime.name)
}
}
return true return true
} }

View file

@ -1,5 +1,8 @@
package eu.kanade.tachiyomi.data.database.models package eu.kanade.tachiyomi.data.database.models
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
import java.io.Serializable import java.io.Serializable
interface Category : Serializable { interface Category : Serializable {
@ -17,16 +20,19 @@ interface Category : Serializable {
} }
var displayMode: Int var displayMode: Int
get() = flags and MASK get() = flags and DisplayModeSetting.MASK
set(mode) = setFlags(mode, MASK) set(mode) = setFlags(mode, DisplayModeSetting.MASK)
var sortMode: Int
get() = flags and SortModeSetting.MASK
set(mode) = setFlags(mode, SortModeSetting.MASK)
var sortDirection: Int
get() = flags and SortDirectionSetting.MASK
set(mode) = setFlags(mode, SortDirectionSetting.MASK)
companion object { companion object {
const val COMPACT_GRID = 0b00000000
const val COMFORTABLE_GRID = 0b00000001
const val LIST = 0b00000010
const val MASK = 0b00000011
fun create(name: String): Category = CategoryImpl().apply { fun create(name: String): Category = CategoryImpl().apply {
this.name = name this.name = name
} }

View file

@ -118,6 +118,7 @@ object PreferenceKeys {
const val lastUsedAnimeCategory = "last_used_anime_category" const val lastUsedAnimeCategory = "last_used_anime_category"
const val sourceDisplayMode = "pref_display_mode_catalogue" const val sourceDisplayMode = "pref_display_mode_catalogue"
const val animesourceDisplayMode = "pref_display_mode_anime_catalogue"
const val enabledLanguages = "source_languages" const val enabledLanguages = "source_languages"
@ -163,8 +164,10 @@ object PreferenceKeys {
const val filterTracked = "pref_filter_library_tracked" const val filterTracked = "pref_filter_library_tracked"
const val librarySortingMode = "library_sorting_mode" const val librarySortingMode = "library_sorting_mode"
const val librarySortingDirection = "library_sorting_ascending"
const val animelibSortingMode = "animelib_sorting_mode" const val animelibSortingMode = "animelib_sorting_mode"
const val animelibSortingDirection = "animelib_sorting_ascending"
const val automaticExtUpdates = "automatic_ext_updates" const val automaticExtUpdates = "automatic_ext_updates"

View file

@ -37,12 +37,6 @@ object PreferenceValues {
/* ktlint-enable experimental:enum-entry-name-case */ /* ktlint-enable experimental:enum-entry-name-case */
enum class DisplayMode {
COMPACT_GRID,
COMFORTABLE_GRID,
LIST,
}
enum class TappingInvertMode(val shouldInvertHorizontal: Boolean = false, val shouldInvertVertical: Boolean = false) { enum class TappingInvertMode(val shouldInvertHorizontal: Boolean = false, val shouldInvertVertical: Boolean = false) {
NONE, NONE,
HORIZONTAL(shouldInvertHorizontal = true), HORIZONTAL(shouldInvertHorizontal = true),

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.data.preference package eu.kanade.tachiyomi.data.preference
import android.content.Context import android.content.Context
import android.content.res.Configuration
import android.os.Environment import android.os.Environment
import androidx.core.content.edit import androidx.core.content.edit
import androidx.core.net.toUri import androidx.core.net.toUri
@ -10,9 +11,12 @@ import com.tfcporciuncula.flow.Preference
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Anime import eu.kanade.tachiyomi.data.database.models.Anime
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode import eu.kanade.tachiyomi.data.preference.PreferenceValues.ThemeMode.*
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.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
import eu.kanade.tachiyomi.widget.ExtendedNavigationView import eu.kanade.tachiyomi.widget.ExtendedNavigationView
@ -85,7 +89,7 @@ class PreferencesHelper(val context: Context) {
fun showLibraryUpdateErrors() = prefs.getBoolean(Keys.showLibraryUpdateErrors, true) fun showLibraryUpdateErrors() = prefs.getBoolean(Keys.showLibraryUpdateErrors, true)
fun themeMode() = flowPrefs.getEnum(Keys.themeMode, Values.ThemeMode.system) fun themeMode() = flowPrefs.getEnum(Keys.themeMode, system)
fun themeLight() = flowPrefs.getEnum(Keys.themeLight, Values.LightThemeVariant.default) fun themeLight() = flowPrefs.getEnum(Keys.themeLight, Values.LightThemeVariant.default)
@ -199,7 +203,8 @@ class PreferencesHelper(val context: Context) {
fun lastVersionCode() = flowPrefs.getInt("last_version_code", 0) fun lastVersionCode() = flowPrefs.getInt("last_version_code", 0)
fun sourceDisplayMode() = flowPrefs.getEnum(Keys.sourceDisplayMode, DisplayMode.COMPACT_GRID) fun sourceDisplayMode() = flowPrefs.getEnum(Keys.sourceDisplayMode, DisplayModeSetting.COMPACT_GRID)
fun animesourceDisplayMode() = flowPrefs.getEnum(Keys.animesourceDisplayMode, DisplayModeSetting.COMPACT_GRID)
fun enabledLanguages() = flowPrefs.getStringSet(Keys.enabledLanguages, setOf("en", Locale.getDefault().language)) fun enabledLanguages() = flowPrefs.getStringSet(Keys.enabledLanguages, setOf("en", Locale.getDefault().language))
@ -255,9 +260,9 @@ class PreferencesHelper(val context: Context) {
fun libraryUpdatePrioritization() = flowPrefs.getInt(Keys.libraryUpdatePrioritization, 0) fun libraryUpdatePrioritization() = flowPrefs.getInt(Keys.libraryUpdatePrioritization, 0)
fun libraryDisplayMode() = flowPrefs.getEnum(Keys.libraryDisplayMode, DisplayMode.COMPACT_GRID) fun libraryDisplayMode() = flowPrefs.getEnum(Keys.libraryDisplayMode, DisplayModeSetting.COMPACT_GRID)
fun animelibDisplayMode() = flowPrefs.getEnum(Keys.animelibDisplayMode, DisplayMode.COMPACT_GRID) fun animelibDisplayMode() = flowPrefs.getEnum(Keys.animelibDisplayMode, DisplayModeSetting.COMPACT_GRID)
fun downloadBadge() = flowPrefs.getBoolean(Keys.downloadBadge, false) fun downloadBadge() = flowPrefs.getBoolean(Keys.downloadBadge, false)
@ -283,13 +288,11 @@ class PreferencesHelper(val context: Context) {
fun filterTracking(name: Int) = flowPrefs.getInt("${Keys.filterTracked}_$name", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) fun filterTracking(name: Int) = flowPrefs.getInt("${Keys.filterTracked}_$name", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
fun librarySortingMode() = flowPrefs.getInt(Keys.librarySortingMode, 0) fun librarySortingMode() = flowPrefs.getEnum(Keys.librarySortingMode, SortModeSetting.ALPHABETICAL)
fun librarySortingAscending() = flowPrefs.getEnum(Keys.librarySortingDirection, SortDirectionSetting.ASCENDING)
fun librarySortingAscending() = flowPrefs.getBoolean("library_sorting_ascending", true) fun animelibSortingMode() = flowPrefs.getEnum(Keys.animelibSortingMode, SortModeSetting.ALPHABETICAL)
fun animelibSortingAscending() = flowPrefs.getEnum(Keys.animelibSortingDirection, SortDirectionSetting.ASCENDING)
fun animelibSortingMode() = flowPrefs.getInt(Keys.animelibSortingMode, 0)
fun animelibSortingAscending() = flowPrefs.getBoolean("animelib_sorting_ascending", true)
fun automaticExtUpdates() = flowPrefs.getBoolean(Keys.automaticExtUpdates, true) fun automaticExtUpdates() = flowPrefs.getBoolean(Keys.automaticExtUpdates, true)
@ -382,7 +385,21 @@ class PreferencesHelper(val context: Context) {
putInt(Keys.defaultEpisodeFilterByBookmarked, anime.bookmarkedFilter) putInt(Keys.defaultEpisodeFilterByBookmarked, anime.bookmarkedFilter)
putInt(Keys.defaultEpisodeSortBySourceOrNumber, anime.sorting) putInt(Keys.defaultEpisodeSortBySourceOrNumber, anime.sorting)
putInt(Keys.defaultEpisodeDisplayByNameOrNumber, anime.displayMode) putInt(Keys.defaultEpisodeDisplayByNameOrNumber, anime.displayMode)
putInt(Keys.defaultEpisodeSortByAscendingOrDescending, if (anime.sortDescending()) Anime.EPISODE_SORT_DESC else Anime.EPISODE_SORT_ASC) putInt(
Keys.defaultEpisodeSortByAscendingOrDescending,
if (anime.sortDescending()) Anime.EPISODE_SORT_DESC else Anime.EPISODE_SORT_ASC
)
}
}
fun isDarkMode(): Boolean {
return when (themeMode().get()) {
light -> false
dark -> true
system -> {
context.applicationContext.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
Configuration.UI_MODE_NIGHT_YES
}
} }
} }
} }

View file

@ -12,7 +12,6 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.animelib.AnimelibUpdateService import eu.kanade.tachiyomi.data.animelib.AnimelibUpdateService
import eu.kanade.tachiyomi.data.database.models.Anime import eu.kanade.tachiyomi.data.database.models.Anime
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.AnimelibCategoryBinding import eu.kanade.tachiyomi.databinding.AnimelibCategoryBinding
import eu.kanade.tachiyomi.util.lang.plusAssign import eu.kanade.tachiyomi.util.lang.plusAssign
@ -28,6 +27,7 @@ import reactivecircus.flowbinding.swiperefreshlayout.refreshes
import rx.subscriptions.CompositeSubscription import rx.subscriptions.CompositeSubscription
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.ArrayDeque import java.util.ArrayDeque
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting as DisplayMode
/** /**
* Fragment containing the animelib anime for a certain category. * Fragment containing the animelib anime for a certain category.
@ -125,7 +125,7 @@ class AnimelibCategoryView @JvmOverloads constructor(context: Context, attrs: At
// If displayMode should be set from category adjust manga count per row // If displayMode should be set from category adjust manga count per row
if (preferences.categorisedDisplaySettings().get()) { if (preferences.categorisedDisplaySettings().get()) {
recycler.spanCount = if (category.displayMode == Category.LIST || (preferences.animelibDisplayMode().get() == DisplayMode.LIST && category.id == 0)) { recycler.spanCount = if (DisplayMode.fromFlag(category.displayMode) == DisplayMode.LIST || (preferences.libraryDisplayMode().get() == DisplayMode.LIST && category.id == 0)) {
1 1
} else { } else {
controller.animePerRow controller.animePerRow

View file

@ -295,6 +295,11 @@ class AnimelibController(
.map { (it.id ?: -1) to (animeMap[it.id]?.size ?: 0) } .map { (it.id ?: -1) to (animeMap[it.id]?.size ?: 0) }
.toMap() .toMap()
if (preferences.categorisedDisplaySettings().get()) {
// Reattach adapter so it doesn't get de-synced
reattachAdapter()
}
// Restore active category. // Restore active category.
binding.libraryPager.setCurrentItem(activeCat, false) binding.libraryPager.setCurrentItem(activeCat, false)

View file

@ -14,9 +14,9 @@ import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.animesource.AnimeSourceManager import eu.kanade.tachiyomi.animesource.AnimeSourceManager
import eu.kanade.tachiyomi.data.database.models.AnimelibAnime import eu.kanade.tachiyomi.data.database.models.AnimelibAnime
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding
import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.widget.AutofitRecyclerView import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -24,7 +24,7 @@ import uy.kohesive.injekt.api.get
class AnimelibItem( class AnimelibItem(
val anime: AnimelibAnime, val anime: AnimelibAnime,
private val shouldSetFromCategory: Preference<Boolean>, private val shouldSetFromCategory: Preference<Boolean>,
private val defaultLibraryDisplayMode: Preference<DisplayMode> private val defaultLibraryDisplayMode: Preference<DisplayModeSetting>
) : ) :
AbstractFlexibleItem<AnimelibHolder<*>>(), IFilterable<String> { AbstractFlexibleItem<AnimelibHolder<*>>(), IFilterable<String> {
@ -35,13 +35,9 @@ class AnimelibItem(
var unreadCount = -1 var unreadCount = -1
var isLocal = false var isLocal = false
private fun getDisplayMode(): DisplayMode { private fun getDisplayMode(): DisplayModeSetting {
return if (shouldSetFromCategory.get() && anime.category != 0) { return if (shouldSetFromCategory.get() && anime.category != 0) {
if (displayMode != -1) { DisplayModeSetting.fromFlag(displayMode)
DisplayMode.values()[displayMode]
} else {
DisplayMode.COMPACT_GRID
}
} else { } else {
defaultLibraryDisplayMode.get() defaultLibraryDisplayMode.get()
} }
@ -49,15 +45,15 @@ class AnimelibItem(
override fun getLayoutRes(): Int { override fun getLayoutRes(): Int {
return when (getDisplayMode()) { return when (getDisplayMode()) {
DisplayMode.COMPACT_GRID -> R.layout.source_compact_grid_item DisplayModeSetting.COMPACT_GRID -> R.layout.source_compact_grid_item
DisplayMode.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item DisplayModeSetting.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item
DisplayMode.LIST -> R.layout.source_list_item DisplayModeSetting.LIST -> R.layout.source_list_item
} }
} }
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): AnimelibHolder<*> { override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): AnimelibHolder<*> {
return when (getDisplayMode()) { return when (getDisplayMode()) {
DisplayMode.COMPACT_GRID -> { DisplayModeSetting.COMPACT_GRID -> {
val binding = SourceCompactGridItemBinding.bind(view) val binding = SourceCompactGridItemBinding.bind(view)
val parent = adapter.recyclerView as AutofitRecyclerView val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4 val coverHeight = parent.itemWidth / 3 * 4
@ -71,7 +67,7 @@ class AnimelibItem(
} }
AnimelibCompactGridHolder(view, adapter) AnimelibCompactGridHolder(view, adapter)
} }
DisplayMode.COMFORTABLE_GRID -> { DisplayModeSetting.COMFORTABLE_GRID -> {
val binding = SourceComfortableGridItemBinding.bind(view) val binding = SourceComfortableGridItemBinding.bind(view)
val parent = adapter.recyclerView as AutofitRecyclerView val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4 val coverHeight = parent.itemWidth / 3 * 4
@ -83,7 +79,7 @@ class AnimelibItem(
} }
AnimelibComfortableGridHolder(view, adapter) AnimelibComfortableGridHolder(view, adapter)
} }
DisplayMode.LIST -> { DisplayModeSetting.LIST -> {
AnimelibListHolder(view, adapter) AnimelibListHolder(view, adapter)
} }
} }

View file

@ -15,6 +15,8 @@ import eu.kanade.tachiyomi.data.download.AnimeDownloadManager
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
import eu.kanade.tachiyomi.util.isLocal import eu.kanade.tachiyomi.util.isLocal
import eu.kanade.tachiyomi.util.lang.combineLatest import eu.kanade.tachiyomi.util.lang.combineLatest
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
@ -98,7 +100,7 @@ class AnimelibPresenter(
lib.copy(animeMap = applyFilters(lib.animeMap, tracks)) lib.copy(animeMap = applyFilters(lib.animeMap, tracks))
} }
.combineLatest(sortTriggerRelay.observeOn(Schedulers.io())) { lib, _ -> .combineLatest(sortTriggerRelay.observeOn(Schedulers.io())) { lib, _ ->
lib.copy(animeMap = applySort(lib.animeMap)) lib.copy(animeMap = applySort(lib.categories, lib.animeMap))
} }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribeLatestCache({ view, (categories, animeMap) -> .subscribeLatestCache({ view, (categories, animeMap) ->
@ -228,9 +230,7 @@ class AnimelibPresenter(
* *
* @param map the map to sort. * @param map the map to sort.
*/ */
private fun applySort(map: AnimelibMap): AnimelibMap { private fun applySort(categories: List<Category>, map: AnimelibMap): AnimelibMap {
val sortingMode = preferences.animelibSortingMode().get()
val lastReadAnime by lazy { val lastReadAnime by lazy {
var counter = 0 var counter = 0
db.getLastSeenAnime().executeAsBlocking().associate { it.id!! to counter++ } db.getLastSeenAnime().executeAsBlocking().associate { it.id!! to counter++ }
@ -248,55 +248,66 @@ class AnimelibPresenter(
db.getEpisodeFetchDateAnime().executeAsBlocking().associate { it.id!! to counter++ } db.getEpisodeFetchDateAnime().executeAsBlocking().associate { it.id!! to counter++ }
} }
val sortAscending = preferences.animelibSortingAscending().get() val sortingModes = categories.associate { category ->
(category.id ?: 0) to SortModeSetting.get(preferences, category)
}
val sortAscending = categories.associate { category ->
(category.id ?: 0) to SortDirectionSetting.get(preferences, category)
}
val sortFn: (AnimelibItem, AnimelibItem) -> Int = { i1, i2 -> val sortFn: (AnimelibItem, AnimelibItem) -> Int = { i1, i2 ->
val sortingMode = sortingModes[i1.anime.category]!!
val sortAscending = sortAscending[i1.anime.category]!! == SortDirectionSetting.ASCENDING
when (sortingMode) { when (sortingMode) {
AnimelibSort.ALPHA -> i1.anime.title.compareTo(i2.anime.title, true) SortModeSetting.ALPHABETICAL -> i1.anime.title.compareTo(i2.anime.title, true)
AnimelibSort.LAST_READ -> { SortModeSetting.LAST_READ -> {
// Get index of anime, set equal to list if size unknown. // Get index of anime, set equal to list if size unknown.
val anime1LastRead = lastReadAnime[i1.anime.id!!] ?: lastReadAnime.size val anime1LastRead = lastReadAnime[i1.anime.id!!] ?: lastReadAnime.size
val anime2LastRead = lastReadAnime[i2.anime.id!!] ?: lastReadAnime.size val anime2LastRead = lastReadAnime[i2.anime.id!!] ?: lastReadAnime.size
anime1LastRead.compareTo(anime2LastRead) anime1LastRead.compareTo(anime2LastRead)
} }
AnimelibSort.LAST_CHECKED -> i2.anime.last_update.compareTo(i1.anime.last_update) SortModeSetting.LAST_CHECKED -> i2.anime.last_update.compareTo(i1.anime.last_update)
AnimelibSort.UNREAD -> when { SortModeSetting.UNREAD -> when {
// Ensure unread content comes first // Ensure unread content comes first
i1.anime.unread == i2.anime.unread -> 0 i1.anime.unread == i2.anime.unread -> 0
i1.anime.unread == 0 -> if (sortAscending) 1 else -1 i1.anime.unread == 0 -> if (sortAscending) 1 else -1
i2.anime.unread == 0 -> if (sortAscending) -1 else 1 i2.anime.unread == 0 -> if (sortAscending) -1 else 1
else -> i1.anime.unread.compareTo(i2.anime.unread) else -> i1.anime.unread.compareTo(i2.anime.unread)
} }
AnimelibSort.TOTAL -> { SortModeSetting.TOTAL_CHAPTERS -> {
val anime1TotalEpisode = totalChapterAnime[i1.anime.id!!] ?: 0 val anime1TotalEpisode = totalChapterAnime[i1.anime.id!!] ?: 0
val mange2TotalEpisode = totalChapterAnime[i2.anime.id!!] ?: 0 val mange2TotalEpisode = totalChapterAnime[i2.anime.id!!] ?: 0
anime1TotalEpisode.compareTo(mange2TotalEpisode) anime1TotalEpisode.compareTo(mange2TotalEpisode)
} }
AnimelibSort.LATEST_CHAPTER -> { SortModeSetting.LATEST_CHAPTER -> {
val anime1latestEpisode = latestChapterAnime[i1.anime.id!!] val anime1latestEpisode = latestChapterAnime[i1.anime.id!!]
?: latestChapterAnime.size ?: latestChapterAnime.size
val anime2latestEpisode = latestChapterAnime[i2.anime.id!!] val anime2latestEpisode = latestChapterAnime[i2.anime.id!!]
?: latestChapterAnime.size ?: latestChapterAnime.size
anime1latestEpisode.compareTo(anime2latestEpisode) anime1latestEpisode.compareTo(anime2latestEpisode)
} }
AnimelibSort.CHAPTER_FETCH_DATE -> { SortModeSetting.DATE_FETCHED -> {
val anime1chapterFetchDate = chapterFetchDateAnime[i1.anime.id!!] val anime1chapterFetchDate = chapterFetchDateAnime[i1.anime.id!!]
?: chapterFetchDateAnime.size ?: chapterFetchDateAnime.size
val anime2chapterFetchDate = chapterFetchDateAnime[i2.anime.id!!] val anime2chapterFetchDate = chapterFetchDateAnime[i2.anime.id!!]
?: chapterFetchDateAnime.size ?: chapterFetchDateAnime.size
anime1chapterFetchDate.compareTo(anime2chapterFetchDate) anime1chapterFetchDate.compareTo(anime2chapterFetchDate)
} }
AnimelibSort.DATE_ADDED -> i2.anime.date_added.compareTo(i1.anime.date_added) SortModeSetting.DATE_ADDED -> i2.anime.date_added.compareTo(i1.anime.date_added)
else -> throw Exception("Unknown sorting mode")
} }
} }
val comparator = if (sortAscending) { return map.mapValues { entry ->
Comparator(sortFn) val sortAscending = sortAscending[entry.key]!! == SortDirectionSetting.ASCENDING
} else {
Collections.reverseOrder(sortFn)
}
return map.mapValues { entry -> entry.value.sortedWith(comparator) } val comparator = if (sortAscending) {
Comparator(sortFn)
} else {
Collections.reverseOrder(sortFn)
}
entry.value.sortedWith(comparator)
}
} }
/** /**

View file

@ -7,10 +7,12 @@ import com.bluelinelabs.conductor.Router
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.AnimeDatabaseHelper import eu.kanade.tachiyomi.data.database.AnimeDatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
import eu.kanade.tachiyomi.widget.ExtendedNavigationView import eu.kanade.tachiyomi.widget.ExtendedNavigationView
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State
import eu.kanade.tachiyomi.widget.sheet.TabbedBottomSheetDialog import eu.kanade.tachiyomi.widget.sheet.TabbedBottomSheetDialog
@ -45,6 +47,8 @@ class AnimelibSettingsSheet(
* @param currentCategory ID of currently shown category * @param currentCategory ID of currently shown category
*/ */
fun show(currentCategory: Category) { fun show(currentCategory: Category) {
sort.currentCategory = currentCategory
sort.adjustDisplaySelection()
display.currentCategory = currentCategory display.currentCategory = currentCategory
display.adjustDisplaySelection() display.adjustDisplaySelection()
super.show() super.show()
@ -158,8 +162,16 @@ class AnimelibSettingsSheet(
inner class Sort @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : inner class Sort @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
Settings(context, attrs) { Settings(context, attrs) {
private val sort = SortGroup()
init { init {
setGroups(listOf(SortGroup())) setGroups(listOf(sort))
}
// Refreshes Display Setting selections
fun adjustDisplaySelection() {
sort.initModels()
sort.items.forEach { adapter.notifyItemChanged(it) }
} }
inner class SortGroup : Group { inner class SortGroup : Group {
@ -179,29 +191,29 @@ class AnimelibSettingsSheet(
override val footer = null override val footer = null
override fun initModels() { override fun initModels() {
val sorting = preferences.animelibSortingMode().get() val sorting = SortModeSetting.get(preferences, currentCategory)
val order = if (preferences.animelibSortingAscending().get()) { val order = if (SortDirectionSetting.get(preferences, currentCategory) == SortDirectionSetting.ASCENDING) {
Item.MultiSort.SORT_ASC Item.MultiSort.SORT_ASC
} else { } else {
Item.MultiSort.SORT_DESC Item.MultiSort.SORT_DESC
} }
alphabetically.state = alphabetically.state =
if (sorting == AnimelibSort.ALPHA) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.ALPHABETICAL) order else Item.MultiSort.SORT_NONE
lastRead.state = lastRead.state =
if (sorting == AnimelibSort.LAST_READ) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.LAST_READ) order else Item.MultiSort.SORT_NONE
lastChecked.state = lastChecked.state =
if (sorting == AnimelibSort.LAST_CHECKED) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.LAST_CHECKED) order else Item.MultiSort.SORT_NONE
unread.state = unread.state =
if (sorting == AnimelibSort.UNREAD) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.UNREAD) order else Item.MultiSort.SORT_NONE
total.state = total.state =
if (sorting == AnimelibSort.TOTAL) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.TOTAL_CHAPTERS) order else Item.MultiSort.SORT_NONE
latestChapter.state = latestChapter.state =
if (sorting == AnimelibSort.LATEST_CHAPTER) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.LATEST_CHAPTER) order else Item.MultiSort.SORT_NONE
chapterFetchDate.state = chapterFetchDate.state =
if (sorting == AnimelibSort.CHAPTER_FETCH_DATE) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.DATE_FETCHED) order else Item.MultiSort.SORT_NONE
dateAdded.state = dateAdded.state =
if (sorting == AnimelibSort.DATE_ADDED) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.DATE_ADDED) order else Item.MultiSort.SORT_NONE
} }
override fun onItemClicked(item: Item) { override fun onItemClicked(item: Item) {
@ -219,23 +231,50 @@ class AnimelibSettingsSheet(
else -> throw Exception("Unknown state") else -> throw Exception("Unknown state")
} }
preferences.animelibSortingMode().set( setSortModePreference(item)
when (item) {
alphabetically -> AnimelibSort.ALPHA setSortDirectionPreference(item)
lastRead -> AnimelibSort.LAST_READ
lastChecked -> AnimelibSort.LAST_CHECKED
unread -> AnimelibSort.UNREAD
total -> AnimelibSort.TOTAL
latestChapter -> AnimelibSort.LATEST_CHAPTER
chapterFetchDate -> AnimelibSort.CHAPTER_FETCH_DATE
dateAdded -> AnimelibSort.DATE_ADDED
else -> throw Exception("Unknown sorting")
}
)
preferences.animelibSortingAscending().set(item.state == Item.MultiSort.SORT_ASC)
item.group.items.forEach { adapter.notifyItemChanged(it) } item.group.items.forEach { adapter.notifyItemChanged(it) }
} }
private fun setSortDirectionPreference(item: Item.MultiStateGroup) {
val flag = if (item.state == Item.MultiSort.SORT_ASC) {
SortDirectionSetting.ASCENDING
} else {
SortDirectionSetting.DESCENDING
}
if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
currentCategory?.sortDirection = flag.flag
db.insertCategory(currentCategory!!).executeAsBlocking()
} else {
preferences.animelibSortingAscending().set(flag)
}
}
private fun setSortModePreference(item: Item) {
val flag = when (item) {
alphabetically -> SortModeSetting.ALPHABETICAL
lastRead -> SortModeSetting.LAST_READ
lastChecked -> SortModeSetting.LAST_CHECKED
unread -> SortModeSetting.UNREAD
total -> SortModeSetting.TOTAL_CHAPTERS
latestChapter -> SortModeSetting.LATEST_CHAPTER
chapterFetchDate -> SortModeSetting.DATE_FETCHED
dateAdded -> SortModeSetting.DATE_ADDED
else -> throw NotImplementedError("Unknown display mode")
}
if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
currentCategory?.sortMode = flag.flag
db.insertCategory(currentCategory!!).executeAsBlocking()
} else {
preferences.animelibSortingMode().set(flag)
}
}
} }
} }
@ -264,11 +303,11 @@ class AnimelibSettingsSheet(
} }
// Gets user preference of currently selected display mode at current category // Gets user preference of currently selected display mode at current category
private fun getDisplayModePreference(): DisplayMode { private fun getDisplayModePreference(): DisplayModeSetting {
return if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) { return if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
DisplayMode.values()[currentCategory?.displayMode ?: 0] DisplayModeSetting.fromFlag(currentCategory?.displayMode)
} else { } else {
preferences.libraryDisplayMode().get() preferences.animelibDisplayMode().get()
} }
} }
@ -300,35 +339,26 @@ class AnimelibSettingsSheet(
} }
// Sets display group selections based on given mode // Sets display group selections based on given mode
fun setGroupSelections(mode: DisplayMode) { fun setGroupSelections(mode: DisplayModeSetting) {
compactGrid.checked = mode == DisplayMode.COMPACT_GRID compactGrid.checked = mode == DisplayModeSetting.COMPACT_GRID
comfortableGrid.checked = mode == DisplayMode.COMFORTABLE_GRID comfortableGrid.checked = mode == DisplayModeSetting.COMFORTABLE_GRID
list.checked = mode == DisplayMode.LIST list.checked = mode == DisplayModeSetting.LIST
} }
private fun setDisplayModePreference(item: ExtendedNavigationView.Item) { private fun setDisplayModePreference(item: ExtendedNavigationView.Item) {
if (preferences.categorisedDisplaySettings() val flag = when (item) {
.get() && currentCategory != null && currentCategory?.id != 0 compactGrid -> DisplayModeSetting.COMPACT_GRID
) { comfortableGrid -> DisplayModeSetting.COMFORTABLE_GRID
val flag = when (item) { list -> DisplayModeSetting.LIST
compactGrid -> Category.COMPACT_GRID else -> throw NotImplementedError("Unknown display mode")
comfortableGrid -> Category.COMFORTABLE_GRID }
list -> Category.LIST
else -> throw NotImplementedError("Unknown display mode")
}
currentCategory?.displayMode = flag if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
currentCategory?.displayMode = flag.flag
db.insertCategory(currentCategory!!).executeAsBlocking() db.insertCategory(currentCategory!!).executeAsBlocking()
} else { } else {
preferences.libraryDisplayMode().set( preferences.animelibDisplayMode().set(flag)
when (item) {
compactGrid -> DisplayMode.COMPACT_GRID
comfortableGrid -> DisplayMode.COMFORTABLE_GRID
list -> DisplayMode.LIST
else -> throw NotImplementedError("Unknown display mode")
}
)
} }
} }
} }

View file

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.ui.animelib package eu.kanade.tachiyomi.ui.animelib
@Deprecated("Deprecated in favor for SortModeSetting")
object AnimelibSort { object AnimelibSort {
const val ALPHA = 0 const val ALPHA = 0

View file

@ -1,14 +1,11 @@
package eu.kanade.tachiyomi.ui.base.activity package eu.kanade.tachiyomi.ui.base.activity
import android.content.res.Configuration.UI_MODE_NIGHT_MASK
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DarkThemeVariant import eu.kanade.tachiyomi.data.preference.PreferenceValues.DarkThemeVariant
import eu.kanade.tachiyomi.data.preference.PreferenceValues.LightThemeVariant import eu.kanade.tachiyomi.data.preference.PreferenceValues.LightThemeVariant
import eu.kanade.tachiyomi.data.preference.PreferenceValues.ThemeMode
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.asImmediateFlow import eu.kanade.tachiyomi.data.preference.asImmediateFlow
import eu.kanade.tachiyomi.util.view.setSecureScreen import eu.kanade.tachiyomi.util.view.setSecureScreen
@ -22,29 +19,7 @@ abstract class BaseThemedActivity : AppCompatActivity() {
val preferences: PreferencesHelper by injectLazy() val preferences: PreferencesHelper by injectLazy()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
val isDarkMode = when (preferences.themeMode().get()) { setTheme(getThemeResourceId(preferences))
ThemeMode.light -> false
ThemeMode.dark -> true
ThemeMode.system -> resources.configuration.uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES
}
val themeId = if (isDarkMode) {
when (preferences.themeDark().get()) {
DarkThemeVariant.default -> R.style.Theme_Tachiyomi_Dark
DarkThemeVariant.blue -> R.style.Theme_Tachiyomi_Dark_Blue
DarkThemeVariant.greenapple -> R.style.Theme_Tachiyomi_Dark_GreenApple
DarkThemeVariant.midnightdusk -> R.style.Theme_Tachiyomi_Dark_MidnightDusk
DarkThemeVariant.amoled -> R.style.Theme_Tachiyomi_Amoled
DarkThemeVariant.hotpink -> R.style.Theme_Tachiyomi_Amoled_HotPink
}
} else {
when (preferences.themeLight().get()) {
LightThemeVariant.default -> R.style.Theme_Tachiyomi_Light
LightThemeVariant.blue -> R.style.Theme_Tachiyomi_Light_Blue
LightThemeVariant.strawberrydaiquiri -> R.style.Theme_Tachiyomi_Light_StrawberryDaiquiri
LightThemeVariant.yotsuba -> R.style.Theme_Tachiyomi_Light_Yotsuba
}
}
setTheme(themeId)
Injekt.get<PreferencesHelper>().incognitoMode() Injekt.get<PreferencesHelper>().incognitoMode()
.asImmediateFlow { .asImmediateFlow {
@ -54,4 +29,26 @@ abstract class BaseThemedActivity : AppCompatActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
} }
companion object {
fun getThemeResourceId(preferences: PreferencesHelper): Int {
return if (preferences.isDarkMode()) {
when (preferences.themeDark().get()) {
DarkThemeVariant.default -> R.style.Theme_Tachiyomi_Dark
DarkThemeVariant.blue -> R.style.Theme_Tachiyomi_Dark_Blue
DarkThemeVariant.greenapple -> R.style.Theme_Tachiyomi_Dark_GreenApple
DarkThemeVariant.midnightdusk -> R.style.Theme_Tachiyomi_Dark_MidnightDusk
DarkThemeVariant.amoled -> R.style.Theme_Tachiyomi_Amoled
DarkThemeVariant.hotpink -> R.style.Theme_Tachiyomi_Amoled_HotPink
}
} else {
when (preferences.themeLight().get()) {
LightThemeVariant.default -> R.style.Theme_Tachiyomi_Light
LightThemeVariant.blue -> R.style.Theme_Tachiyomi_Light_Blue
LightThemeVariant.strawberrydaiquiri -> R.style.Theme_Tachiyomi_Light_StrawberryDaiquiri
LightThemeVariant.yotsuba -> R.style.Theme_Tachiyomi_Light_Yotsuba
}
}
}
}
} }

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.ui.browse.animesource.browse package eu.kanade.tachiyomi.ui.browse.animesource.browse
import android.view.View import android.view.View
import androidx.core.view.isVisible
import coil.clear import coil.clear
import coil.imageLoader import coil.imageLoader
import coil.request.ImageRequest import coil.request.ImageRequest
@ -37,6 +38,12 @@ class AnimeSourceComfortableGridHolder(private val view: View, private val adapt
// Set alpha of thumbnail. // Set alpha of thumbnail.
binding.thumbnail.alpha = if (anime.favorite) 0.3f else 1.0f binding.thumbnail.alpha = if (anime.favorite) 0.3f else 1.0f
// For rounded corners
binding.badges.clipToOutline = true
// Set favorite badge
binding.favoriteText.isVisible = anime.favorite
setImage(anime) setImage(anime)
} }

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.ui.browse.animesource.browse package eu.kanade.tachiyomi.ui.browse.animesource.browse
import android.view.View import android.view.View
import androidx.core.view.isVisible
import coil.clear import coil.clear
import coil.imageLoader import coil.imageLoader
import coil.request.ImageRequest import coil.request.ImageRequest
@ -37,6 +38,12 @@ open class AnimeSourceGridHolder(private val view: View, private val adapter: Fl
// Set alpha of thumbnail. // Set alpha of thumbnail.
binding.thumbnail.alpha = if (anime.favorite) 0.3f else 1.0f binding.thumbnail.alpha = if (anime.favorite) 0.3f else 1.0f
// For rounded corners
binding.badges.clipToOutline = true
// Set favorite badge
binding.favoriteText.isVisible = anime.favorite
setImage(anime) setImage(anime)
} }

View file

@ -12,19 +12,19 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Anime import eu.kanade.tachiyomi.data.database.models.Anime
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding
import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.widget.AutofitRecyclerView import eu.kanade.tachiyomi.widget.AutofitRecyclerView
class AnimeSourceItem(val anime: Anime, private val displayMode: Preference<DisplayMode>) : class AnimeSourceItem(val anime: Anime, private val displayMode: Preference<DisplayModeSetting>) :
AbstractFlexibleItem<AnimeSourceHolder<*>>() { AbstractFlexibleItem<AnimeSourceHolder<*>>() {
override fun getLayoutRes(): Int { override fun getLayoutRes(): Int {
return when (displayMode.get()) { return when (displayMode.get()) {
DisplayMode.COMPACT_GRID -> R.layout.source_compact_grid_item DisplayModeSetting.COMPACT_GRID -> R.layout.source_compact_grid_item
DisplayMode.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item DisplayModeSetting.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item
DisplayMode.LIST -> R.layout.source_list_item DisplayModeSetting.LIST -> R.layout.source_list_item
} }
} }
@ -33,7 +33,7 @@ class AnimeSourceItem(val anime: Anime, private val displayMode: Preference<Disp
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>> adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
): AnimeSourceHolder<*> { ): AnimeSourceHolder<*> {
return when (displayMode.get()) { return when (displayMode.get()) {
DisplayMode.COMPACT_GRID -> { DisplayModeSetting.COMPACT_GRID -> {
val binding = SourceCompactGridItemBinding.bind(view) val binding = SourceCompactGridItemBinding.bind(view)
val parent = adapter.recyclerView as AutofitRecyclerView val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4 val coverHeight = parent.itemWidth / 3 * 4
@ -50,7 +50,7 @@ class AnimeSourceItem(val anime: Anime, private val displayMode: Preference<Disp
} }
AnimeSourceGridHolder(view, adapter) AnimeSourceGridHolder(view, adapter)
} }
DisplayMode.COMFORTABLE_GRID -> { DisplayModeSetting.COMFORTABLE_GRID -> {
val binding = SourceComfortableGridItemBinding.bind(view) val binding = SourceComfortableGridItemBinding.bind(view)
val parent = adapter.recyclerView as AutofitRecyclerView val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4 val coverHeight = parent.itemWidth / 3 * 4
@ -62,7 +62,7 @@ class AnimeSourceItem(val anime: Anime, private val displayMode: Preference<Disp
} }
AnimeSourceComfortableGridHolder(view, adapter) AnimeSourceComfortableGridHolder(view, adapter)
} }
DisplayMode.LIST -> { DisplayModeSetting.LIST -> {
AnimeSourceListHolder(view, adapter) AnimeSourceListHolder(view, adapter)
} }
} }

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.ui.browse.animesource.browse package eu.kanade.tachiyomi.ui.browse.animesource.browse
import android.view.View import android.view.View
import androidx.core.view.isVisible
import coil.clear import coil.clear
import coil.loadAny import coil.loadAny
import coil.transform.RoundedCornersTransformation import coil.transform.RoundedCornersTransformation
@ -40,6 +41,12 @@ class AnimeSourceListHolder(private val view: View, adapter: FlexibleAdapter<*>)
// Set alpha of thumbnail. // Set alpha of thumbnail.
binding.thumbnail.alpha = if (anime.favorite) 0.3f else 1.0f binding.thumbnail.alpha = if (anime.favorite) 0.3f else 1.0f
// For rounded corners
binding.badges.clipToOutline = true
// Set favorite badge
binding.favoriteText.isVisible = anime.favorite
setImage(anime) setImage(anime)
} }

View file

@ -28,7 +28,6 @@ import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
import eu.kanade.tachiyomi.data.database.models.Anime import eu.kanade.tachiyomi.data.database.models.Anime
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.asImmediateFlow import eu.kanade.tachiyomi.data.preference.asImmediateFlow
import eu.kanade.tachiyomi.databinding.SourceControllerBinding import eu.kanade.tachiyomi.databinding.SourceControllerBinding
@ -38,6 +37,7 @@ import eu.kanade.tachiyomi.ui.base.controller.FabController
import eu.kanade.tachiyomi.ui.base.controller.SearchableNucleusController import eu.kanade.tachiyomi.ui.base.controller.SearchableNucleusController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.animesource.globalsearch.GlobalAnimeSearchController import eu.kanade.tachiyomi.ui.browse.animesource.globalsearch.GlobalAnimeSearchController
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.more.MoreController import eu.kanade.tachiyomi.ui.more.MoreController
import eu.kanade.tachiyomi.ui.webview.WebViewActivityAnime import eu.kanade.tachiyomi.ui.webview.WebViewActivityAnime
@ -205,7 +205,7 @@ open class BrowseAnimeSourceController(bundle: Bundle) :
binding.catalogueView.removeView(oldRecycler) binding.catalogueView.removeView(oldRecycler)
} }
val recycler = if (preferences.sourceDisplayMode().get() == DisplayMode.LIST) { val recycler = if (preferences.sourceDisplayMode().get() == DisplayModeSetting.LIST) {
RecyclerView(view.context).apply { RecyclerView(view.context).apply {
id = R.id.recycler id = R.id.recycler
layoutManager = LinearLayoutManager(context) layoutManager = LinearLayoutManager(context)
@ -273,9 +273,9 @@ open class BrowseAnimeSourceController(bundle: Bundle) :
) )
val displayItem = when (preferences.sourceDisplayMode().get()) { val displayItem = when (preferences.sourceDisplayMode().get()) {
DisplayMode.COMPACT_GRID -> R.id.action_compact_grid DisplayModeSetting.COMPACT_GRID -> R.id.action_compact_grid
DisplayMode.COMFORTABLE_GRID -> R.id.action_comfortable_grid DisplayModeSetting.COMFORTABLE_GRID -> R.id.action_comfortable_grid
DisplayMode.LIST -> R.id.action_list DisplayModeSetting.LIST -> R.id.action_list
} }
menu.findItem(displayItem).isChecked = true menu.findItem(displayItem).isChecked = true
} }
@ -297,9 +297,9 @@ open class BrowseAnimeSourceController(bundle: Bundle) :
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.action_search -> expandActionViewFromInteraction = true R.id.action_search -> expandActionViewFromInteraction = true
R.id.action_compact_grid -> setDisplayMode(DisplayMode.COMPACT_GRID) R.id.action_compact_grid -> setDisplayMode(DisplayModeSetting.COMPACT_GRID)
R.id.action_comfortable_grid -> setDisplayMode(DisplayMode.COMFORTABLE_GRID) R.id.action_comfortable_grid -> setDisplayMode(DisplayModeSetting.COMFORTABLE_GRID)
R.id.action_list -> setDisplayMode(DisplayMode.LIST) R.id.action_list -> setDisplayMode(DisplayModeSetting.LIST)
R.id.action_open_in_web_view -> openInWebView() R.id.action_open_in_web_view -> openInWebView()
R.id.action_local_source_help -> openLocalSourceHelpGuide() R.id.action_local_source_help -> openLocalSourceHelpGuide()
} }
@ -446,7 +446,7 @@ open class BrowseAnimeSourceController(bundle: Bundle) :
* *
* @param mode the mode to change to * @param mode the mode to change to
*/ */
private fun setDisplayMode(mode: DisplayMode) { private fun setDisplayMode(mode: DisplayModeSetting) {
val view = view ?: return val view = view ?: return
val adapter = adapter ?: return val adapter = adapter ?: return

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.ui.browse.animesource.globalsearch package eu.kanade.tachiyomi.ui.browse.animesource.globalsearch
import android.view.View import android.view.View
import androidx.core.view.isVisible
import coil.clear import coil.clear
import coil.imageLoader import coil.imageLoader
import coil.request.ImageRequest import coil.request.ImageRequest
@ -36,10 +37,18 @@ class GlobalAnimeSearchCardHolder(view: View, adapter: GlobalAnimeSearchCardAdap
fun bind(anime: Anime) { fun bind(anime: Anime) {
binding.card.clipToOutline = true binding.card.clipToOutline = true
// Set anime title
binding.title.text = anime.title binding.title.text = anime.title
// Set alpha of anime_thumbnail. // Set alpha of anime_thumbnail.
binding.cover.alpha = if (anime.favorite) 0.3f else 1.0f binding.cover.alpha = if (anime.favorite) 0.3f else 1.0f
// For rounded corners
binding.badges.clipToOutline = true
// Set favorite badge
binding.favoriteText.isVisible = anime.favorite
setImage(anime) setImage(anime)
} }

View file

@ -24,7 +24,6 @@ import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.asImmediateFlow import eu.kanade.tachiyomi.data.preference.asImmediateFlow
import eu.kanade.tachiyomi.databinding.SourceControllerBinding import eu.kanade.tachiyomi.databinding.SourceControllerBinding
@ -37,6 +36,7 @@ import eu.kanade.tachiyomi.ui.base.controller.SearchableNucleusController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.more.MoreController import eu.kanade.tachiyomi.ui.more.MoreController
@ -205,7 +205,7 @@ open class BrowseSourceController(bundle: Bundle) :
binding.catalogueView.removeView(oldRecycler) binding.catalogueView.removeView(oldRecycler)
} }
val recycler = if (preferences.sourceDisplayMode().get() == DisplayMode.LIST) { val recycler = if (preferences.sourceDisplayMode().get() == DisplayModeSetting.LIST) {
RecyclerView(view.context).apply { RecyclerView(view.context).apply {
id = R.id.recycler id = R.id.recycler
layoutManager = LinearLayoutManager(context) layoutManager = LinearLayoutManager(context)
@ -273,9 +273,9 @@ open class BrowseSourceController(bundle: Bundle) :
) )
val displayItem = when (preferences.sourceDisplayMode().get()) { val displayItem = when (preferences.sourceDisplayMode().get()) {
DisplayMode.COMPACT_GRID -> R.id.action_compact_grid DisplayModeSetting.COMPACT_GRID -> R.id.action_compact_grid
DisplayMode.COMFORTABLE_GRID -> R.id.action_comfortable_grid DisplayModeSetting.COMFORTABLE_GRID -> R.id.action_comfortable_grid
DisplayMode.LIST -> R.id.action_list DisplayModeSetting.LIST -> R.id.action_list
} }
menu.findItem(displayItem).isChecked = true menu.findItem(displayItem).isChecked = true
} }
@ -297,9 +297,9 @@ open class BrowseSourceController(bundle: Bundle) :
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.action_search -> expandActionViewFromInteraction = true R.id.action_search -> expandActionViewFromInteraction = true
R.id.action_compact_grid -> setDisplayMode(DisplayMode.COMPACT_GRID) R.id.action_compact_grid -> setDisplayMode(DisplayModeSetting.COMPACT_GRID)
R.id.action_comfortable_grid -> setDisplayMode(DisplayMode.COMFORTABLE_GRID) R.id.action_comfortable_grid -> setDisplayMode(DisplayModeSetting.COMFORTABLE_GRID)
R.id.action_list -> setDisplayMode(DisplayMode.LIST) R.id.action_list -> setDisplayMode(DisplayModeSetting.LIST)
R.id.action_open_in_web_view -> openInWebView() R.id.action_open_in_web_view -> openInWebView()
R.id.action_local_source_help -> openLocalSourceHelpGuide() R.id.action_local_source_help -> openLocalSourceHelpGuide()
} }
@ -446,7 +446,7 @@ open class BrowseSourceController(bundle: Bundle) :
* *
* @param mode the mode to change to * @param mode the mode to change to
*/ */
private fun setDisplayMode(mode: DisplayMode) { private fun setDisplayMode(mode: DisplayModeSetting) {
val view = view ?: return val view = view ?: return
val adapter = adapter ?: return val adapter = adapter ?: return

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.ui.browse.source.browse package eu.kanade.tachiyomi.ui.browse.source.browse
import android.view.View import android.view.View
import androidx.core.view.isVisible
import coil.clear import coil.clear
import coil.imageLoader import coil.imageLoader
import coil.request.ImageRequest import coil.request.ImageRequest
@ -37,6 +38,12 @@ class SourceComfortableGridHolder(private val view: View, private val adapter: F
// Set alpha of anime_thumbnail. // Set alpha of anime_thumbnail.
binding.thumbnail.alpha = if (manga.favorite) 0.3f else 1.0f binding.thumbnail.alpha = if (manga.favorite) 0.3f else 1.0f
// For rounded corners
binding.badges.clipToOutline = true
// Set favorite badge
binding.favoriteText.isVisible = manga.favorite
setImage(manga) setImage(manga)
} }

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.ui.browse.source.browse package eu.kanade.tachiyomi.ui.browse.source.browse
import android.view.View import android.view.View
import androidx.core.view.isVisible
import coil.clear import coil.clear
import coil.imageLoader import coil.imageLoader
import coil.request.ImageRequest import coil.request.ImageRequest
@ -37,6 +38,12 @@ open class SourceGridHolder(private val view: View, private val adapter: Flexibl
// Set alpha of anime_thumbnail. // Set alpha of anime_thumbnail.
binding.thumbnail.alpha = if (manga.favorite) 0.3f else 1.0f binding.thumbnail.alpha = if (manga.favorite) 0.3f else 1.0f
// For rounded corners
binding.badges.clipToOutline = true
// Set favorite badge
binding.favoriteText.isVisible = manga.favorite
setImage(manga) setImage(manga)
} }

View file

@ -12,19 +12,19 @@ import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding
import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.widget.AutofitRecyclerView import eu.kanade.tachiyomi.widget.AutofitRecyclerView
class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMode>) : class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayModeSetting>) :
AbstractFlexibleItem<SourceHolder<*>>() { AbstractFlexibleItem<SourceHolder<*>>() {
override fun getLayoutRes(): Int { override fun getLayoutRes(): Int {
return when (displayMode.get()) { return when (displayMode.get()) {
DisplayMode.COMPACT_GRID -> R.layout.source_compact_grid_item DisplayModeSetting.COMPACT_GRID -> R.layout.source_compact_grid_item
DisplayMode.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item DisplayModeSetting.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item
DisplayMode.LIST -> R.layout.source_list_item DisplayModeSetting.LIST -> R.layout.source_list_item
} }
} }
@ -33,7 +33,7 @@ class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMo
adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>> adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>
): SourceHolder<*> { ): SourceHolder<*> {
return when (displayMode.get()) { return when (displayMode.get()) {
DisplayMode.COMPACT_GRID -> { DisplayModeSetting.COMPACT_GRID -> {
val binding = SourceCompactGridItemBinding.bind(view) val binding = SourceCompactGridItemBinding.bind(view)
val parent = adapter.recyclerView as AutofitRecyclerView val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4 val coverHeight = parent.itemWidth / 3 * 4
@ -50,7 +50,7 @@ class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMo
} }
SourceGridHolder(view, adapter) SourceGridHolder(view, adapter)
} }
DisplayMode.COMFORTABLE_GRID -> { DisplayModeSetting.COMFORTABLE_GRID -> {
val binding = SourceComfortableGridItemBinding.bind(view) val binding = SourceComfortableGridItemBinding.bind(view)
val parent = adapter.recyclerView as AutofitRecyclerView val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4 val coverHeight = parent.itemWidth / 3 * 4
@ -62,7 +62,7 @@ class SourceItem(val manga: Manga, private val displayMode: Preference<DisplayMo
} }
SourceComfortableGridHolder(view, adapter) SourceComfortableGridHolder(view, adapter)
} }
DisplayMode.LIST -> { DisplayModeSetting.LIST -> {
SourceListHolder(view, adapter) SourceListHolder(view, adapter)
} }
} }

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.ui.browse.source.browse package eu.kanade.tachiyomi.ui.browse.source.browse
import android.view.View import android.view.View
import androidx.core.view.isVisible
import coil.clear import coil.clear
import coil.loadAny import coil.loadAny
import coil.transform.RoundedCornersTransformation import coil.transform.RoundedCornersTransformation
@ -40,6 +41,12 @@ class SourceListHolder(private val view: View, adapter: FlexibleAdapter<*>) :
// Set alpha of anime_thumbnail. // Set alpha of anime_thumbnail.
binding.thumbnail.alpha = if (manga.favorite) 0.3f else 1.0f binding.thumbnail.alpha = if (manga.favorite) 0.3f else 1.0f
// For rounded corners
binding.badges.clipToOutline = true
// Set favorite badge
binding.favoriteText.isVisible = manga.favorite
setImage(manga) setImage(manga)
} }

View file

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.ui.browse.source.globalsearch package eu.kanade.tachiyomi.ui.browse.source.globalsearch
import android.view.View import android.view.View
import androidx.core.view.isVisible
import coil.clear import coil.clear
import coil.imageLoader import coil.imageLoader
import coil.request.ImageRequest import coil.request.ImageRequest
@ -36,10 +37,18 @@ class GlobalSearchCardHolder(view: View, adapter: GlobalSearchCardAdapter) :
fun bind(manga: Manga) { fun bind(manga: Manga) {
binding.card.clipToOutline = true binding.card.clipToOutline = true
// Set manga title
binding.title.text = manga.title binding.title.text = manga.title
// Set alpha of anime_thumbnail.
// Set alpha of thumbnail.
binding.cover.alpha = if (manga.favorite) 0.3f else 1.0f binding.cover.alpha = if (manga.favorite) 0.3f else 1.0f
// For rounded corners
binding.badges.clipToOutline = true
// Set favorite badge
binding.favoriteText.isVisible = manga.favorite
setImage(manga) setImage(manga)
} }

View file

@ -12,7 +12,6 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.library.LibraryUpdateService import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.LibraryCategoryBinding import eu.kanade.tachiyomi.databinding.LibraryCategoryBinding
import eu.kanade.tachiyomi.util.lang.plusAssign import eu.kanade.tachiyomi.util.lang.plusAssign
@ -28,6 +27,7 @@ import reactivecircus.flowbinding.swiperefreshlayout.refreshes
import rx.subscriptions.CompositeSubscription import rx.subscriptions.CompositeSubscription
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.ArrayDeque import java.util.ArrayDeque
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting as DisplayMode
/** /**
* Fragment containing the library manga for a certain category. * Fragment containing the library manga for a certain category.
@ -125,7 +125,7 @@ class LibraryCategoryView @JvmOverloads constructor(context: Context, attrs: Att
// If displayMode should be set from category adjust manga count per row // If displayMode should be set from category adjust manga count per row
if (preferences.categorisedDisplaySettings().get()) { if (preferences.categorisedDisplaySettings().get()) {
recycler.spanCount = if (category.displayMode == Category.LIST || (preferences.libraryDisplayMode().get() == DisplayMode.LIST && category.id == 0)) { recycler.spanCount = if (DisplayMode.fromFlag(category.displayMode) == DisplayMode.LIST || (preferences.libraryDisplayMode().get() == DisplayMode.LIST && category.id == 0)) {
1 1
} else { } else {
controller.mangaPerRow controller.mangaPerRow

View file

@ -295,6 +295,11 @@ class LibraryController(
.map { (it.id ?: -1) to (mangaMap[it.id]?.size ?: 0) } .map { (it.id ?: -1) to (mangaMap[it.id]?.size ?: 0) }
.toMap() .toMap()
if (preferences.categorisedDisplaySettings().get()) {
// Reattach adapter so it doesn't get de-synced
reattachAdapter()
}
// Restore active category. // Restore active category.
binding.libraryPager.setCurrentItem(activeCat, false) binding.libraryPager.setCurrentItem(activeCat, false)

View file

@ -13,10 +13,10 @@ import eu.davidea.flexibleadapter.items.IFilterable
import eu.davidea.flexibleadapter.items.IFlexible import eu.davidea.flexibleadapter.items.IFlexible
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding
import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.widget.AutofitRecyclerView import eu.kanade.tachiyomi.widget.AutofitRecyclerView
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -24,7 +24,7 @@ import uy.kohesive.injekt.api.get
class LibraryItem( class LibraryItem(
val manga: LibraryManga, val manga: LibraryManga,
private val shouldSetFromCategory: Preference<Boolean>, private val shouldSetFromCategory: Preference<Boolean>,
private val defaultLibraryDisplayMode: Preference<DisplayMode> private val defaultLibraryDisplayMode: Preference<DisplayModeSetting>
) : ) :
AbstractFlexibleItem<LibraryHolder<*>>(), IFilterable<String> { AbstractFlexibleItem<LibraryHolder<*>>(), IFilterable<String> {
@ -35,13 +35,9 @@ class LibraryItem(
var unreadCount = -1 var unreadCount = -1
var isLocal = false var isLocal = false
private fun getDisplayMode(): DisplayMode { private fun getDisplayMode(): DisplayModeSetting {
return if (shouldSetFromCategory.get() && manga.category != 0) { return if (shouldSetFromCategory.get() && manga.category != 0) {
if (displayMode != -1) { DisplayModeSetting.fromFlag(displayMode)
DisplayMode.values()[displayMode]
} else {
DisplayMode.COMPACT_GRID
}
} else { } else {
defaultLibraryDisplayMode.get() defaultLibraryDisplayMode.get()
} }
@ -49,15 +45,15 @@ class LibraryItem(
override fun getLayoutRes(): Int { override fun getLayoutRes(): Int {
return when (getDisplayMode()) { return when (getDisplayMode()) {
DisplayMode.COMPACT_GRID -> R.layout.source_compact_grid_item DisplayModeSetting.COMPACT_GRID -> R.layout.source_compact_grid_item
DisplayMode.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item DisplayModeSetting.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item
DisplayMode.LIST -> R.layout.source_list_item DisplayModeSetting.LIST -> R.layout.source_list_item
} }
} }
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): LibraryHolder<*> { override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): LibraryHolder<*> {
return when (getDisplayMode()) { return when (getDisplayMode()) {
DisplayMode.COMPACT_GRID -> { DisplayModeSetting.COMPACT_GRID -> {
val binding = SourceCompactGridItemBinding.bind(view) val binding = SourceCompactGridItemBinding.bind(view)
val parent = adapter.recyclerView as AutofitRecyclerView val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4 val coverHeight = parent.itemWidth / 3 * 4
@ -71,7 +67,7 @@ class LibraryItem(
} }
LibraryCompactGridHolder(view, adapter) LibraryCompactGridHolder(view, adapter)
} }
DisplayMode.COMFORTABLE_GRID -> { DisplayModeSetting.COMFORTABLE_GRID -> {
val binding = SourceComfortableGridItemBinding.bind(view) val binding = SourceComfortableGridItemBinding.bind(view)
val parent = adapter.recyclerView as AutofitRecyclerView val parent = adapter.recyclerView as AutofitRecyclerView
val coverHeight = parent.itemWidth / 3 * 4 val coverHeight = parent.itemWidth / 3 * 4
@ -83,7 +79,7 @@ class LibraryItem(
} }
LibraryComfortableGridHolder(view, adapter) LibraryComfortableGridHolder(view, adapter)
} }
DisplayMode.LIST -> { DisplayModeSetting.LIST -> {
LibraryListHolder(view, adapter) LibraryListHolder(view, adapter)
} }
} }

View file

@ -15,6 +15,8 @@ import eu.kanade.tachiyomi.source.SourceManager
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.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
import eu.kanade.tachiyomi.util.isLocal import eu.kanade.tachiyomi.util.isLocal
import eu.kanade.tachiyomi.util.lang.combineLatest import eu.kanade.tachiyomi.util.lang.combineLatest
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
@ -98,7 +100,7 @@ class LibraryPresenter(
lib.copy(mangaMap = applyFilters(lib.mangaMap, tracks)) lib.copy(mangaMap = applyFilters(lib.mangaMap, tracks))
} }
.combineLatest(sortTriggerRelay.observeOn(Schedulers.io())) { lib, _ -> .combineLatest(sortTriggerRelay.observeOn(Schedulers.io())) { lib, _ ->
lib.copy(mangaMap = applySort(lib.mangaMap)) lib.copy(mangaMap = applySort(lib.categories, lib.mangaMap))
} }
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribeLatestCache({ view, (categories, mangaMap) -> .subscribeLatestCache({ view, (categories, mangaMap) ->
@ -228,9 +230,7 @@ class LibraryPresenter(
* *
* @param map the map to sort. * @param map the map to sort.
*/ */
private fun applySort(map: LibraryMap): LibraryMap { private fun applySort(categories: List<Category>, map: LibraryMap): LibraryMap {
val sortingMode = preferences.librarySortingMode().get()
val lastReadManga by lazy { val lastReadManga by lazy {
var counter = 0 var counter = 0
db.getLastReadManga().executeAsBlocking().associate { it.id!! to counter++ } db.getLastReadManga().executeAsBlocking().associate { it.id!! to counter++ }
@ -248,55 +248,67 @@ class LibraryPresenter(
db.getChapterFetchDateManga().executeAsBlocking().associate { it.id!! to counter++ } db.getChapterFetchDateManga().executeAsBlocking().associate { it.id!! to counter++ }
} }
val sortAscending = preferences.librarySortingAscending().get() val sortingModes = categories.associate { category ->
(category.id ?: 0) to SortModeSetting.get(preferences, category)
}
val sortAscending = categories.associate { category ->
(category.id ?: 0) to SortDirectionSetting.get(preferences, category)
}
val sortFn: (LibraryItem, LibraryItem) -> Int = { i1, i2 -> val sortFn: (LibraryItem, LibraryItem) -> Int = { i1, i2 ->
val sortingMode = sortingModes[i1.manga.category]!!
val sortAscending = sortAscending[i1.manga.category]!! == SortDirectionSetting.ASCENDING
when (sortingMode) { when (sortingMode) {
LibrarySort.ALPHA -> i1.manga.title.compareTo(i2.manga.title, true) SortModeSetting.ALPHABETICAL -> i1.manga.title.compareTo(i2.manga.title, true)
LibrarySort.LAST_READ -> { SortModeSetting.LAST_READ -> {
// Get index of manga, set equal to list if size unknown. // Get index of manga, set equal to list if size unknown.
val manga1LastRead = lastReadManga[i1.manga.id!!] ?: lastReadManga.size val manga1LastRead = lastReadManga[i1.manga.id!!] ?: lastReadManga.size
val manga2LastRead = lastReadManga[i2.manga.id!!] ?: lastReadManga.size val manga2LastRead = lastReadManga[i2.manga.id!!] ?: lastReadManga.size
manga1LastRead.compareTo(manga2LastRead) manga1LastRead.compareTo(manga2LastRead)
} }
LibrarySort.LAST_CHECKED -> i2.manga.last_update.compareTo(i1.manga.last_update) SortModeSetting.LAST_CHECKED -> i2.manga.last_update.compareTo(i1.manga.last_update)
LibrarySort.UNREAD -> when { SortModeSetting.UNREAD -> when {
// Ensure unread content comes first // Ensure unread content comes first
i1.manga.unread == i2.manga.unread -> 0 i1.manga.unread == i2.manga.unread -> 0
i1.manga.unread == 0 -> if (sortAscending) 1 else -1 i1.manga.unread == 0 -> if (sortAscending) 1 else -1
i2.manga.unread == 0 -> if (sortAscending) -1 else 1 i2.manga.unread == 0 -> if (sortAscending) -1 else 1
else -> i1.manga.unread.compareTo(i2.manga.unread) else -> i1.manga.unread.compareTo(i2.manga.unread)
} }
LibrarySort.TOTAL -> { SortModeSetting.TOTAL_CHAPTERS -> {
val manga1TotalChapter = totalChapterManga[i1.manga.id!!] ?: 0 val manga1TotalChapter = totalChapterManga[i1.manga.id!!] ?: 0
val mange2TotalChapter = totalChapterManga[i2.manga.id!!] ?: 0 val mange2TotalChapter = totalChapterManga[i2.manga.id!!] ?: 0
manga1TotalChapter.compareTo(mange2TotalChapter) manga1TotalChapter.compareTo(mange2TotalChapter)
} }
LibrarySort.LATEST_CHAPTER -> { SortModeSetting.LATEST_CHAPTER -> {
val manga1latestChapter = latestChapterManga[i1.manga.id!!] val manga1latestChapter = latestChapterManga[i1.manga.id!!]
?: latestChapterManga.size ?: latestChapterManga.size
val manga2latestChapter = latestChapterManga[i2.manga.id!!] val manga2latestChapter = latestChapterManga[i2.manga.id!!]
?: latestChapterManga.size ?: latestChapterManga.size
manga1latestChapter.compareTo(manga2latestChapter) manga1latestChapter.compareTo(manga2latestChapter)
} }
LibrarySort.CHAPTER_FETCH_DATE -> { SortModeSetting.DATE_FETCHED -> {
val manga1chapterFetchDate = chapterFetchDateManga[i1.manga.id!!] val manga1chapterFetchDate = chapterFetchDateManga[i1.manga.id!!]
?: chapterFetchDateManga.size ?: chapterFetchDateManga.size
val manga2chapterFetchDate = chapterFetchDateManga[i2.manga.id!!] val manga2chapterFetchDate = chapterFetchDateManga[i2.manga.id!!]
?: chapterFetchDateManga.size ?: chapterFetchDateManga.size
manga1chapterFetchDate.compareTo(manga2chapterFetchDate) manga1chapterFetchDate.compareTo(manga2chapterFetchDate)
} }
LibrarySort.DATE_ADDED -> i2.manga.date_added.compareTo(i1.manga.date_added) SortModeSetting.DATE_ADDED -> i2.manga.date_added.compareTo(i1.manga.date_added)
else -> throw Exception("Unknown sorting mode")
} }
} }
val comparator = if (sortAscending) { return map.mapValues { entry ->
Comparator(sortFn) val sortAscending = sortAscending[entry.key]!! == SortDirectionSetting.ASCENDING
} else {
Collections.reverseOrder(sortFn)
}
return map.mapValues { entry -> entry.value.sortedWith(comparator) } val comparator = if (sortAscending) {
Comparator(sortFn)
} else {
Collections.reverseOrder(sortFn)
}
entry.value.sortedWith(comparator)
}
} }
/** /**

View file

@ -7,10 +7,12 @@ import com.bluelinelabs.conductor.Router
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting
import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting
import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting
import eu.kanade.tachiyomi.widget.ExtendedNavigationView import eu.kanade.tachiyomi.widget.ExtendedNavigationView
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State
import eu.kanade.tachiyomi.widget.sheet.TabbedBottomSheetDialog import eu.kanade.tachiyomi.widget.sheet.TabbedBottomSheetDialog
@ -45,6 +47,8 @@ class LibrarySettingsSheet(
* @param currentCategory ID of currently shown category * @param currentCategory ID of currently shown category
*/ */
fun show(currentCategory: Category) { fun show(currentCategory: Category) {
sort.currentCategory = currentCategory
sort.adjustDisplaySelection()
display.currentCategory = currentCategory display.currentCategory = currentCategory
display.adjustDisplaySelection() display.adjustDisplaySelection()
super.show() super.show()
@ -158,8 +162,16 @@ class LibrarySettingsSheet(
inner class Sort @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : inner class Sort @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
Settings(context, attrs) { Settings(context, attrs) {
private val sort = SortGroup()
init { init {
setGroups(listOf(SortGroup())) setGroups(listOf(sort))
}
// Refreshes Display Setting selections
fun adjustDisplaySelection() {
sort.initModels()
sort.items.forEach { adapter.notifyItemChanged(it) }
} }
inner class SortGroup : Group { inner class SortGroup : Group {
@ -179,29 +191,29 @@ class LibrarySettingsSheet(
override val footer = null override val footer = null
override fun initModels() { override fun initModels() {
val sorting = preferences.librarySortingMode().get() val sorting = SortModeSetting.get(preferences, currentCategory)
val order = if (preferences.librarySortingAscending().get()) { val order = if (SortDirectionSetting.get(preferences, currentCategory) == SortDirectionSetting.ASCENDING) {
Item.MultiSort.SORT_ASC Item.MultiSort.SORT_ASC
} else { } else {
Item.MultiSort.SORT_DESC Item.MultiSort.SORT_DESC
} }
alphabetically.state = alphabetically.state =
if (sorting == LibrarySort.ALPHA) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.ALPHABETICAL) order else Item.MultiSort.SORT_NONE
lastRead.state = lastRead.state =
if (sorting == LibrarySort.LAST_READ) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.LAST_READ) order else Item.MultiSort.SORT_NONE
lastChecked.state = lastChecked.state =
if (sorting == LibrarySort.LAST_CHECKED) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.LAST_CHECKED) order else Item.MultiSort.SORT_NONE
unread.state = unread.state =
if (sorting == LibrarySort.UNREAD) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.UNREAD) order else Item.MultiSort.SORT_NONE
total.state = total.state =
if (sorting == LibrarySort.TOTAL) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.TOTAL_CHAPTERS) order else Item.MultiSort.SORT_NONE
latestChapter.state = latestChapter.state =
if (sorting == LibrarySort.LATEST_CHAPTER) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.LATEST_CHAPTER) order else Item.MultiSort.SORT_NONE
chapterFetchDate.state = chapterFetchDate.state =
if (sorting == LibrarySort.CHAPTER_FETCH_DATE) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.DATE_FETCHED) order else Item.MultiSort.SORT_NONE
dateAdded.state = dateAdded.state =
if (sorting == LibrarySort.DATE_ADDED) order else Item.MultiSort.SORT_NONE if (sorting == SortModeSetting.DATE_ADDED) order else Item.MultiSort.SORT_NONE
} }
override fun onItemClicked(item: Item) { override fun onItemClicked(item: Item) {
@ -219,23 +231,50 @@ class LibrarySettingsSheet(
else -> throw Exception("Unknown state") else -> throw Exception("Unknown state")
} }
preferences.librarySortingMode().set( setSortModePreference(item)
when (item) {
alphabetically -> LibrarySort.ALPHA setSortDirectionPrefernece(item)
lastRead -> LibrarySort.LAST_READ
lastChecked -> LibrarySort.LAST_CHECKED
unread -> LibrarySort.UNREAD
total -> LibrarySort.TOTAL
latestChapter -> LibrarySort.LATEST_CHAPTER
chapterFetchDate -> LibrarySort.CHAPTER_FETCH_DATE
dateAdded -> LibrarySort.DATE_ADDED
else -> throw Exception("Unknown sorting")
}
)
preferences.librarySortingAscending().set(item.state == Item.MultiSort.SORT_ASC)
item.group.items.forEach { adapter.notifyItemChanged(it) } item.group.items.forEach { adapter.notifyItemChanged(it) }
} }
private fun setSortDirectionPrefernece(item: Item.MultiStateGroup) {
val flag = if (item.state == Item.MultiSort.SORT_ASC) {
SortDirectionSetting.ASCENDING
} else {
SortDirectionSetting.DESCENDING
}
if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
currentCategory?.sortDirection = flag.flag
db.insertCategory(currentCategory!!).executeAsBlocking()
} else {
preferences.librarySortingAscending().set(flag)
}
}
private fun setSortModePreference(item: Item) {
val flag = when (item) {
alphabetically -> SortModeSetting.ALPHABETICAL
lastRead -> SortModeSetting.LAST_READ
lastChecked -> SortModeSetting.LAST_CHECKED
unread -> SortModeSetting.UNREAD
total -> SortModeSetting.TOTAL_CHAPTERS
latestChapter -> SortModeSetting.LATEST_CHAPTER
chapterFetchDate -> SortModeSetting.DATE_FETCHED
dateAdded -> SortModeSetting.DATE_ADDED
else -> throw NotImplementedError("Unknown display mode")
}
if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
currentCategory?.sortMode = flag.flag
db.insertCategory(currentCategory!!).executeAsBlocking()
} else {
preferences.librarySortingMode().set(flag)
}
}
} }
} }
@ -264,9 +303,9 @@ class LibrarySettingsSheet(
} }
// Gets user preference of currently selected display mode at current category // Gets user preference of currently selected display mode at current category
private fun getDisplayModePreference(): DisplayMode { private fun getDisplayModePreference(): DisplayModeSetting {
return if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) { return if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
DisplayMode.values()[currentCategory?.displayMode ?: 0] DisplayModeSetting.fromFlag(currentCategory?.displayMode)
} else { } else {
preferences.libraryDisplayMode().get() preferences.libraryDisplayMode().get()
} }
@ -300,33 +339,26 @@ class LibrarySettingsSheet(
} }
// Sets display group selections based on given mode // Sets display group selections based on given mode
fun setGroupSelections(mode: DisplayMode) { fun setGroupSelections(mode: DisplayModeSetting) {
compactGrid.checked = mode == DisplayMode.COMPACT_GRID compactGrid.checked = mode == DisplayModeSetting.COMPACT_GRID
comfortableGrid.checked = mode == DisplayMode.COMFORTABLE_GRID comfortableGrid.checked = mode == DisplayModeSetting.COMFORTABLE_GRID
list.checked = mode == DisplayMode.LIST list.checked = mode == DisplayModeSetting.LIST
} }
private fun setDisplayModePreference(item: Item) { private fun setDisplayModePreference(item: Item) {
if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) { val flag = when (item) {
val flag = when (item) { compactGrid -> DisplayModeSetting.COMPACT_GRID
compactGrid -> Category.COMPACT_GRID comfortableGrid -> DisplayModeSetting.COMFORTABLE_GRID
comfortableGrid -> Category.COMFORTABLE_GRID list -> DisplayModeSetting.LIST
list -> Category.LIST else -> throw NotImplementedError("Unknown display mode")
else -> throw NotImplementedError("Unknown display mode") }
}
currentCategory?.displayMode = flag if (preferences.categorisedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) {
currentCategory?.displayMode = flag.flag
db.insertCategory(currentCategory!!).executeAsBlocking() db.insertCategory(currentCategory!!).executeAsBlocking()
} else { } else {
preferences.libraryDisplayMode().set( preferences.libraryDisplayMode().set(flag)
when (item) {
compactGrid -> DisplayMode.COMPACT_GRID
comfortableGrid -> DisplayMode.COMFORTABLE_GRID
list -> DisplayMode.LIST
else -> throw NotImplementedError("Unknown display mode")
}
)
} }
} }
} }

View file

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.ui.library package eu.kanade.tachiyomi.ui.library
@Deprecated("Deprecated in favor for SortModeSetting")
object LibrarySort { object LibrarySort {
const val ALPHA = 0 const val ALPHA = 0

View file

@ -0,0 +1,16 @@
package eu.kanade.tachiyomi.ui.library.setting
enum class DisplayModeSetting(val flag: Int) {
COMPACT_GRID(0b00000000),
COMFORTABLE_GRID(0b00000001),
LIST(0b00000010);
companion object {
const val MASK = 0b00000011
fun fromFlag(flag: Int?): DisplayModeSetting {
return values()
.find { mode -> mode.flag == flag } ?: COMPACT_GRID
}
}
}

View file

@ -0,0 +1,25 @@
package eu.kanade.tachiyomi.ui.library.setting
import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
enum class SortDirectionSetting(val flag: Int) {
ASCENDING(0b01000000),
DESCENDING(0b00000000);
companion object {
const val MASK = 0b01000000
fun fromFlag(flag: Int?): SortDirectionSetting {
return values().find { mode -> mode.flag == flag } ?: ASCENDING
}
fun get(preferences: PreferencesHelper, category: Category?): SortDirectionSetting {
return if (preferences.categorisedDisplaySettings().get() && category != null && category.id != 0) {
fromFlag(category.sortDirection)
} else {
preferences.librarySortingAscending().get()
}
}
}
}

View file

@ -0,0 +1,32 @@
package eu.kanade.tachiyomi.ui.library.setting
import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
enum class SortModeSetting(val flag: Int) {
ALPHABETICAL(0b00000000),
LAST_READ(0b00000100),
LAST_CHECKED(0b00001000),
UNREAD(0b00001100),
TOTAL_CHAPTERS(0b00010000),
LATEST_CHAPTER(0b00010100),
DATE_FETCHED(0b00011000),
DATE_ADDED(0b00011100);
companion object {
// Mask supports for more sorting flags if necessary
const val MASK = 0b00111100
fun fromFlag(flag: Int?): SortModeSetting {
return values().find { mode -> mode.flag == flag } ?: ALPHABETICAL
}
fun get(preferences: PreferencesHelper, category: Category?): SortModeSetting {
return if (preferences.categorisedDisplaySettings().get() && category != null && category.id != 0) {
fromFlag(category.sortMode)
} else {
preferences.librarySortingMode().get()
}
}
}
}

View file

@ -90,6 +90,8 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val didMigration = if (savedInstanceState == null) Migrations.upgrade(preferences) else false
binding = MainActivityBinding.inflate(layoutInflater) binding = MainActivityBinding.inflate(layoutInflater)
// Do not let the launcher create a new activity http://stackoverflow.com/questions/16283079 // Do not let the launcher create a new activity http://stackoverflow.com/questions/16283079
@ -234,7 +236,7 @@ class MainActivity : BaseViewBindingActivity<MainActivityBinding>() {
preferences.incognitoMode().set(false) preferences.incognitoMode().set(false)
// Show changelog prompt on update // Show changelog prompt on update
if (Migrations.upgrade(preferences) && !BuildConfig.DEBUG) { if (didMigration && !BuildConfig.DEBUG) {
WhatsNewDialogController().showDialog(router) WhatsNewDialogController().showDialog(router)
} }
} }

View file

@ -6,11 +6,13 @@ import android.app.ProgressDialog
import android.content.ClipData import android.content.ClipData
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
import android.graphics.ColorMatrix import android.graphics.ColorMatrix
import android.graphics.ColorMatrixColorFilter import android.graphics.ColorMatrixColorFilter
import android.graphics.Paint import android.graphics.Paint
import android.graphics.drawable.ColorDrawable
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.KeyEvent import android.view.KeyEvent
@ -23,12 +25,14 @@ import android.view.animation.Animation
import android.view.animation.AnimationUtils import android.view.animation.AnimationUtils
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.Toast import android.widget.Toast
import androidx.core.view.ViewCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.setPadding
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.google.android.material.shape.MaterialShapeDrawable
import dev.chrisbanes.insetter.applyInsetter
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
@ -38,6 +42,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.toggle import eu.kanade.tachiyomi.data.preference.toggle
import eu.kanade.tachiyomi.databinding.ReaderActivityBinding import eu.kanade.tachiyomi.databinding.ReaderActivityBinding
import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity
import eu.kanade.tachiyomi.ui.base.activity.BaseThemedActivity
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.AddToLibraryFirst import eu.kanade.tachiyomi.ui.reader.ReaderPresenter.SetAsCoverResult.AddToLibraryFirst
@ -55,12 +60,8 @@ import eu.kanade.tachiyomi.util.storage.getUriCompat
import eu.kanade.tachiyomi.util.system.GLUtil import eu.kanade.tachiyomi.util.system.GLUtil
import eu.kanade.tachiyomi.util.system.hasDisplayCutout import eu.kanade.tachiyomi.util.system.hasDisplayCutout
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.defaultBar
import eu.kanade.tachiyomi.util.view.hideBar
import eu.kanade.tachiyomi.util.view.isDefaultBar
import eu.kanade.tachiyomi.util.view.popupMenu import eu.kanade.tachiyomi.util.view.popupMenu
import eu.kanade.tachiyomi.util.view.setTooltip import eu.kanade.tachiyomi.util.view.setTooltip
import eu.kanade.tachiyomi.util.view.showBar
import eu.kanade.tachiyomi.widget.listener.SimpleAnimationListener import eu.kanade.tachiyomi.widget.listener.SimpleAnimationListener
import eu.kanade.tachiyomi.widget.listener.SimpleSeekBarListener import eu.kanade.tachiyomi.widget.listener.SimpleSeekBarListener
import kotlinx.coroutines.flow.drop import kotlinx.coroutines.flow.drop
@ -129,22 +130,20 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
private var readingModeToast: Toast? = null private var readingModeToast: Toast? = null
private val windowInsetsController by lazy { WindowInsetsControllerCompat(window, binding.root) }
/** /**
* Called when the activity is created. Initializes the presenter and configuration. * Called when the activity is created. Initializes the presenter and configuration.
*/ */
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setTheme( setTheme(BaseThemedActivity.getThemeResourceId(preferences))
when (preferences.readerTheme().get()) {
0 -> R.style.Theme_Reader_Light
2 -> R.style.Theme_Reader_Dark_Grey
else -> R.style.Theme_Reader_Dark
}
)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ReaderActivityBinding.inflate(layoutInflater) binding = ReaderActivityBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
if (presenter.needsInit()) { if (presenter.needsInit()) {
val manga = intent.extras!!.getLong("manga", -1) val manga = intent.extras!!.getLong("manga", -1)
val chapter = intent.extras!!.getLong("chapter", -1) val chapter = intent.extras!!.getLong("chapter", -1)
@ -163,9 +162,10 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
config = ReaderConfig() config = ReaderConfig()
initializeMenu() initializeMenu()
// Avoid status bar showing up on rotation binding.pageNumber.applyInsetter {
window.decorView.setOnSystemUiVisibilityChangeListener { type(navigationBars = true) {
setMenuVisibility(menuVisible, animate = false) margin()
}
} }
// Finish when incognito mode is disabled // Finish when incognito mode is disabled
@ -299,17 +299,15 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
onBackPressed() onBackPressed()
} }
ViewCompat.setOnApplyWindowInsetsListener(binding.readerMenu) { _, insets -> binding.toolbar.applyInsetter {
if (!window.isDefaultBar()) { type(navigationBars = true, statusBars = true) {
val systemInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()) margin(top = true, horizontal = true)
binding.readerMenu.setPadding( }
systemInsets.left, }
systemInsets.top, binding.readerMenuBottom.applyInsetter {
systemInsets.right, type(navigationBars = true) {
systemInsets.bottom margin(bottom = true, horizontal = true)
)
} }
insets
} }
binding.toolbar.setOnClickListener { binding.toolbar.setOnClickListener {
@ -355,6 +353,21 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
initBottomShortcuts() initBottomShortcuts()
val alpha = if (preferences.isDarkMode()) 230 else 242 // 90% dark 95% light
listOf(
binding.toolbarBottom,
binding.leftChapter,
binding.readerSeekbar,
binding.rightChapter
).forEach {
it.background.alpha = alpha
}
val systemBarsColor = (binding.toolbarBottom.background as ColorDrawable).color
window.statusBarColor = systemBarsColor
window.navigationBarColor = systemBarsColor
(binding.toolbar.background as MaterialShapeDrawable).fillColor = ColorStateList.valueOf(systemBarsColor)
// Set initial visibility // Set initial visibility
setMenuVisibility(menuVisible) setMenuVisibility(menuVisible)
} }
@ -475,11 +488,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
fun setMenuVisibility(visible: Boolean, animate: Boolean = true) { fun setMenuVisibility(visible: Boolean, animate: Boolean = true) {
menuVisible = visible menuVisible = visible
if (visible) { if (visible) {
if (preferences.fullscreen().get()) { windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
window.showBar()
} else {
resetDefaultMenuAndBar()
}
binding.readerMenu.isVisible = true binding.readerMenu.isVisible = true
if (animate) { if (animate) {
@ -503,9 +512,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
} }
} else { } else {
if (preferences.fullscreen().get()) { if (preferences.fullscreen().get()) {
window.hideBar() windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
} else {
resetDefaultMenuAndBar()
} }
if (animate) { if (animate) {
@ -529,14 +536,6 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
} }
} }
/**
* Reset menu padding and system bar
*/
private fun resetDefaultMenuAndBar() {
binding.readerMenu.setPadding(0)
window.defaultBar()
}
/** /**
* Called from the presenter when a manga is ready. Used to instantiate the appropriate viewer * Called from the presenter when a manga is ready. Used to instantiate the appropriate viewer
* and the toolbar title. * and the toolbar title.
@ -557,6 +556,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
binding.viewerContainer.removeAllViews() binding.viewerContainer.removeAllViews()
} }
viewer = newViewer viewer = newViewer
updateViewerInset(preferences.fullscreen().get())
binding.viewerContainer.addView(newViewer.getView()) binding.viewerContainer.addView(newViewer.getView())
if (preferences.showReadingMode()) { if (preferences.showReadingMode()) {
@ -811,6 +811,19 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
updateOrientationShortcut(presenter.getMangaOrientationType(resolveDefault = false)) updateOrientationShortcut(presenter.getMangaOrientationType(resolveDefault = false))
} }
/**
* Updates viewer inset depending on fullscreen reader preferences.
*/
fun updateViewerInset(fullscreen: Boolean) {
viewer?.getView()?.applyInsetter {
if (!fullscreen) {
type(navigationBars = true, statusBars = true) {
padding()
}
}
}
}
/** /**
* Class that handles the user preferences of the reader. * Class that handles the user preferences of the reader.
*/ */
@ -831,8 +844,15 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
*/ */
init { init {
preferences.readerTheme().asFlow() preferences.readerTheme().asFlow()
.drop(1) // We only care about updates .onEach {
.onEach { recreate() } binding.readerContainer.setBackgroundResource(
when (preferences.readerTheme().get()) {
0 -> android.R.color.white
2 -> R.color.background_dark
else -> android.R.color.black
}
)
}
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
preferences.showPageNumber().asFlow() preferences.showPageNumber().asFlow()
@ -868,6 +888,13 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
preferences.grayscale().asFlow() preferences.grayscale().asFlow()
.onEach { setGrayscale(it) } .onEach { setGrayscale(it) }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
preferences.fullscreen().asFlow()
.onEach {
WindowCompat.setDecorFitsSystemWindows(window, !it)
updateViewerInset(it)
}
.launchIn(lifecycleScope)
} }
/** /**

View file

@ -54,7 +54,6 @@ import eu.kanade.tachiyomi.util.lang.awaitSingle
import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.withIOContext import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.hideBar
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -109,9 +108,6 @@ class WatcherActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.watcher_activity) setContentView(R.layout.watcher_activity)
window.decorView.setOnSystemUiVisibilityChangeListener {
window.hideBar()
}
playerView = findViewById(R.id.player_view) playerView = findViewById(R.id.player_view)
youTubeDoubleTap = findViewById(R.id.youtube_overlay) youTubeDoubleTap = findViewById(R.id.youtube_overlay)
youTubeDoubleTap youTubeDoubleTap

View file

@ -43,7 +43,6 @@ object ImageUtil {
fun findImageType(stream: InputStream): ImageType? { fun findImageType(stream: InputStream): ImageType? {
try { try {
return when (getImageType(stream)?.format) { return when (getImageType(stream)?.format) {
// TODO: image-decoder library currently doesn't actually detect AVIF yet
Format.Avif -> ImageType.AVIF Format.Avif -> ImageType.AVIF
Format.Gif -> ImageType.GIF Format.Gif -> ImageType.GIF
Format.Heif -> ImageType.HEIF Format.Heif -> ImageType.HEIF

View file

@ -3,32 +3,11 @@ package eu.kanade.tachiyomi.util.view
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import android.os.Build import android.os.Build
import android.view.View
import android.view.Window import android.view.Window
import android.view.WindowManager import android.view.WindowManager
import eu.kanade.tachiyomi.util.system.InternalResourceHelper import eu.kanade.tachiyomi.util.system.InternalResourceHelper
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
fun Window.showBar() {
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
}
fun Window.hideBar() {
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
}
fun Window.defaultBar() {
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
}
fun Window.isDefaultBar() = decorView.systemUiVisibility == View.SYSTEM_UI_FLAG_VISIBLE
/** /**
* Sets navigation bar color to transparent if system's config_navBarNeedsScrim is false, * Sets navigation bar color to transparent if system's config_navBarNeedsScrim is false,
* otherwise it will use the theme navigationBarColor with 70% opacity. * otherwise it will use the theme navigationBarColor with 70% opacity.

View file

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.widget.sheet package eu.kanade.tachiyomi.widget.sheet
import android.content.Context import android.content.Context
import android.content.res.Configuration
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.DisplayMetrics import android.util.DisplayMetrics
@ -10,7 +9,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferenceValues
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.system.displayCompat import eu.kanade.tachiyomi.util.system.displayCompat
import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat
@ -45,16 +43,9 @@ abstract class BaseBottomSheetDialog(context: Context) : BottomSheetDialog(conte
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
window?.setNavigationBarTransparentCompat(context) window?.setNavigationBarTransparentCompat(context)
val isDarkMode = when (Injekt.get<PreferencesHelper>().themeMode().get()) {
PreferenceValues.ThemeMode.light -> false
PreferenceValues.ThemeMode.dark -> true
PreferenceValues.ThemeMode.system ->
context.resources.configuration.uiMode and
Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
}
val bottomSheet = rootView.parent as ViewGroup val bottomSheet = rootView.parent as ViewGroup
var flags = bottomSheet.systemUiVisibility var flags = bottomSheet.systemUiVisibility
flags = if (isDarkMode) { flags = if (Injekt.get<PreferencesHelper>().isDarkMode()) {
flags and View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv() flags and View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.inv()
} else { } else {
flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR flags or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR

View file

@ -38,6 +38,32 @@
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:src="@mipmap/ic_launcher" /> tools:src="@mipmap/ic_launcher" />
<LinearLayout
android:id="@+id/badges"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginTop="4dp"
android:background="@drawable/rounded_rectangle">
<TextView
android:id="@+id/favorite_text"
style="@style/TextAppearance.Regular.Caption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/colorSecondary"
android:maxLines="1"
android:paddingStart="3dp"
android:paddingTop="1dp"
android:paddingEnd="3dp"
android:paddingBottom="1dp"
android:text="@string/in_library"
android:textColor="?attr/colorOnSecondary"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
</FrameLayout> </FrameLayout>
<TextView <TextView

View file

@ -61,7 +61,6 @@
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/colorToolbar"
android:minHeight="?attr/actionBarSize" /> android:minHeight="?attr/actionBarSize" />
<LinearLayout <LinearLayout
@ -147,6 +146,7 @@
</LinearLayout> </LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/toolbar_bottom"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:layout_gravity="bottom" android:layout_gravity="bottom"

View file

@ -84,6 +84,22 @@
tools:text="120" tools:text="120"
tools:visibility="visible" /> tools:visibility="visible" />
<TextView
android:id="@+id/favorite_text"
style="@style/TextAppearance.Regular.Caption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/colorSecondary"
android:maxLines="1"
android:paddingStart="3dp"
android:paddingTop="1dp"
android:paddingEnd="3dp"
android:paddingBottom="1dp"
android:text="@string/in_library"
android:textColor="?attr/colorOnSecondary"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout> </LinearLayout>
<com.google.android.material.progressindicator.CircularProgressIndicator <com.google.android.material.progressindicator.CircularProgressIndicator

View file

@ -83,6 +83,22 @@
tools:text="120" tools:text="120"
tools:visibility="visible" /> tools:visibility="visible" />
<TextView
android:id="@+id/favorite_text"
style="@style/TextAppearance.Regular.Caption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/colorSecondary"
android:maxLines="1"
android:paddingStart="3dp"
android:paddingTop="1dp"
android:paddingEnd="3dp"
android:paddingBottom="1dp"
android:text="@string/in_library"
android:textColor="?attr/colorOnSecondary"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout> </LinearLayout>
<TextView <TextView

View file

@ -97,6 +97,22 @@
tools:text="130" tools:text="130"
tools:visibility="visible" /> tools:visibility="visible" />
<TextView
android:id="@+id/favorite_text"
style="@style/TextAppearance.Regular.Caption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?attr/colorSecondary"
android:maxLines="1"
android:paddingStart="3dp"
android:paddingTop="1dp"
android:paddingEnd="3dp"
android:paddingBottom="1dp"
android:text="@string/in_library"
android:textColor="?attr/colorOnSecondary"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout> </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -53,9 +53,6 @@
<color name="accent_hotpink">#FF3399</color> <color name="accent_hotpink">#FF3399</color>
<color name="ripple_colored_hotpink">#1FFF3399</color> <color name="ripple_colored_hotpink">#1FFF3399</color>
<!-- Reader Theme -->
<color name="reader_toolbar">#242529</color>
<color name="filterColorLight">#FFC107</color> <color name="filterColorLight">#FFC107</color>
<color name="filterColorDark">#FFEB3B</color> <color name="filterColorDark">#FFEB3B</color>
<color name="filterColorAmoled">#FFEB3B</color> <color name="filterColorAmoled">#FFEB3B</color>

View file

@ -219,11 +219,6 @@
</style> </style>
<style name="Widget.Tachiyomi.BasicSwitch" parent="Widget.MaterialComponents.CompoundButton.Switch">
<item name="useMaterialThemeColors">false</item>
</style>
<style name="Widget.Tachiyomi.CircularProgressIndicator.Small" parent="Widget.MaterialComponents.CircularProgressIndicator"> <style name="Widget.Tachiyomi.CircularProgressIndicator.Small" parent="Widget.MaterialComponents.CircularProgressIndicator">
<item name="indicatorSize">16dp</item> <item name="indicatorSize">16dp</item>
<item name="trackThickness">2dp</item> <item name="trackThickness">2dp</item>

View file

@ -39,6 +39,7 @@
<item name="android:navigationBarColor">@color/md_black_1000</item> <item name="android:navigationBarColor">@color/md_black_1000</item>
<item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">@null</item> <item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">@null</item>
<item name="android:enforceNavigationBarContrast" tools:targetApi="Q">false</item> <item name="android:enforceNavigationBarContrast" tools:targetApi="Q">false</item>
<item name="android:enforceStatusBarContrast" tools:targetApi="Q">false</item>
<item name="android:itemTextAppearance">@style/TextAppearance.Widget.Menu</item> <item name="android:itemTextAppearance">@style/TextAppearance.Widget.Menu</item>
<item name="android:backgroundDimAmount">0.32</item> <item name="android:backgroundDimAmount">0.32</item>
<item name="windowActionModeOverlay">true</item> <item name="windowActionModeOverlay">true</item>
@ -174,6 +175,7 @@
<item name="android:navigationBarColor">@color/md_black_1000</item> <item name="android:navigationBarColor">@color/md_black_1000</item>
<item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">@null</item> <item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">@null</item>
<item name="android:enforceNavigationBarContrast" tools:targetApi="Q">false</item> <item name="android:enforceNavigationBarContrast" tools:targetApi="Q">false</item>
<item name="android:enforceStatusBarContrast" tools:targetApi="Q">false</item>
<item name="android:itemTextAppearance">@style/TextAppearance.Widget.Menu</item> <item name="android:itemTextAppearance">@style/TextAppearance.Widget.Menu</item>
<item name="android:backgroundDimAmount">0.32</item> <item name="android:backgroundDimAmount">0.32</item>
<item name="windowActionModeOverlay">true</item> <item name="windowActionModeOverlay">true</item>
@ -298,6 +300,7 @@
<item name="android:statusBarColor">?attr/colorSurface</item> <item name="android:statusBarColor">?attr/colorSurface</item>
<item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">@null</item> <item name="android:navigationBarDividerColor" tools:targetApi="o_mr1">@null</item>
<item name="android:enforceNavigationBarContrast" tools:targetApi="Q">false</item> <item name="android:enforceNavigationBarContrast" tools:targetApi="Q">false</item>
<item name="android:enforceStatusBarContrast" tools:targetApi="Q">false</item>
<item name="android:itemTextAppearance">@style/TextAppearance.Widget.Menu</item> <item name="android:itemTextAppearance">@style/TextAppearance.Widget.Menu</item>
<item name="android:backgroundDimAmount">0.32</item> <item name="android:backgroundDimAmount">0.32</item>
<item name="windowActionModeOverlay">true</item> <item name="windowActionModeOverlay">true</item>
@ -349,64 +352,6 @@
<item name="colorControlHighlight">@color/ripple_colored_hotpink</item> <item name="colorControlHighlight">@color/ripple_colored_hotpink</item>
</style> </style>
<!--===============-->
<!-- Reader Themes -->
<!--===============-->
<!--== Light Reader base ==-->
<style name="Theme.Base.Reader.Light" parent="Theme.Base.Light">
<!-- Theme colors -->
<item name="colorSurface">@color/md_white_1000</item>
<item name="colorToolbar">@color/reader_toolbar</item>
<item name="colorOnToolbar">@color/md_white_1000</item>
<!-- Base background/text colors -->
<item name="android:colorBackground">@color/md_white_1000</item>
<item name="android:statusBarColor">?attr/colorToolbar</item>
<item name="android:navigationBarColor">?attr/colorToolbar</item>
<!-- Themes -->
<item name="toolbarStyle">@style/Widget.Tachiyomi.Toolbar.Primary</item>
<item name="switchStyle">@style/Widget.Tachiyomi.BasicSwitch</item>
<item name="bottomSheetDialogTheme">@style/ThemeOverlay.Tachiyomi.BottomSheetDialog</item>
<item name="android:alertDialogTheme">@style/ThemeOverlay.Tachiyomi.MaterialAlertDialog</item>
</style>
<!--== Light Reader ==-->
<style name="Theme.Reader.Light" parent="Theme.Base.Reader.Light" />
<!--== Dark Reader base ==-->
<style name="Theme.Base.Reader.Dark" parent="Theme.Base.Dark">
<!-- Theme colors -->
<item name="colorSurface">@color/md_black_1000</item>
<item name="colorToolbar">@color/reader_toolbar</item>
<!-- Base background/text colors -->
<item name="android:colorBackground">@color/md_black_1000</item>
<item name="android:statusBarColor">?attr/colorToolbar</item>
<item name="android:navigationBarColor">?attr/colorToolbar</item>
<!-- Themes -->
<item name="switchStyle">@style/Widget.Tachiyomi.BasicSwitch</item>
<item name="bottomSheetDialogTheme">@style/ThemeOverlay.Tachiyomi.BottomSheetDialog</item>
<item name="android:alertDialogTheme">@style/ThemeOverlay.Tachiyomi.MaterialAlertDialog</item>
</style>
<!--== Dark Reader ==-->
<style name="Theme.Reader.Dark" parent="Theme.Base.Reader.Dark" />
<!--== Dark Grey Reader ==-->
<style name="Theme.Reader.Dark.Grey" parent="Theme.Base.Reader.Dark">
<!-- Theme colors -->
<item name="colorSurface">@color/background_dark</item>
<!-- Base background/text colors -->
<item name="android:colorBackground">@color/background_dark</item>
<!-- Alert Dialog -->
<item name="android:alertDialogTheme">@style/ThemeOverlay.Tachiyomi.MaterialAlertDialog</item>
</style>
<!--===============--> <!--===============-->
<!-- Launch Screen --> <!-- Launch Screen -->
<!--===============--> <!--===============-->