1.修复界面无数据状态下的显示问题

This commit is contained in:
beyond committed 2026-08-26 16:22:49 +08:00
1 parent 668a4f8274
commit 24c493f448
36 files changed
+387 -329

No files matched your search

+1 -3
View File
@@ -1,3 +1 @@
# lumaplayer # LumaPlayer
播放器
+1 -1
View File
@@ -12,7 +12,7 @@ android {
minSdk = 24 minSdk = 24
targetSdk = 36 targetSdk = 36
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.0.0"
} }
buildTypes { buildTypes {
@@ -172,7 +172,7 @@ fun MainApp() {
Column(Modifier.fillMaxSize().layerBackdrop(glassBackdrop)) { Column(Modifier.fillMaxSize().layerBackdrop(glassBackdrop)) {
when (selectedTab) { when (selectedTab) {
0 -> Spacer(Modifier.height(0.dp)) 0 -> Spacer(Modifier.height(0.dp))
1 -> RecordsTopBar(recordsSegment) { recordsSegment = it } 1 -> Spacer(Modifier.height(0.dp))
2 -> LibraryTopBar( 2 -> LibraryTopBar(
isGrid = libraryIsGrid, isGrid = libraryIsGrid,
onViewToggle = { libraryIsGrid = !libraryIsGrid }, onViewToggle = { libraryIsGrid = !libraryIsGrid },
@@ -220,7 +220,7 @@ fun MainApp() {
SettingsTopBar() SettingsTopBar()
} }
} }
4 -> SearchTopBar(searchQuery, { searchQuery = it }, { }) 4 -> Spacer(Modifier.height(0.dp))
} }
Box(Modifier.weight(1f)) { Box(Modifier.weight(1f)) {
@@ -230,7 +230,7 @@ fun MainApp() {
selected = selectedServer, selected = selectedServer,
onDetailVisibilityChanged = { homeDetailVisible = it }, onDetailVisibilityChanged = { homeDetailVisible = it },
) )
1 -> RecordsScreen(segment = recordsSegment) 1 -> RecordsScreen(segment = recordsSegment, onSelect = { recordsSegment = it })
2 -> LibraryScreen( 2 -> LibraryScreen(
servers = servers, servers = servers,
selectedServer = selectedServer, selectedServer = selectedServer,
@@ -305,7 +305,7 @@ fun MainApp() {
onOpenAbout = { showAboutDetail = true }, onOpenAbout = { showAboutDetail = true },
onBackFromAbout = { showAboutDetail = false }, onBackFromAbout = { showAboutDetail = false },
) )
4 -> SearchScreen(query = searchQuery) 4 -> SearchScreen(query = searchQuery, onQueryChange = { searchQuery = it }, onGearClick = { })
} }
} }
} }
@@ -575,7 +575,7 @@ private fun MyMediaGrid(libraries: List<EmbyMediaFolder>, serverUrl: String, onS
/* ---- Empty State ---- */ /* ---- Empty State ---- */
@Composable @Composable
private fun EmptyHomeState() { private fun EmptyHomeState() {
Column(Modifier.fillMaxWidth().padding(vertical = 80.dp), horizontalAlignment = Alignment.CenterHorizontally) { Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
Box(Modifier.size(64.dp).clip(CircleShape).background(homeSecondaryColor().copy(alpha = 0.16f)), contentAlignment = Alignment.Center) { Box(Modifier.size(64.dp).clip(CircleShape).background(homeSecondaryColor().copy(alpha = 0.16f)), contentAlignment = Alignment.Center) {
Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null, tint = homeSecondaryColor(), modifier = Modifier.size(32.dp)) Icon(imageVector = Icons.Filled.PlayArrow, contentDescription = null, tint = homeSecondaryColor(), modifier = Modifier.size(32.dp))
} }
@@ -663,7 +663,11 @@ fun HomeScreen(
verticalArrangement = Arrangement.spacedBy(0.dp), verticalArrangement = Arrangement.spacedBy(0.dp),
) { ) {
if (activeServer == null) { if (activeServer == null) {
item { EmptyHomeState() } item {
Box(Modifier.fillParentMaxSize(), contentAlignment = Alignment.Center) {
EmptyHomeState()
}
}
} else if (loading) { } else if (loading) {
item { item {
Column( Column(
@@ -811,3 +815,4 @@ private fun HomeOverlayTopBar(
@@ -45,6 +45,8 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.CompositionLocalProvider
import com.example.myapplication.ui.AppLanguage
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@@ -684,6 +686,9 @@ private fun IconLibraryCard(
@Composable @Composable
private fun IconLibraryDetailDialog(library: IconLibrary, onDismiss: () -> Unit) { private fun IconLibraryDetailDialog(library: IconLibrary, onDismiss: () -> Unit) {
Dialog(onDismissRequest = onDismiss) { Dialog(onDismissRequest = onDismiss) {
val dialogCtx = LocalContext.current
val localizedCtx = remember(AppLanguage.language) { AppLanguage.getLocalizedContext(dialogCtx) }
CompositionLocalProvider(LocalContext provides localizedCtx) {
Box( Box(
Modifier Modifier
.width(340.dp) .width(340.dp)
@@ -772,6 +777,7 @@ private fun IconLibraryDetailDialog(library: IconLibrary, onDismiss: () -> Unit)
) { Text("\u5173\u95ED", color = GlassTokens.subtext, fontSize = 15.sp, fontWeight = FontWeight.Medium) } ) { Text("\u5173\u95ED", color = GlassTokens.subtext, fontSize = 15.sp, fontWeight = FontWeight.Medium) }
} }
} }
}
} }
} }
@@ -940,6 +946,9 @@ private fun AddIconLibraryDialog(
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
Dialog(onDismissRequest = onDismiss) { Dialog(onDismissRequest = onDismiss) {
val dialogCtx = LocalContext.current
val localizedCtx = remember(AppLanguage.language) { AppLanguage.getLocalizedContext(dialogCtx) }
CompositionLocalProvider(LocalContext provides localizedCtx) {
Box( Box(
Modifier Modifier
.width(320.dp) .width(320.dp)
@@ -1134,6 +1143,7 @@ private fun AddIconLibraryDialog(
} }
} }
} }
}
} }
} }
@@ -1165,6 +1175,9 @@ private fun IconPickerDialog(server: EmbyServer, onDismiss: () -> Unit, onPick:
} }
Dialog(onDismissRequest = onDismiss) { Dialog(onDismissRequest = onDismiss) {
val dialogCtx = LocalContext.current
val localizedCtx = remember(AppLanguage.language) { AppLanguage.getLocalizedContext(dialogCtx) }
CompositionLocalProvider(LocalContext provides localizedCtx) {
Box( Box(
Modifier Modifier
.width(320.dp) .width(320.dp)
@@ -1348,6 +1361,7 @@ private fun IconPickerDialog(server: EmbyServer, onDismiss: () -> Unit, onPick:
) { Text(text = "\u5173\u95ED", color = GlassTokens.subtext, fontSize = 15.sp, fontWeight = FontWeight.Medium) } ) { Text(text = "\u5173\u95ED", color = GlassTokens.subtext, fontSize = 15.sp, fontWeight = FontWeight.Medium) }
} }
} }
}
} }
} }
@@ -2,28 +2,20 @@ package com.example.myapplication.screens
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@@ -31,12 +23,11 @@ import com.example.myapplication.R as Res
import top.yukonga.miuix.kmp.basic.Text import top.yukonga.miuix.kmp.basic.Text
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.CalendarMonth import androidx.compose.material.icons.outlined.CalendarMonth
import com.example.myapplication.model.sampleMovies import androidx.compose.material.icons.outlined.FavoriteBorder
import com.example.myapplication.ui.GlassTokens import com.example.myapplication.ui.GlassTokens
import com.example.myapplication.ui.bottomBarContentPadding
import com.example.myapplication.ui.LiquidGlassTopBar import com.example.myapplication.ui.LiquidGlassTopBar
import com.example.myapplication.ui.PosterBox
import com.example.myapplication.ui.SegmentedControl import com.example.myapplication.ui.SegmentedControl
import com.example.myapplication.ui.bottomBarContentPadding
@Composable @Composable
fun RecordsTopBar( fun RecordsTopBar(
@@ -62,52 +53,70 @@ fun RecordsTopBar(
} }
@Composable @Composable
fun RecordsScreen(segment: Int) { fun RecordsScreen(
if (segment == 1) { segment: Int,
Box( onSelect: (Int) -> Unit = {},
Modifier.fillMaxSize().padding(top = 40.dp), ) {
contentAlignment = Alignment.TopCenter, val bottomPadding = bottomBarContentPadding(90.dp).calculateBottomPadding()
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Box(
Modifier.size(64.dp).clip(CircleShape)
.background(GlassTokens.glassFill)
.border(1.dp, GlassTokens.glassBorder, CircleShape),
contentAlignment = Alignment.Center,
) {
androidx.compose.material3.Icon(
imageVector = Icons.Outlined.CalendarMonth,
contentDescription = null,
tint = GlassTokens.subtext2,
modifier = Modifier.size(30.dp),
)
}
Text(text = stringResource(Res.string.no_updates), color = GlassTokens.subtext, fontSize = 15.sp)
}
}
} else {
val favorites = sampleMovies().take(6)
LazyVerticalGrid(
columns = GridCells.Fixed(2),
modifier = Modifier.fillMaxSize().padding(horizontal = 16.dp),
contentPadding = PaddingValues(top = 16.dp, bottom = bottomBarContentPadding(86.dp).calculateBottomPadding()),
verticalArrangement = Arrangement.spacedBy(12.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
) {
items(favorites) { item ->
Box(Modifier.fillMaxWidth()) {
PosterBox(
colors = item.posterColors,
title = item.title,
subtitle = item.subtitle,
height = 200.dp,
)
}
}
}
}
}
Box(Modifier.fillMaxSize()) {
// Content area (full size, same as HomeScreen)
Box(
Modifier.fillMaxSize().padding(bottom = bottomPadding),
contentAlignment = Alignment.Center,
) {
if (segment == 1) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
Modifier.size(64.dp).clip(CircleShape)
.background(GlassTokens.glassFill)
.border(1.dp, GlassTokens.glassBorder, CircleShape),
contentAlignment = Alignment.Center,
) {
androidx.compose.material3.Icon(
imageVector = Icons.Outlined.CalendarMonth,
contentDescription = null,
tint = GlassTokens.subtext2,
modifier = Modifier.size(32.dp),
)
}
Spacer(Modifier.height(16.dp))
Text(text = stringResource(Res.string.no_updates), color = GlassTokens.subtext, fontSize = 15.sp)
Spacer(Modifier.height(6.dp))
Text(text = stringResource(Res.string.empty_calendar_sub), color = GlassTokens.subtext, fontSize = 12.sp)
}
} else {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(
Modifier.size(64.dp).clip(CircleShape)
.background(GlassTokens.glassFill)
.border(1.dp, GlassTokens.glassBorder, CircleShape),
contentAlignment = Alignment.Center,
) {
androidx.compose.material3.Icon(
imageVector = Icons.Outlined.FavoriteBorder,
contentDescription = null,
tint = GlassTokens.subtext2,
modifier = Modifier.size(32.dp),
)
}
Spacer(Modifier.height(16.dp))
Text(text = stringResource(Res.string.empty_favorites), color = GlassTokens.subtext, fontSize = 15.sp)
Spacer(Modifier.height(6.dp))
Text(text = stringResource(Res.string.empty_favorites_sub), color = GlassTokens.subtext, fontSize = 12.sp)
}
}
}
// Overlay top bar (same pattern as HomeScreen)
RecordsTopBar(
selected = segment,
onSelect = onSelect,
modifier = Modifier.align(Alignment.TopCenter),
)
}
}
@@ -6,26 +6,21 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
@@ -59,7 +54,7 @@ fun SearchTopBar(
GlassSearchField( GlassSearchField(
value = query, value = query,
onValueChange = onQueryChange, onValueChange = onQueryChange,
placeholder = stringResource(Res.string.search_hint), placeholder = stringResource(Res.string.search_hint),
onGearClick = onGearClick, onGearClick = onGearClick,
) )
} }
@@ -67,7 +62,11 @@ fun SearchTopBar(
} }
@Composable @Composable
fun SearchScreen(query: String) { fun SearchScreen(
query: String,
onQueryChange: (String) -> Unit = {},
onGearClick: () -> Unit = {},
) {
val allMedia: List<MediaItem> = sampleMovies() + sampleTvShows() val allMedia: List<MediaItem> = sampleMovies() + sampleTvShows()
val results = remember(query) { val results = remember(query) {
val q = query.trim() val q = query.trim()
@@ -76,71 +75,80 @@ fun SearchScreen(query: String) {
} }
} }
Column( val bottomPadding = bottomBarContentPadding(90.dp).calculateBottomPadding()
Modifier
.fillMaxSize() Box(Modifier.fillMaxSize()) {
.padding(horizontal = 16.dp, vertical = 16.dp), // Content area (full size, same as HomeScreen)
) { Box(
if (query.isBlank()) { Modifier
Box( .fillMaxSize()
Modifier .padding(horizontal = 16.dp)
.fillMaxSize() .padding(bottom = bottomPadding),
.padding(top = 80.dp), ) {
contentAlignment = Alignment.TopCenter, if (query.isBlank()) {
) { Box(
Column( Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally, contentAlignment = Alignment.Center,
verticalArrangement = Arrangement.spacedBy(10.dp),
) { ) {
Box( Column(
Modifier horizontalAlignment = Alignment.CenterHorizontally,
.size(72.dp)
.clip(CircleShape)
.background(GlassTokens.glassFill)
.border(1.dp, GlassTokens.glassBorder, CircleShape),
contentAlignment = Alignment.Center,
) { ) {
androidx.compose.material3.Icon( Box(
imageVector = Icons.Outlined.Search, Modifier
contentDescription = null, .size(64.dp)
tint = GlassTokens.subtext2, .clip(CircleShape)
modifier = Modifier.size(34.dp), .background(GlassTokens.glassFill)
) .border(1.dp, GlassTokens.glassBorder, CircleShape),
contentAlignment = Alignment.Center,
) {
androidx.compose.material3.Icon(
imageVector = Icons.Outlined.Search,
contentDescription = null,
tint = GlassTokens.subtext2,
modifier = Modifier.size(32.dp),
)
}
Spacer(Modifier.height(16.dp))
Text(text = stringResource(Res.string.search_title), color = GlassTokens.text, fontSize = 15.sp, fontWeight = FontWeight.SemiBold)
Spacer(Modifier.height(6.dp))
Text(text = stringResource(Res.string.search_empty_input), color = GlassTokens.subtext, fontSize = 12.sp)
} }
Text(text = stringResource(Res.string.search_title), color = GlassTokens.text, fontSize = 16.sp, fontWeight = FontWeight.SemiBold)
Text(text = stringResource(Res.string.search_empty_input), color = GlassTokens.subtext, fontSize = 13.sp)
} }
} } else if (results.isEmpty()) {
} else if (results.isEmpty()) { Box(
Box( Modifier.fillMaxSize(),
Modifier contentAlignment = Alignment.Center,
.fillMaxSize() ) {
.padding(top = 80.dp), Text(text = stringResource(Res.string.search_no_result_prefix) + "$query" + stringResource(Res.string.search_no_result_suffix), color = GlassTokens.subtext, fontSize = 14.sp)
contentAlignment = Alignment.TopCenter, }
) { } else {
Text(text = stringResource(Res.string.search_no_result_prefix) + "$query" + stringResource(Res.string.search_no_result_suffix), color = GlassTokens.subtext, fontSize = 14.sp) LazyVerticalGrid(
} columns = GridCells.Fixed(2),
} else { modifier = Modifier.fillMaxSize(),
LazyVerticalGrid( contentPadding = PaddingValues(bottom = bottomBarContentPadding(86.dp).calculateBottomPadding()),
columns = GridCells.Fixed(2), verticalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.fillMaxSize(), horizontalArrangement = Arrangement.spacedBy(12.dp),
contentPadding = PaddingValues(bottom = bottomBarContentPadding(86.dp).calculateBottomPadding()), ) {
verticalArrangement = Arrangement.spacedBy(12.dp), items(results) { item ->
horizontalArrangement = Arrangement.spacedBy(12.dp), Box(Modifier.fillMaxWidth()) {
) { PosterBox(
items(results) { item -> colors = item.posterColors,
Box(Modifier.fillMaxWidth()) { title = item.title,
PosterBox( subtitle = item.subtitle,
colors = item.posterColors, height = 190.dp,
title = item.title, )
subtitle = item.subtitle, }
height = 190.dp,
)
} }
} }
} }
} }
// Overlay top bar (same pattern as HomeScreen)
SearchTopBar(
query = query,
onQueryChange = onQueryChange,
onGearClick = onGearClick,
modifier = Modifier.align(Alignment.TopCenter),
)
} }
} }
@@ -54,6 +54,14 @@ object AppLanguage {
return context as? Activity return context as? Activity
} }
fun getLocalizedContext(context: Context): Context {
val tag = if (language == 0) "zh-CN" else "en"
val locale = java.util.Locale.forLanguageTag(tag)
val config = android.content.res.Configuration(context.resources.configuration)
config.setLocale(locale)
return context.createConfigurationContext(config)
}
private fun preferences(context: Context): SharedPreferences { private fun preferences(context: Context): SharedPreferences {
return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) return context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
} }
@@ -40,6 +40,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
@@ -936,6 +938,9 @@ fun GlassDialog(
content: @Composable () -> Unit, content: @Composable () -> Unit,
) { ) {
Dialog(onDismissRequest = onDismissRequest) { Dialog(onDismissRequest = onDismissRequest) {
val dialogCtx = LocalContext.current
val localizedCtx = remember(AppLanguage.language) { AppLanguage.getLocalizedContext(dialogCtx) }
CompositionLocalProvider(LocalContext provides localizedCtx) {
Box( Box(
modifier modifier
.width(IntrinsicSize.Min) .width(IntrinsicSize.Min)
@@ -953,6 +958,7 @@ fun GlassDialog(
) { ) {
content() content()
} }
}
} }
} }
@@ -4,167 +4,15 @@
android:height="108dp" android:height="108dp"
android:viewportWidth="108" android:viewportWidth="108"
android:viewportHeight="108"> android:viewportHeight="108">
<!-- Dark purple-blue gradient background -->
<path <path
android:fillColor="#3DDC84" android:fillColor="#FF191932"
android:pathData="M0,0h108v108h-108z" /> android:pathData="M0,0h108v108h-108z" />
<!-- Subtle inner glow -->
<path <path
android:fillColor="#00000000" android:fillColor="#1A321946"
android:pathData="M9,0L9,108" android:pathData="M54,54m-36,0a36,36 0,1 1,72 0a36,36 0,1 1,-72 0" />
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector> </vector>
@@ -1,30 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp" android:width="108dp"
android:height="108dp" android:height="108dp"
android:viewportWidth="108" android:viewportWidth="108"
android:viewportHeight="108"> android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor"> <!-- White play circle centered at (54,54), radius 22dp -->
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path <path
android:fillColor="#FFFFFF" android:fillColor="#FFFFFFFF"
android:fillType="nonZero" android:pathData="M54,54m-22,0a22,22 0,1 1,44 0a22,22 0,1 1,-44 0" />
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1" <!-- Play triangle (dark purple) -->
android:strokeColor="#00000000" /> <path
</vector> android:fillColor="#FF231946"
android:pathData="M47,42 L65,54 L47,66 Z" />
</vector>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background" /> <background android:drawable="@mipmap/ic_launcher_background" />
<foreground android:drawable="@android:color/transparent" /> <foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon> </adaptive-icon>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background" /> <background android:drawable="@mipmap/ic_launcher_background" />
<foreground android:drawable="@android:color/transparent" /> <foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon> </adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 36 KiB

