首页优化
This commit is contained in:
1 parent
dd1c62f0f0
commit
0dfb3788e8
3 files changed
+51
-13
No files matched your search
@@ -295,7 +295,7 @@ object EmbyRepository {
|
||||
limit: Int = 6,
|
||||
): EmbyLibraryPage = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
val url = "${server.fullUrl}/emby/Users/${server.userId}/Items?ParentId=$libraryId&SortBy=$sortBy&SortOrder=$sortOrder&StartIndex=${startIndex.coerceAtLeast(0)}&Limit=${limit.coerceAtLeast(1)}&IncludeItemTypes=Movie,Series&Fields=PrimaryImageAspectRatio,Overview,ProductionYear,Genres,RecursiveChildCount,ChildCount,DateCreated,RunTimeTicks,UserData&Recursive=true"
|
||||
val url = "${server.fullUrl}/emby/Users/${server.userId}/Items?ParentId=$libraryId&SortBy=$sortBy&SortOrder=$sortOrder&StartIndex=${startIndex.coerceAtLeast(0)}&Limit=${limit.coerceAtLeast(1)}&IncludeItemTypes=Movie,Series&Fields=PrimaryImageAspectRatio,Overview,ProductionYear,Genres,RecursiveChildCount,ChildCount,DateCreated,RunTimeTicks,UserData,CommunityRating,OfficialRating&Recursive=true"
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.header("X-Emby-Token", server.apiKey)
|
||||
|
||||
@@ -490,9 +490,17 @@ private fun MediaPoster(
|
||||
ImageRequest.Builder(context).data(it).crossfade(true).build()
|
||||
}
|
||||
}
|
||||
val subtitle = listOfNotNull(
|
||||
item.communityRating?.takeIf { it > 0.0 }?.let { "★ ${String.format("%.1f", it)}" },
|
||||
item.productionYear?.let { "$it" },
|
||||
).takeIf { it.isNotEmpty() }?.joinToString(" ")
|
||||
|
||||
LumaMediaCard(
|
||||
model = imageRequest,
|
||||
title = item.seriesName ?: item.name,
|
||||
subtitle = subtitle,
|
||||
subtitleColor = homeSecondaryColor(),
|
||||
subtitleStarColor = LumaColors.ratingStar,
|
||||
modifier = modifier.width(115.dp),
|
||||
imageAspectRatio = 115f / 165f,
|
||||
titleColor = homeContentColor(),
|
||||
@@ -590,6 +598,7 @@ private fun LazyLibrarySection(
|
||||
refreshToken: Int,
|
||||
onItemClick: (EmbyItem) -> Unit = {},
|
||||
onViewAll: () -> Unit = {},
|
||||
onEmpty: () -> Unit = {},
|
||||
) {
|
||||
val cacheKey = remember(activeServer.id, activeServer.fullUrl, activeServer.userId) {
|
||||
homeCacheKey(activeServer)
|
||||
@@ -616,6 +625,7 @@ private fun LazyLibrarySection(
|
||||
EmbyLibraryPage()
|
||||
}.also { loaded ->
|
||||
HomeContentCache.putLibraryPage(cacheKey, folder.id, loaded)
|
||||
if (loaded.items.isEmpty()) onEmpty()
|
||||
}
|
||||
}
|
||||
// Fetch accurate episode counts for series items (parallel)
|
||||
@@ -637,7 +647,7 @@ private fun LazyLibrarySection(
|
||||
}
|
||||
}
|
||||
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
SectionTitle(title = folder.name, count = page?.totalCount ?: 0, onMoreClick = onViewAll)
|
||||
val list = page?.items
|
||||
if (list == null) {
|
||||
@@ -676,13 +686,12 @@ private fun SectionTitle(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(text = title, color = homeContentColor(), fontSize = 18.sp, fontWeight = FontWeight.Bold)
|
||||
Text(text = title, color = homeContentColor(), fontSize = 15.sp, fontWeight = FontWeight.Bold)
|
||||
if (count > 0) {
|
||||
Box(
|
||||
Modifier
|
||||
.heightIn(min = 48.dp)
|
||||
.clickable(onClick = { onMoreClick?.invoke() })
|
||||
.padding(horizontal = 8.dp),
|
||||
.padding(horizontal = 8.dp, vertical = 4.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(
|
||||
@@ -698,7 +707,7 @@ private fun SectionTitle(
|
||||
|
||||
@Composable
|
||||
private fun MyMediaGrid(libraries: List<EmbyMediaFolder>, serverUrl: String, onSelect: (EmbyMediaFolder) -> Unit) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
SectionTitle(title = stringResource(Res.string.section_library))
|
||||
LazyRow(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
items(libraries, key = { it.id }) { folder ->
|
||||
@@ -898,6 +907,7 @@ fun HomeScreen(
|
||||
var reloadToken by remember(homeKey) { mutableIntStateOf(0) }
|
||||
var showResourceStats by remember(homeKey) { mutableStateOf(false) }
|
||||
var serverMenuVisible by remember(homeKey) { mutableStateOf(false) }
|
||||
val emptyLibraries = remember(homeKey) { mutableStateMapOf<String, Boolean>() }
|
||||
var serverMenuMounted by remember(homeKey) { mutableStateOf(false) }
|
||||
var serverAnchorBounds by remember { mutableStateOf<Rect?>(null) }
|
||||
var homeRootOrigin by remember { mutableStateOf(Offset.Zero) }
|
||||
@@ -1064,8 +1074,8 @@ fun HomeScreen(
|
||||
|
||||
if (resumeItems.isNotEmpty()) {
|
||||
item(key = "resume", contentType = "resume") {
|
||||
HomeSection(first = true) {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
HomeSection {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
SectionTitle(title = stringResource(Res.string.continue_watching))
|
||||
LazyRow(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
items(resumeItems, key = { it.id }) { item ->
|
||||
@@ -1081,7 +1091,7 @@ fun HomeScreen(
|
||||
|
||||
if (libraries.isNotEmpty()) {
|
||||
item(key = "media", contentType = "media") {
|
||||
HomeSection(first = resumeItems.isEmpty()) {
|
||||
HomeSection {
|
||||
MyMediaGrid(libraries, server.fullUrl) { folder ->
|
||||
onViewAll(server.id, folder.id, folder.name)
|
||||
}
|
||||
@@ -1089,7 +1099,8 @@ fun HomeScreen(
|
||||
}
|
||||
}
|
||||
|
||||
items(libraries, key = { "library_${it.id}" }, contentType = { "library" }) { folder ->
|
||||
val visibleLibraries = libraries.filter { emptyLibraries[it.id] != true }
|
||||
items(visibleLibraries, key = { "library_${it.id}" }, contentType = { "library" }) { folder ->
|
||||
HomeSection {
|
||||
LazyLibrarySection(
|
||||
folder = folder,
|
||||
@@ -1097,12 +1108,13 @@ fun HomeScreen(
|
||||
refreshToken = reloadToken,
|
||||
onItemClick = { onOpenDetail(it.id) },
|
||||
onViewAll = { onViewAll(server.id, folder.id, folder.name) },
|
||||
onEmpty = { emptyLibraries[folder.id] = true },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
item(key = "stats", contentType = "stats") {
|
||||
HomeSection(first = resumeItems.isEmpty() && libraries.isEmpty()) {
|
||||
HomeSection {
|
||||
ResourceStatsCard(
|
||||
stats = resourceStats,
|
||||
onClick = { showResourceStats = true },
|
||||
@@ -1172,12 +1184,12 @@ fun HomeScreen(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun HomeSection(first: Boolean = false, content: @Composable () -> Unit) {
|
||||
private fun HomeSection(content: @Composable () -> Unit) {
|
||||
Box(
|
||||
Modifier.fillMaxWidth().padding(
|
||||
start = LumaSpacing.md,
|
||||
end = LumaSpacing.md,
|
||||
top = if (first) LumaSpacing.md else LumaSpacing.xl,
|
||||
top = LumaSpacing.md,
|
||||
),
|
||||
) {
|
||||
content()
|
||||
|
||||
@@ -192,6 +192,9 @@ fun LumaMediaCard(
|
||||
titleSize: TextUnit = LumaTypography.body,
|
||||
titleWeight: FontWeight = FontWeight.Medium,
|
||||
titleSpacing: Dp = LumaSpacing.xs,
|
||||
subtitle: String? = null,
|
||||
subtitleColor: Color = titleColor.copy(alpha = 0.6f),
|
||||
subtitleStarColor: Color = subtitleColor,
|
||||
progress: Float? = null,
|
||||
onClick: (() -> Unit)? = null,
|
||||
overlay: @Composable BoxScope.() -> Unit = {},
|
||||
@@ -283,6 +286,29 @@ fun LumaMediaCard(
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
if (!subtitle.isNullOrBlank()) {
|
||||
val parts = subtitle.split(" ", limit = 2)
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = parts[0],
|
||||
color = subtitleStarColor,
|
||||
fontSize = (titleSize.value - 1).sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
if (parts.size > 1) {
|
||||
Text(
|
||||
text = " ${parts[1]}",
|
||||
color = subtitleColor,
|
||||
fontSize = (titleSize.value - 1).sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user