basic ui mock-up
This commit is contained in:
parent
b9caa79e48
commit
4312d1fdea
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -53,6 +53,7 @@ dependencies {
|
||||||
implementation 'com.google.android.material:material:1.4.0'
|
implementation 'com.google.android.material:material:1.4.0'
|
||||||
implementation "androidx.compose.ui:ui:$compose_version"
|
implementation "androidx.compose.ui:ui:$compose_version"
|
||||||
implementation "androidx.compose.material:material:$compose_version"
|
implementation "androidx.compose.material:material:$compose_version"
|
||||||
|
implementation "androidx.compose.material:material-icons-extended:$compose_version"
|
||||||
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
|
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
|
||||||
implementation "androidx.navigation:navigation-compose:$nav_compose_version"
|
implementation "androidx.navigation:navigation-compose:$nav_compose_version"
|
||||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
|
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="net.blumia.pcmdroid">
|
package="net.blumia.pcmdroid">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
|
|
@ -3,6 +3,7 @@ package net.blumia.pcmdroid
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Surface
|
import androidx.compose.material.Surface
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
|
@ -13,28 +14,18 @@ import net.blumia.pcmdroid.ui.screen.main.MainPlayer
|
||||||
import net.blumia.pcmdroid.ui.theme.PrivateCloudMusicTheme
|
import net.blumia.pcmdroid.ui.theme.PrivateCloudMusicTheme
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
|
private val model: MainViewModel by viewModels()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContent {
|
setContent {
|
||||||
PrivateCloudMusicTheme {
|
PrivateCloudMusicTheme {
|
||||||
// A surface container using the 'background' color from the theme
|
// A surface container using the 'background' color from the theme
|
||||||
Surface(color = MaterialTheme.colors.background) {
|
Surface(color = MaterialTheme.colors.background) {
|
||||||
NavGraph()
|
NavGraph(model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun Greeting(name: String) {
|
|
||||||
Text(text = "Hello $name!")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
|
||||||
@Composable
|
|
||||||
fun DefaultPreview() {
|
|
||||||
PrivateCloudMusicTheme {
|
|
||||||
Greeting("Android")
|
|
||||||
}
|
|
||||||
}
|
}
|
63
app/src/main/java/net/blumia/pcmdroid/MainViewModel.kt
Normal file
63
app/src/main/java/net/blumia/pcmdroid/MainViewModel.kt
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
package net.blumia.pcmdroid
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import net.blumia.pcmdroid.model.Folder
|
||||||
|
import net.blumia.pcmdroid.model.Server
|
||||||
|
import net.blumia.pcmdroid.model.Song
|
||||||
|
|
||||||
|
class MainViewModel : ViewModel() {
|
||||||
|
|
||||||
|
val servers: LiveData<List<Server>> = MutableLiveData<List<Server>>(
|
||||||
|
listOf(
|
||||||
|
Server(
|
||||||
|
url = Uri.parse("https://localhost/api.php"),
|
||||||
|
name = "PCM",
|
||||||
|
baseFolderName = "pcm",
|
||||||
|
),
|
||||||
|
Server(
|
||||||
|
url = Uri.parse("https://localhost/api.php"),
|
||||||
|
name = "PCM2",
|
||||||
|
baseFolderName = "pcm2",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val currentPath: LiveData<String> = MutableLiveData("")
|
||||||
|
|
||||||
|
val drawerFolders: LiveData<List<Folder>> = MutableLiveData(
|
||||||
|
listOf(
|
||||||
|
Folder("Test/"),
|
||||||
|
Folder("Folder/")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val folders: LiveData<List<Folder>> = MutableLiveData(
|
||||||
|
listOf(
|
||||||
|
Folder("Test/Converted-Modules/")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val songs: LiveData<List<Song>> = MutableLiveData(
|
||||||
|
listOf(
|
||||||
|
Song(
|
||||||
|
filePath = "Test/Rick Astley - Never Gonna Give You Up.mp3",
|
||||||
|
url = Uri.parse("http://localhost/rickroll.mp3")
|
||||||
|
),
|
||||||
|
Song(
|
||||||
|
filePath = "Test/哇 好东西一堆.xm",
|
||||||
|
url = Uri.parse("http://localhost/rickroll.mp3")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun fetchServer(srv: Server) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fetchFolder(folder: Folder) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,4 +6,4 @@ data class Server (
|
||||||
val url: Uri,
|
val url: Uri,
|
||||||
val name: String,
|
val name: String,
|
||||||
val baseFolderName: String,
|
val baseFolderName: String,
|
||||||
)
|
)
|
||||||
|
|
23
app/src/main/java/net/blumia/pcmdroid/model/Song.kt
Normal file
23
app/src/main/java/net/blumia/pcmdroid/model/Song.kt
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package net.blumia.pcmdroid.model
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
|
||||||
|
data class Song (
|
||||||
|
val filePath: String, // with file name
|
||||||
|
val modifiedTime: Int = 0,
|
||||||
|
val fileSize: Int = 0,
|
||||||
|
val additionalInfo: Boolean = false, // if sidecar meta-info json file exist.
|
||||||
|
val url: Uri,
|
||||||
|
) {
|
||||||
|
fun displayName(): String {
|
||||||
|
return Uri.parse(filePath).lastPathSegment ?: "???"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Folder (
|
||||||
|
val folderPath: String,
|
||||||
|
) {
|
||||||
|
fun displayName(): String {
|
||||||
|
return Uri.parse(folderPath).lastPathSegment ?: "???"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package net.blumia.pcmdroid.repository
|
||||||
|
|
||||||
|
class ServerRepository {
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
package net.blumia.pcmdroid.ui
|
package net.blumia.pcmdroid.ui
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
|
import net.blumia.pcmdroid.MainViewModel
|
||||||
import net.blumia.pcmdroid.ui.screen.addserver.AddServerScreen
|
import net.blumia.pcmdroid.ui.screen.addserver.AddServerScreen
|
||||||
import net.blumia.pcmdroid.ui.screen.main.MainPlayer
|
import net.blumia.pcmdroid.ui.screen.main.MainPlayer
|
||||||
import net.blumia.pcmdroid.ui.screen.settings.SettingsScreen
|
import net.blumia.pcmdroid.ui.screen.settings.SettingsScreen
|
||||||
|
@ -18,6 +18,7 @@ object MainDestinations {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NavGraph(
|
fun NavGraph(
|
||||||
|
viewModel: MainViewModel,
|
||||||
navController: NavHostController = rememberNavController(),
|
navController: NavHostController = rememberNavController(),
|
||||||
startDestination: String = MainDestinations.MAIN_ROUTE,
|
startDestination: String = MainDestinations.MAIN_ROUTE,
|
||||||
) {
|
) {
|
||||||
|
@ -27,6 +28,7 @@ fun NavGraph(
|
||||||
) {
|
) {
|
||||||
composable(MainDestinations.MAIN_ROUTE) {
|
composable(MainDestinations.MAIN_ROUTE) {
|
||||||
MainPlayer(
|
MainPlayer(
|
||||||
|
viewModel = viewModel,
|
||||||
addServerActionTriggered = {
|
addServerActionTriggered = {
|
||||||
navController.navigate(MainDestinations.ADD_SERVER_ROUTE)
|
navController.navigate(MainDestinations.ADD_SERVER_ROUTE)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,50 +1,72 @@
|
||||||
package net.blumia.pcmdroid.ui.screen.main
|
package net.blumia.pcmdroid.ui.screen.main
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.gestures.scrollable
|
||||||
|
import androidx.compose.foundation.horizontalScroll
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.*
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material.icons.rounded.FeaturedPlayList
|
||||||
import androidx.compose.material.icons.rounded.PlayArrow
|
import androidx.compose.material.icons.rounded.PlayArrow
|
||||||
|
import androidx.compose.material.icons.rounded.PlayCircle
|
||||||
|
import androidx.compose.material.icons.rounded.PlayCircleOutline
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.layout.VerticalAlignmentLine
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import net.blumia.pcmdroid.MainViewModel
|
||||||
import net.blumia.pcmdroid.R
|
import net.blumia.pcmdroid.R
|
||||||
|
import net.blumia.pcmdroid.model.Folder
|
||||||
|
import net.blumia.pcmdroid.model.Server
|
||||||
|
import net.blumia.pcmdroid.model.Song
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun NowPlaying() {
|
fun NowPlaying() {
|
||||||
Row(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth(),
|
||||||
.height(56.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
) {
|
) {
|
||||||
Image(
|
LinearProgressIndicator(
|
||||||
painter = painterResource(id = R.drawable.ic_launcher_background),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
contentDescription = "Album cover",
|
progress = 0f,
|
||||||
)
|
)
|
||||||
|
|
||||||
ListItem(
|
Row(
|
||||||
text = {
|
modifier = Modifier
|
||||||
Text(
|
.fillMaxWidth()
|
||||||
text = "Not playing at all.",
|
.height(56.dp),
|
||||||
)
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
},
|
) {
|
||||||
trailing = {
|
Image(
|
||||||
IconButton(onClick = { /*TODO*/ }) {
|
painter = painterResource(id = R.drawable.ic_launcher_background),
|
||||||
Icon(imageVector = Icons.Rounded.PlayArrow, contentDescription = "Menu")
|
contentDescription = "Album cover",
|
||||||
|
)
|
||||||
|
|
||||||
|
ListItem(
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text = "Not playing at all.",
|
||||||
|
)
|
||||||
|
},
|
||||||
|
trailing = {
|
||||||
|
IconButton(onClick = { /*TODO*/ }) {
|
||||||
|
Icon(imageVector = Icons.Rounded.PlayCircleOutline, contentDescription = "Menu")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,32 +74,34 @@ fun NowPlaying() {
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun DrawerContent(
|
fun DrawerContent(
|
||||||
|
viewModel: MainViewModel = MainViewModel(),
|
||||||
addServerActionTriggered: () -> Unit = {},
|
addServerActionTriggered: () -> Unit = {},
|
||||||
settingsActionTriggered: () -> Unit = {},
|
settingsActionTriggered: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
Row(modifier = Modifier.fillMaxSize()) {
|
Row(modifier = Modifier.fillMaxSize()) {
|
||||||
var selectedItem by remember { mutableStateOf<Int?>(null) }
|
var selectedItem by remember { mutableStateOf<Int?>(0) }
|
||||||
val items = listOf<String>()
|
val servers = viewModel.servers.value
|
||||||
val icons = listOf<ImageVector>()
|
|
||||||
NavigationRail {
|
NavigationRail {
|
||||||
items.forEachIndexed { index, item ->
|
servers?.forEachIndexed { index, server ->
|
||||||
NavigationRailItem(
|
NavigationRailItem(
|
||||||
icon = {
|
icon = {
|
||||||
Icon(
|
Icon(
|
||||||
icons[index], item
|
Icons.Filled.LibraryMusic, server.name
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
label = {
|
label = {
|
||||||
Text(item)
|
Text(server.name)
|
||||||
},
|
},
|
||||||
selected = selectedItem == index,
|
selected = selectedItem == index,
|
||||||
onClick = { /*TODO*/ }
|
onClick = {
|
||||||
|
viewModel.fetchServer(server)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
NavigationRailItem(
|
NavigationRailItem(
|
||||||
icon = { Icon(Icons.Filled.AddCircle, null) },
|
icon = { Icon(Icons.Filled.AddCircle, null) },
|
||||||
label = { Text("Add") },
|
label = { Text(stringResource(id = R.string.add)) },
|
||||||
selected = false,
|
selected = false,
|
||||||
onClick = addServerActionTriggered,
|
onClick = addServerActionTriggered,
|
||||||
)
|
)
|
||||||
|
@ -86,7 +110,7 @@ fun DrawerContent(
|
||||||
|
|
||||||
NavigationRailItem(
|
NavigationRailItem(
|
||||||
icon = { Icon(Icons.Filled.Settings, null) },
|
icon = { Icon(Icons.Filled.Settings, null) },
|
||||||
label = { Text("Settings") },
|
label = { Text(stringResource(id = R.string.settings)) },
|
||||||
selected = false,
|
selected = false,
|
||||||
onClick = settingsActionTriggered,
|
onClick = settingsActionTriggered,
|
||||||
)
|
)
|
||||||
|
@ -108,13 +132,30 @@ fun DrawerContent(
|
||||||
)
|
)
|
||||||
|
|
||||||
Divider()
|
Divider()
|
||||||
|
|
||||||
|
val drawerFolders = viewModel.drawerFolders.value
|
||||||
|
drawerFolders?.forEach { folder ->
|
||||||
|
ListItem(
|
||||||
|
modifier = Modifier.clickable{
|
||||||
|
viewModel.fetchFolder(folder)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text = folder.displayName(),
|
||||||
|
style = MaterialTheme.typography.subtitle1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun MainPlayer(
|
fun MainPlayer(
|
||||||
|
viewModel: MainViewModel = MainViewModel(),
|
||||||
addServerActionTriggered: () -> Unit = {},
|
addServerActionTriggered: () -> Unit = {},
|
||||||
settingsActionTriggered: () -> Unit = {},
|
settingsActionTriggered: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
|
@ -124,6 +165,7 @@ fun MainPlayer(
|
||||||
drawerState = drawerState,
|
drawerState = drawerState,
|
||||||
drawerContent = {
|
drawerContent = {
|
||||||
DrawerContent(
|
DrawerContent(
|
||||||
|
viewModel = viewModel,
|
||||||
addServerActionTriggered = addServerActionTriggered,
|
addServerActionTriggered = addServerActionTriggered,
|
||||||
settingsActionTriggered = settingsActionTriggered,
|
settingsActionTriggered = settingsActionTriggered,
|
||||||
)
|
)
|
||||||
|
@ -132,7 +174,7 @@ fun MainPlayer(
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text("Private Cloud Music") },
|
title = { Text(stringResource(id = R.string.app_name)) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = {
|
IconButton(onClick = {
|
||||||
drawerScope.launch {
|
drawerScope.launch {
|
||||||
|
@ -154,7 +196,68 @@ fun MainPlayer(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.weight(1f, fill = true)) {
|
Column(modifier = Modifier.weight(1f, fill = true)) {
|
||||||
//
|
|
||||||
|
val iconLeftPadding = 16.dp
|
||||||
|
val iconVerticalPadding = 12.dp
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.horizontalScroll(rememberScrollState())
|
||||||
|
.padding(
|
||||||
|
horizontal = iconLeftPadding,
|
||||||
|
vertical = iconVerticalPadding,
|
||||||
|
),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
val pathSeg = listOf("Deep", "Dark", "Folder")
|
||||||
|
pathSeg.forEach { seg ->
|
||||||
|
val isLastSeg = seg == pathSeg.last()
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = seg,
|
||||||
|
style = MaterialTheme.typography.body1,
|
||||||
|
color = if (isLastSeg) MaterialTheme.colors.primary else MaterialTheme.colors.onSurface
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!isLastSeg) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.padding(horizontal = 5.dp),
|
||||||
|
imageVector = Icons.Filled.NavigateNext,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.folders.value?.forEach { folder ->
|
||||||
|
ListItem(
|
||||||
|
modifier = Modifier.clickable { },
|
||||||
|
icon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.FolderOpen,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(folder.displayName())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.songs.value?.forEach { song ->
|
||||||
|
ListItem(
|
||||||
|
modifier = Modifier.clickable { },
|
||||||
|
icon = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.MusicNote,
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(song.displayName())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
NowPlaying()
|
NowPlaying()
|
||||||
}
|
}
|
||||||
|
|
5
app/src/main/res/values-zh/strings.xml
Normal file
5
app/src/main/res/values-zh/strings.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">私有云音乐</string>
|
||||||
|
<string name="settings">设置</string>
|
||||||
|
<string name="add">添加</string>
|
||||||
|
</resources>
|
|
@ -1,3 +1,5 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Private Cloud Music</string>
|
<string name="app_name">Private Cloud Music</string>
|
||||||
|
<string name="settings">Settings</string>
|
||||||
|
<string name="add">Add</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue
Block a user