+89 -2
View File
@@ -46,7 +46,7 @@
<string name="continue_watching">Continue Watching</string> <string name="continue_watching">Continue Watching</string>
<string name="icon_default_badge">Default</string> <string name="icon_default_badge">Default</string>
<string name="set_default_library">Set as default icon library</string> <string name="set_default_library">Set as default icon library</string>
<string name="set_default_library_sub">Used first when changing library icons</string> <string name="app_name">My Application</string> <string name="set_default_library_sub">Used first when changing library icons</string> <string name="app_name">LumaPlayer</string>
<string name="featured_title">Cold War 2</string> <string name="featured_title">Cold War 2</string>
<string name="featured_subtitle">Jul 8, 2016 Crime / Mystery</string> <string name="featured_subtitle">Jul 8, 2016 Crime / Mystery</string>
<string name="library_tv_korea">TV - Korea</string> <string name="library_tv_korea">TV - Korea</string>
@@ -92,7 +92,94 @@
<string name="icon_error_load_failed">Failed to load icons</string> <string name="icon_error_load_failed">Failed to load icons</string>
<string name="search">Search</string> <string name="search">Search</string>
<string name="search_settings">Search settings</string> <string name="search_settings">Search settings</string>
<string name="about_app_name">Luma Player</string> <string name="about_app_name">LumaPlayer</string>
<string name="empty_home_no_server">No media libraries available</string>
<string name="empty_home_no_server_sub">Add a server in the server tab</string>
<string name="empty_home_no_data">No media content</string>
<string name="empty_home_no_data_sub">The current server has no content available</string>
<string name="empty_favorites">No favorites yet</string>
<string name="empty_favorites_sub">Browse media and add to favorites</string>
<string name="empty_calendar">No calendar data</string>
<string name="empty_calendar_sub">Calendar feature coming soon</string>
<!-- Icon Library Manager -->
<string name="icon_lib_manager_title">Icon Library Manager</string>
<string name="icon_lib_add">Add</string>
<string name="icon_lib_empty">No icon libraries yet</string>
<string name="icon_lib_empty_hint">Tap top-left to add</string>
<string name="icon_lib_not_loaded">Icons not loaded</string>
<string name="icon_lib_no_icons">No icons</string>
<string name="icon_lib_preview_edit">Preview · Edit</string>
<string name="icon_lib_section_title">Icon Libraries</string>
<string name="icon_lib_manage">Manage</string>
<string name="icon_lib_close">Close</string>
<string name="icon_count_suffix">%d icons</string>
<string name="icon_count_unit">%d</string>
<!-- Manage Icon Library Dialog -->
<string name="icon_lib_manage_dialog_title">Manage Icon Library</string>
<string name="icon_lib_count">Icon Count</string>
<string name="icon_lib_name_label">Library Name</string>
<string name="icon_lib_url_label">Library URL (JSON)</string>
<string name="icon_lib_preview">Icon Preview</string>
<string name="icon_lib_refresh">Refresh Icons</string>
<string name="icon_lib_delete">Delete</string>
<string name="icon_lib_save">Save</string>
<!-- Add Icon Library Dialog -->
<string name="icon_lib_add_title">Add Icon Library</string>
<string name="icon_lib_name_hint">e.g. Emby Icon Library</string>
<string name="icon_lib_fetch_preview">Fetch Preview</string>
<string name="icon_lib_fetch_error">Fetch failed</string>
<string name="icon_lib_preview_count">Preview (%d icons)</string>
<string name="icon_lib_loaded_count">✓ Loaded %d icons</string>
<string name="icon_lib_cancel">Cancel</string>
<!-- Icon Picker Dialog -->
<string name="icon_picker_title">Select Icon</string>
<string name="icon_picker_search_hint">Search icon name</string>
<string name="icon_picker_clear_search">Clear search</string>
<string name="icon_picker_no_lib">No icon libraries</string>
<string name="icon_picker_no_lib_hint">Add icon libraries in the library manager first</string>
<string name="icon_picker_loaded_hint">Loaded %d icons, tap to select</string>
<string name="icon_picker_no_match">No matching icons found</string>
<!-- Server Management -->
<string name="add_server">Add Server</string>
<string name="edit_server">Edit Server</string>
<string name="server_name_label">Name</string>
<string name="server_name_placeholder">My Emby</string>
<string name="server_url_label">URL</string>
<string name="server_url_error">Please enter URL</string>
<string name="server_path_label">Path</string>
<string name="server_port_label">Port</string>
<string name="server_port_error">Please enter port</string>
<string name="server_username_label">Username</string>
<string name="server_username_placeholder">Username</string>
<string name="server_username_error">Please enter username</string>
<string name="server_password_label">Password</string>
<string name="server_password_placeholder">Password</string>
<string name="server_hide_password">Hide password</string>
<string name="server_show_password">Show password</string>
<string name="server_note_label">Note</string>
<string name="server_note_placeholder">Note</string>
<string name="server_saving">Saving…</string>
<string name="server_save">Save</string>
<string name="server_cancel">Cancel</string>
<string name="server_online">Online</string>
<string name="server_offline">Offline</string>
<string name="server_actions">Actions</string>
<string name="server_edit">Edit</string>
<string name="change_icon_action">Change Icon</string>
<string name="server_just_now">Just now</string>
<string name="view_toggle">Toggle View</string>
<string name="server_library_manager">Icon Library</string>
<string name="add_server_action">Add Server</string>
<!-- Error Messages -->
<string name="error_login_failed">Login failed</string>
<string name="error_network">Network error: %s</string>
<string name="error_unknown">Unknown</string>
</resources> </resources>
+89 -2
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">My Application</string> <string name="app_name">LumaPlayer</string>
<string name="nav_home">首页</string> <string name="nav_home">首页</string>
<string name="nav_records">Vision</string> <string name="nav_records">Vision</string>
<string name="nav_library">服务器</string> <string name="nav_library">服务器</string>
@@ -92,7 +92,94 @@
<string name="icon_error_load_failed">图标加载失败</string> <string name="icon_error_load_failed">图标加载失败</string>
<string name="search">搜索</string> <string name="search">搜索</string>
<string name="search_settings">搜索设置</string> <string name="search_settings">搜索设置</string>
<string name="about_app_name">Luma Player</string> <string name="about_app_name">LumaPlayer</string>
<string name="empty_home_no_server">暂无可用的媒体库</string>
<string name="empty_home_no_server_sub">请在资源库中添加服务器</string>
<string name="empty_home_no_data">暂无媒体内容</string>
<string name="empty_home_no_data_sub">当前服务器暂无可用内容</string>
<string name="empty_favorites">暂无收藏内容</string>
<string name="empty_favorites_sub">浏览媒体并添加收藏</string>
<string name="empty_calendar">暂无日历数据</string>
<string name="empty_calendar_sub">日历功能即将推出</string>
<!-- Icon Library Manager -->
<string name="icon_lib_manager_title">图标库管理</string>
<string name="icon_lib_add">添加</string>
<string name="icon_lib_empty">还没有图标库</string>
<string name="icon_lib_empty_hint">点击左上角添加</string>
<string name="icon_lib_not_loaded">图标未加载</string>
<string name="icon_lib_no_icons">暂无图标</string>
<string name="icon_lib_preview_edit">预览 · 修改</string>
<string name="icon_lib_section_title">图标库</string>
<string name="icon_lib_manage">管理</string>
<string name="icon_lib_close">关闭</string>
<string name="icon_count_suffix">%d 个图标</string>
<string name="icon_count_unit">%d 个</string>
<!-- Manage Icon Library Dialog -->
<string name="icon_lib_manage_dialog_title">管理图标库</string>
<string name="icon_lib_count">图标数量</string>
<string name="icon_lib_name_label">图标库名称</string>
<string name="icon_lib_url_label">图标库地址 (JSON)</string>
<string name="icon_lib_preview">图标预览</string>
<string name="icon_lib_refresh">刷新图标</string>
<string name="icon_lib_delete">删除</string>
<string name="icon_lib_save">保存</string>
<!-- Add Icon Library Dialog -->
<string name="icon_lib_add_title">增加图标库</string>
<string name="icon_lib_name_hint">例如: Emby 图标库</string>
<string name="icon_lib_fetch_preview">获取预览</string>
<string name="icon_lib_fetch_error">获取失败</string>
<string name="icon_lib_preview_count">预览 (%d 个图标)</string>
<string name="icon_lib_loaded_count">✓ 已加载 %d 个图标</string>
<string name="icon_lib_cancel">取消</string>
<!-- Icon Picker Dialog -->
<string name="icon_picker_title">选择图标</string>
<string name="icon_picker_search_hint">搜索图标名称</string>
<string name="icon_picker_clear_search">清除搜索</string>
<string name="icon_picker_no_lib">暂无图标库</string>
<string name="icon_picker_no_lib_hint">请先在图标库管理中添加图标库</string>
<string name="icon_picker_loaded_hint">已加载 %d 个图标,点击选择</string>
<string name="icon_picker_no_match">未找到匹配的图标</string>
<!-- Server Management -->
<string name="add_server">添加服务器</string>
<string name="edit_server">编辑服务器</string>
<string name="server_name_label">名称</string>
<string name="server_name_placeholder">我的 Emby</string>
<string name="server_url_label">地址</string>
<string name="server_url_error">请输入地址</string>
<string name="server_path_label">路径</string>
<string name="server_port_label">端口</string>
<string name="server_port_error">请输入端口</string>
<string name="server_username_label">用户名</string>
<string name="server_username_placeholder">用户名</string>
<string name="server_username_error">请输入用户名</string>
<string name="server_password_label">密码</string>
<string name="server_password_placeholder">密码</string>
<string name="server_hide_password">隐藏密码</string>
<string name="server_show_password">显示密码</string>
<string name="server_note_label">备注</string>
<string name="server_note_placeholder">备注</string>
<string name="server_saving">保存中…</string>
<string name="server_save">保存</string>
<string name="server_cancel">取消</string>
<string name="server_online">在线</string>
<string name="server_offline">离线</string>
<string name="server_actions">操作</string>
<string name="server_edit">编辑</string>
<string name="change_icon_action">更换图标</string>
<string name="server_just_now">刚刚</string>
<string name="view_toggle">视图切换</string>
<string name="server_library_manager">图标库管理</string>
<string name="add_server_action">添加服务器</string>
<!-- Error Messages -->
<string name="error_login_failed">登录失败</string>
<string name="error_network">网络错误: %s</string>
<string name="error_unknown">未知</string>
</resources> </resources>
+1 -1
View File
@@ -27,5 +27,5 @@ dependencyResolutionManagement {
} }
} }
rootProject.name = "EmbyPlayer" rootProject.name = "LumaPlayer"
include(":app") include(":app")