feat (ui): showing source icon in library (#261)

* showing source icon in library

* Change language icon for local source from Folder to Globe

* adjust size & padding for icon & badge

* Setting enable/disable source icon
This commit is contained in:
Tran M. Cuong 2024-08-19 12:50:16 +07:00 committed by GitHub
parent 49e1759a05
commit 29eeccad1b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 142 additions and 4 deletions

View file

@ -34,6 +34,7 @@ import tachiyomi.domain.library.model.LibrarySort
import tachiyomi.domain.library.model.sort
import tachiyomi.domain.library.service.LibraryPreferences
import tachiyomi.i18n.MR
import tachiyomi.i18n.kmk.KMR
import tachiyomi.i18n.sy.SYMR
import tachiyomi.presentation.core.components.CheckboxItem
import tachiyomi.presentation.core.components.HeadingItem
@ -311,6 +312,12 @@ private fun ColumnScope.DisplayPage(
label = stringResource(MR.strings.action_display_language_badge),
pref = screenModel.libraryPreferences.languageBadge(),
)
// KMK -->
CheckboxItem(
label = stringResource(KMR.strings.action_display_source_badge),
pref = screenModel.libraryPreferences.sourceBadge(),
)
// KMK <--
CheckboxItem(
label = stringResource(MR.strings.action_display_show_continue_reading_button),
pref = screenModel.libraryPreferences.showContinueReadingButton(),

View file

@ -1,13 +1,23 @@
package eu.kanade.presentation.library.components
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.height
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Warning
import androidx.compose.material.icons.outlined.Folder
import androidx.compose.material.icons.outlined.Language
import androidx.compose.material.icons.outlined.LocalLibrary
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import eu.kanade.domain.source.model.icon
import eu.kanade.presentation.theme.TachiyomiPreviewTheme
import tachiyomi.domain.source.model.Source
import tachiyomi.presentation.core.components.Badge
import tachiyomi.source.local.isLocal
@Composable
internal fun DownloadsBadge(count: Long) {
@ -34,7 +44,7 @@ internal fun LanguageBadge(
) {
if (isLocal) {
Badge(
imageVector = Icons.Outlined.Folder,
imageVector = Icons.Outlined.Language,
color = MaterialTheme.colorScheme.tertiary,
iconColor = MaterialTheme.colorScheme.onTertiary,
)
@ -47,6 +57,46 @@ internal fun LanguageBadge(
}
}
// KMK -->
@Composable
fun SourceIconBadge(
source: Source?,
) {
if (source == null) return
val icon = source.icon
when {
source.isStub && icon == null -> {
Badge(
imageVector = Icons.Filled.Warning,
iconColor = MaterialTheme.colorScheme.error,
)
}
icon != null -> {
Badge(
imageBitmap = icon,
modifier = Modifier.scale(1.3f).height(18.dp),
)
}
source.isLocal() -> {
Badge(
imageVector = Icons.Outlined.Folder,
color = MaterialTheme.colorScheme.tertiary,
iconColor = MaterialTheme.colorScheme.onTertiary,
)
}
else -> {
// Default source icon (if source doesn't have an icon)
Badge(
imageVector = Icons.Outlined.LocalLibrary,
color = MaterialTheme.colorScheme.tertiary,
iconColor = MaterialTheme.colorScheme.onTertiary,
)
}
}
}
// KMK <--
@PreviewLightDark
@Composable
private fun BadgePreview() {

View file

@ -53,6 +53,9 @@ internal fun LibraryComfortableGrid(
isLocal = libraryItem.isLocal,
sourceLanguage = libraryItem.sourceLanguage,
)
// KMK -->
SourceIconBadge(source = libraryItem.source)
// KMK <--
},
onLongClick = { onLongClick(libraryItem.libraryManga) },
onClick = { onClick(libraryItem.libraryManga) },

View file

@ -54,6 +54,9 @@ internal fun LibraryCompactGrid(
isLocal = libraryItem.isLocal,
sourceLanguage = libraryItem.sourceLanguage,
)
// KMK -->
SourceIconBadge(source = libraryItem.source)
// KMK <--
},
onLongClick = { onLongClick(libraryItem.libraryManga) },
onClick = { onClick(libraryItem.libraryManga) },

View file

@ -61,6 +61,9 @@ internal fun LibraryList(
isLocal = libraryItem.isLocal,
sourceLanguage = libraryItem.sourceLanguage,
)
// KMK -->
SourceIconBadge(source = libraryItem.source)
// KMK <--
},
onLongClick = { onLongClick(libraryItem.libraryManga) },
onClick = { onClick(libraryItem.libraryManga) },

View file

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.library
import eu.kanade.tachiyomi.source.getNameForMangaInfo
import tachiyomi.domain.library.model.LibraryManga
import tachiyomi.domain.source.model.Source
import tachiyomi.domain.source.service.SourceManager
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -12,6 +13,9 @@ data class LibraryItem(
val unreadCount: Long = -1,
val isLocal: Boolean = false,
val sourceLanguage: String = "",
// KMK -->
val source: Source? = null,
// KMK <--
private val sourceManager: SourceManager = Injekt.get(),
) {
/**

View file

@ -107,6 +107,7 @@ import tachiyomi.domain.manga.model.CustomMangaInfo
import tachiyomi.domain.manga.model.Manga
import tachiyomi.domain.manga.model.MangaUpdate
import tachiyomi.domain.manga.model.applyFilter
import tachiyomi.domain.source.model.StubSource
import tachiyomi.domain.source.service.SourceManager
import tachiyomi.domain.track.interactor.GetTracks
import tachiyomi.domain.track.interactor.GetTracksPerManga
@ -118,6 +119,7 @@ import tachiyomi.source.local.isLocal
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.Collections
import tachiyomi.domain.source.model.Source as DomainSource
/**
* Typealias for the library manga, using the category as keys, and list of manga as values.
@ -498,6 +500,9 @@ class LibraryScreenModel(
// SY -->
libraryPreferences.filterLewd().changes(),
// SY <--
// KMK -->
libraryPreferences.sourceBadge().changes(),
// KMK <--
) {
ItemPreferences(
downloadBadge = it[0] as Boolean,
@ -514,6 +519,9 @@ class LibraryScreenModel(
// SY -->
filterLewd = it[11] as TriState,
// SY <--
// KMK -->
sourceBadge = it[12] as Boolean,
// KMK <--
)
}
}
@ -530,6 +538,9 @@ class LibraryScreenModel(
libraryMangaList
.map { libraryManga ->
// Display mode based on user preference: take it from global library setting or category
// KMK -->
val source = sourceManager.getOrStub(libraryManga.manga.source)
// KMK <--
LibraryItem(
libraryManga,
downloadCount = if (prefs.downloadBadge) {
@ -548,10 +559,23 @@ class LibraryScreenModel(
unreadCount = libraryManga.unreadCount,
isLocal = if (prefs.localBadge) libraryManga.manga.isLocal() else false,
sourceLanguage = if (prefs.languageBadge) {
sourceManager.getOrStub(libraryManga.manga.source).lang
source.lang
} else {
""
},
// KMK -->
source = if (prefs.sourceBadge) {
DomainSource(
source.id,
source.lang,
source.name,
supportsLatest = false,
isStub = source is StubSource
)
} else {
null
},
// KMK <--
)
}
.groupBy { it.libraryManga.category }
@ -1312,6 +1336,9 @@ class LibraryScreenModel(
val downloadBadge: Boolean,
val localBadge: Boolean,
val languageBadge: Boolean,
// KMK -->
val sourceBadge: Boolean,
// KMK <--
val skipOutsideReleasePeriod: Boolean,
val globalFilterDownloaded: Boolean,

View file

@ -127,7 +127,11 @@ class LibraryPreferences(
fun localBadge() = preferenceStore.getBoolean("display_local_badge", true)
fun languageBadge() = preferenceStore.getBoolean("display_language_badge", false)
fun languageBadge() = preferenceStore.getBoolean("display_language_badge", true)
// KMK -->
fun sourceBadge() = preferenceStore.getBoolean("display_source_badge", true)
// KMK <--
fun newShowUpdatesCount() = preferenceStore.getBoolean("library_show_updates_count", true)
fun newUpdatesCount() = preferenceStore.getInt(Preference.appStateKey("library_unseen_updates_count"), 0)

View file

@ -40,6 +40,7 @@
<!-- Library section -->
<string name="pref_show_updating_progress_banner">Show updating progress banner</string>
<string name="action_display_source_badge">Source icon</string>
<!-- Extension section -->
<string name="ext_unofficial">Unofficial</string>

View file

@ -1,8 +1,11 @@
package tachiyomi.presentation.core.components
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.appendInlineContent
@ -10,9 +13,12 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.vector.ImageVector
@ -29,7 +35,12 @@ fun BadgeGroup(
shape: Shape = MaterialTheme.shapes.extraSmall,
content: @Composable RowScope.() -> Unit,
) {
Row(modifier = modifier.clip(shape)) {
Row(
modifier = modifier.clip(shape)
// KMK -->
.height(18.dp),
// KMK <--
) {
content()
}
}
@ -99,3 +110,28 @@ fun Badge(
style = MaterialTheme.typography.bodySmall,
)
}
// KMK -->
@Composable
fun Badge(
imageBitmap: ImageBitmap,
modifier: Modifier = Modifier,
color: Color = MaterialTheme.colorScheme.secondary,
tint: Color? = null,
shape: Shape = RectangleShape,
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.clip(shape)
.background(color),
) {
Image(
bitmap = imageBitmap,
colorFilter = tint?.let { ColorFilter.tint(it) },
contentDescription = null,
modifier = modifier,
)
}
}
// KMK <--