prepare server summary bottom drawer
This commit is contained in:
parent
1d2ded1eee
commit
bea1235502
|
@ -1,23 +1,25 @@
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
* TODO Add server
|
* Basic functionality
|
||||||
|
|
||||||
- [x] Create
|
** TODO Manage servers [1/3]
|
||||||
- [ ] Delete
|
|
||||||
|
- [X] Create
|
||||||
- [ ] Update
|
- [ ] Update
|
||||||
|
- [ ] Delete
|
||||||
|
|
||||||
* TODO Music playback
|
** TODO Music playback [0/3]
|
||||||
|
|
||||||
- [ ] Regular playback
|
- [ ] Regular playback
|
||||||
- [ ] Playlist
|
- [ ] Playlist
|
||||||
- [ ] Media session
|
- [ ] Media session
|
||||||
|
|
||||||
* TODO Download music to local folder
|
** TODO Download music to local folder [0/2]
|
||||||
|
|
||||||
- [ ] Select and remember selected folder
|
- [ ] Select and remember selected folder
|
||||||
- [ ] Download music
|
- [ ] Download music
|
||||||
|
|
||||||
* TODO Misc.
|
** TODO Misc. [0/1]
|
||||||
|
|
||||||
- [ ] Back key to navigate folder up
|
- [ ] Back key to navigate folder up
|
||||||
|
|
|
@ -69,99 +69,6 @@ fun NowPlaying() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
|
||||||
@Composable
|
|
||||||
fun DrawerContent(
|
|
||||||
currentServer: Server? = null,
|
|
||||||
servers: List<Server> = listOf(),
|
|
||||||
drawerFolders: List<Folder> = listOf(),
|
|
||||||
addServerActionTriggered: () -> Unit = {},
|
|
||||||
onServerItemIconClicked: (Server) -> Unit = {},
|
|
||||||
onDrawerFolderItemClicked: (Folder) -> Unit = {},
|
|
||||||
settingsActionTriggered: () -> Unit = {},
|
|
||||||
) {
|
|
||||||
val currentServerApiUrl = currentServer?.url
|
|
||||||
|
|
||||||
Row(modifier = Modifier.fillMaxSize()) {
|
|
||||||
NavigationRail {
|
|
||||||
servers.forEachIndexed { index, server ->
|
|
||||||
NavigationRailItem(
|
|
||||||
icon = {
|
|
||||||
Icon(
|
|
||||||
Icons.Filled.LibraryMusic, server.name
|
|
||||||
)
|
|
||||||
},
|
|
||||||
label = {
|
|
||||||
Text(server.displayName())
|
|
||||||
},
|
|
||||||
selected = server.url == currentServerApiUrl,
|
|
||||||
onClick = {
|
|
||||||
onServerItemIconClicked(server)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
NavigationRailItem(
|
|
||||||
icon = { Icon(Icons.Filled.AddCircle, null) },
|
|
||||||
label = { Text(stringResource(id = R.string.add)) },
|
|
||||||
selected = false,
|
|
||||||
onClick = addServerActionTriggered,
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
|
|
||||||
NavigationRailItem(
|
|
||||||
icon = { Icon(Icons.Filled.Settings, null) },
|
|
||||||
label = { Text(stringResource(id = R.string.settings)) },
|
|
||||||
selected = false,
|
|
||||||
onClick = settingsActionTriggered,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f)
|
|
||||||
) {
|
|
||||||
ListItem(
|
|
||||||
text = {
|
|
||||||
Text(
|
|
||||||
text = currentServer?.displayName() ?: "No server selected",
|
|
||||||
style = MaterialTheme.typography.subtitle1
|
|
||||||
)
|
|
||||||
},
|
|
||||||
trailing = {
|
|
||||||
IconButton(onClick = { /*TODO*/ }) {
|
|
||||||
Icon(imageVector = Icons.Filled.MoreVert, contentDescription = "Menu")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Divider()
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f, fill = true)
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
) {
|
|
||||||
drawerFolders.forEach { folder ->
|
|
||||||
ListItem(
|
|
||||||
modifier = Modifier.clickable{
|
|
||||||
onDrawerFolderItemClicked(folder)
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Text(
|
|
||||||
text = folder.displayName(),
|
|
||||||
style = MaterialTheme.typography.subtitle1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -177,30 +84,33 @@ fun MainPlayer(
|
||||||
onFolderItemClicked: (Folder) -> Unit = {},
|
onFolderItemClicked: (Folder) -> Unit = {},
|
||||||
settingsActionTriggered: () -> Unit = {},
|
settingsActionTriggered: () -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
val bottomDrawerState = rememberBottomDrawerState(initialValue = BottomDrawerValue.Closed)
|
||||||
val drawerScope = rememberCoroutineScope()
|
val bottomDrawerScope = rememberCoroutineScope()
|
||||||
ModalDrawer(
|
BottomDrawer(
|
||||||
drawerState = drawerState,
|
drawerState = bottomDrawerState,
|
||||||
|
gesturesEnabled = bottomDrawerState.isOpen,
|
||||||
drawerContent = {
|
drawerContent = {
|
||||||
DrawerContent(
|
if (currentServer != null) {
|
||||||
currentServer = currentServer,
|
ServerSummaryDrawer(currentServer)
|
||||||
servers = servers,
|
} else {
|
||||||
drawerFolders = drawerFolders,
|
Text(
|
||||||
addServerActionTriggered = addServerActionTriggered,
|
"TODO: play control and playlist?",
|
||||||
onServerItemIconClicked = onServerItemIconClicked,
|
modifier = Modifier.fillMaxWidth().padding(16.dp),
|
||||||
onDrawerFolderItemClicked = onFolderItemClicked,
|
)
|
||||||
settingsActionTriggered = settingsActionTriggered,
|
}
|
||||||
)
|
},
|
||||||
}
|
|
||||||
) {
|
) {
|
||||||
|
val scaffoldState = rememberScaffoldState()
|
||||||
|
val scaffoldScope = rememberCoroutineScope()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text(stringResource(id = R.string.app_name)) },
|
title = { Text(stringResource(id = R.string.app_name)) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = {
|
IconButton(onClick = {
|
||||||
drawerScope.launch {
|
scaffoldScope.launch {
|
||||||
drawerState.open()
|
scaffoldState.drawerState.open()
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Icon(imageVector = Icons.Filled.Menu, contentDescription = "Open drawer")
|
Icon(imageVector = Icons.Filled.Menu, contentDescription = "Open drawer")
|
||||||
|
@ -212,6 +122,22 @@ fun MainPlayer(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
drawerContent = {
|
||||||
|
SidebarContent(
|
||||||
|
currentServer = currentServer,
|
||||||
|
servers = servers,
|
||||||
|
drawerFolders = drawerFolders,
|
||||||
|
addServerActionTriggered = addServerActionTriggered,
|
||||||
|
onServerItemIconClicked = onServerItemIconClicked,
|
||||||
|
onServerMenuIconClicked = {
|
||||||
|
bottomDrawerScope.launch {
|
||||||
|
bottomDrawerState.open()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDrawerFolderItemClicked = onFolderItemClicked,
|
||||||
|
settingsActionTriggered = settingsActionTriggered,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
package net.blumia.pcmdroid.ui.screen.main
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import net.blumia.pcmdroid.R
|
||||||
|
import net.blumia.pcmdroid.model.Server
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
|
@Composable
|
||||||
|
fun RowScope.ActionIcon(
|
||||||
|
imageVector: ImageVector = Icons.Filled.Share,
|
||||||
|
contentDescription: String = "Share",
|
||||||
|
onActionTriggered: () -> Unit = {},
|
||||||
|
) {
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
onClick = onActionTriggered,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Icon(imageVector = imageVector, contentDescription = contentDescription)
|
||||||
|
Text(contentDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
|
@Composable
|
||||||
|
fun ServerSummaryDrawer(
|
||||||
|
server: Server = Server("http://localhost/", "Demo server", "pcm"),
|
||||||
|
onShareActionTriggered: (Server) -> Unit = {},
|
||||||
|
onEditActionTriggered: (Server) -> Unit = {},
|
||||||
|
onDeleteActionTriggered: (Server) -> Unit = {},
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(vertical = 16.dp)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(50.dp),
|
||||||
|
imageVector = Icons.Filled.LibraryMusic,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 10.dp),
|
||||||
|
text = server.displayName(),
|
||||||
|
// textAlign = TextAlign.Center,
|
||||||
|
style = MaterialTheme.typography.h5,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// Row(
|
||||||
|
// modifier = Modifier.fillMaxWidth(),
|
||||||
|
// ) {
|
||||||
|
// ActionIcon(
|
||||||
|
// imageVector = Icons.Filled.Share,
|
||||||
|
// contentDescription = "Share",
|
||||||
|
// )
|
||||||
|
// ActionIcon(
|
||||||
|
// imageVector = Icons.Filled.Edit,
|
||||||
|
// contentDescription = "Edit",
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
ListItem(
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
onShareActionTriggered(server)
|
||||||
|
},
|
||||||
|
icon = {
|
||||||
|
Icon(Icons.Filled.Share, null)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(stringResource(id = R.string.share_this_server))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
ListItem(
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
onEditActionTriggered(server)
|
||||||
|
},
|
||||||
|
icon = {
|
||||||
|
Icon(Icons.Filled.Edit, null)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(stringResource(id = R.string.edit_server_info))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
ListItem(
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
onDeleteActionTriggered(server)
|
||||||
|
},
|
||||||
|
icon = {
|
||||||
|
Icon(Icons.Filled.Delete, null)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(stringResource(id = R.string.delete_server))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
116
app/src/main/java/net/blumia/pcmdroid/ui/screen/main/Sidebar.kt
Normal file
116
app/src/main/java/net/blumia/pcmdroid/ui/screen/main/Sidebar.kt
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
package net.blumia.pcmdroid.ui.screen.main
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.*
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.AddCircle
|
||||||
|
import androidx.compose.material.icons.filled.LibraryMusic
|
||||||
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
|
import androidx.compose.material.icons.filled.Settings
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import net.blumia.pcmdroid.R
|
||||||
|
import net.blumia.pcmdroid.model.Folder
|
||||||
|
import net.blumia.pcmdroid.model.Server
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
|
@Composable
|
||||||
|
fun SidebarContent(
|
||||||
|
currentServer: Server? = null,
|
||||||
|
servers: List<Server> = listOf(),
|
||||||
|
drawerFolders: List<Folder> = listOf(),
|
||||||
|
addServerActionTriggered: () -> Unit = {},
|
||||||
|
onServerItemIconClicked: (Server) -> Unit = {},
|
||||||
|
onServerMenuIconClicked: () -> Unit = {},
|
||||||
|
onDrawerFolderItemClicked: (Folder) -> Unit = {},
|
||||||
|
settingsActionTriggered: () -> Unit = {},
|
||||||
|
) {
|
||||||
|
val currentServerApiUrl = currentServer?.url
|
||||||
|
|
||||||
|
Row(modifier = Modifier.fillMaxSize()) {
|
||||||
|
NavigationRail {
|
||||||
|
servers.forEachIndexed { index, server ->
|
||||||
|
NavigationRailItem(
|
||||||
|
icon = {
|
||||||
|
Icon(
|
||||||
|
Icons.Filled.LibraryMusic, server.name
|
||||||
|
)
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text(server.displayName())
|
||||||
|
},
|
||||||
|
selected = server.url == currentServerApiUrl,
|
||||||
|
onClick = {
|
||||||
|
onServerItemIconClicked(server)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationRailItem(
|
||||||
|
icon = { Icon(Icons.Filled.AddCircle, null) },
|
||||||
|
label = { Text(stringResource(id = R.string.add)) },
|
||||||
|
selected = false,
|
||||||
|
onClick = addServerActionTriggered,
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
|
NavigationRailItem(
|
||||||
|
icon = { Icon(Icons.Filled.Settings, null) },
|
||||||
|
label = { Text(stringResource(id = R.string.settings)) },
|
||||||
|
selected = false,
|
||||||
|
onClick = settingsActionTriggered,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
) {
|
||||||
|
ListItem(
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text = currentServer?.displayName() ?: "No server selected",
|
||||||
|
style = MaterialTheme.typography.subtitle1
|
||||||
|
)
|
||||||
|
},
|
||||||
|
trailing = {
|
||||||
|
IconButton(onClick = onServerMenuIconClicked) {
|
||||||
|
Icon(imageVector = Icons.Filled.MoreVert, contentDescription = "Menu")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Divider()
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f, fill = true)
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
drawerFolders.forEach { folder ->
|
||||||
|
ListItem(
|
||||||
|
modifier = Modifier.clickable{
|
||||||
|
onDrawerFolderItemClicked(folder)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text = folder.displayName(),
|
||||||
|
style = MaterialTheme.typography.subtitle1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,4 +2,7 @@
|
||||||
<string name="app_name">私有云音乐</string>
|
<string name="app_name">私有云音乐</string>
|
||||||
<string name="settings">设置</string>
|
<string name="settings">设置</string>
|
||||||
<string name="add">添加</string>
|
<string name="add">添加</string>
|
||||||
|
<string name="share_this_server">分享此服务器</string>
|
||||||
|
<string name="delete_server">删除服务器</string>
|
||||||
|
<string name="edit_server_info">编辑服务器信息</string>
|
||||||
</resources>
|
</resources>
|
|
@ -2,4 +2,7 @@
|
||||||
<string name="app_name">Private Cloud Music</string>
|
<string name="app_name">Private Cloud Music</string>
|
||||||
<string name="settings">Settings</string>
|
<string name="settings">Settings</string>
|
||||||
<string name="add">Add</string>
|
<string name="add">Add</string>
|
||||||
|
<string name="share_this_server">Share This Server</string>
|
||||||
|
<string name="delete_server">Delete Server</string>
|
||||||
|
<string name="edit_server_info">Edit Server Information</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue
Block a user