working breadcrumb, scrollable drawer list, etc.
This commit is contained in:
parent
8edcb91242
commit
d0800429c5
@ -24,13 +24,13 @@ class MainViewModel : ViewModel() {
|
||||
val servers: LiveData<List<Server>> = MutableLiveData<List<Server>>(
|
||||
listOf(
|
||||
Server(
|
||||
url = "http://localhost/api.php",
|
||||
url = "https://localhost/api.php",
|
||||
name = "PCM",
|
||||
baseFolderName = "pcm",
|
||||
),
|
||||
Server(
|
||||
url = "http://localhost/api.php",
|
||||
name = "PCM2",
|
||||
url = "https://localhost/pcm.cgi",
|
||||
name = "Chris",
|
||||
baseFolderName = "pcm2",
|
||||
)
|
||||
)
|
||||
@ -42,13 +42,16 @@ class MainViewModel : ViewModel() {
|
||||
_currentServer.postValue(srv)
|
||||
}
|
||||
|
||||
private val _currentPath: MutableLiveData<String> = MutableLiveData("")
|
||||
val currentPath: LiveData<String> = _currentPath
|
||||
private val _currentFolder: MutableLiveData<Folder> = MutableLiveData(null)
|
||||
val currentFolder: LiveData<Folder> = _currentFolder
|
||||
fun setCurrentFolder(folder: Folder) {
|
||||
_currentFolder.postValue(folder)
|
||||
}
|
||||
|
||||
private val _drawerFolders: MutableLiveData<List<Folder>> = MutableLiveData(
|
||||
listOf(
|
||||
Folder("Test/"),
|
||||
Folder("Folder/")
|
||||
Folder("Folder/"),
|
||||
)
|
||||
)
|
||||
val drawerFolders: LiveData<List<Folder>> = _drawerFolders
|
||||
@ -86,16 +89,21 @@ class MainViewModel : ViewModel() {
|
||||
.post(formBody)
|
||||
.build()
|
||||
|
||||
httpClient.newCall(request).execute().use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
// TODO: non-200 response will go to here too.
|
||||
return@use
|
||||
try {
|
||||
httpClient.newCall(request).execute().use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
// TODO: non-200 response will go to here too.
|
||||
return@use
|
||||
}
|
||||
val pair = parseFromJsonString(response.body!!.string())
|
||||
_drawerFolders.postValue(pair.first)
|
||||
setCurrentServer(srv)
|
||||
Log.d("vvv", drawerFolders.value.toString())
|
||||
}
|
||||
val pair = parseFromJsonString(response.body!!.string())
|
||||
_drawerFolders.postValue(pair.first)
|
||||
setCurrentServer(srv)
|
||||
Log.d("vvv", drawerFolders.value.toString())
|
||||
} catch (e: java.io.IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
// Thread.sleep(5_000)
|
||||
}
|
||||
}
|
||||
@ -124,9 +132,11 @@ class MainViewModel : ViewModel() {
|
||||
val pair = parseFromJsonString(response.body!!.string())
|
||||
_folders.postValue(pair.first)
|
||||
_songs.postValue(pair.second)
|
||||
|
||||
setCurrentFolder(folder)
|
||||
|
||||
Log.d("vvv", folders.value.toString())
|
||||
}
|
||||
// Thread.sleep(5_000)
|
||||
}
|
||||
}
|
||||
}
|
@ -4,4 +4,8 @@ data class Server (
|
||||
val url: String,
|
||||
val name: String,
|
||||
val baseFolderName: String,
|
||||
)
|
||||
) {
|
||||
fun displayName(): String {
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package net.blumia.pcmdroid.model
|
||||
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.net.URLDecoder
|
||||
@ -34,7 +36,7 @@ fun parseFromJsonString(jsonString: String): Pair<List<Folder>, List<Song>> {
|
||||
val result = jsonObj.getJSONObject("result")
|
||||
val data = result.getJSONObject("data")
|
||||
val subFolders = data.getJSONArray("subFolderList")
|
||||
val musicList = data.getJSONArray("musicList")
|
||||
val musicList = if (data.has("musicList")) data.getJSONArray("musicList") else JSONArray()
|
||||
for (i in 0 until subFolders.length()) {
|
||||
val rawFolderName = subFolders.getString(i)
|
||||
folders.add(Folder(rawFolderName))
|
||||
@ -55,6 +57,7 @@ fun parseFromJsonString(jsonString: String): Pair<List<Folder>, List<Song>> {
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
Log.d("vvv", jsonString)
|
||||
}
|
||||
|
||||
return Pair(folders, songs)
|
||||
|
@ -33,14 +33,18 @@ fun NavGraph(
|
||||
) {
|
||||
composable(MainDestinations.MAIN_ROUTE) {
|
||||
|
||||
val curServer: Server? by viewModel.currentServer.observeAsState(initial = null)
|
||||
val servers: List<Server> by viewModel.servers.observeAsState(initial = listOf())
|
||||
val drawerFolders: List<Folder> by viewModel.drawerFolders.observeAsState(initial = listOf())
|
||||
val curFolder: Folder? by viewModel.currentFolder.observeAsState(initial = null)
|
||||
val folders: List<Folder> by viewModel.folders.observeAsState(listOf())
|
||||
val songs: List<Song> by viewModel.songs.observeAsState(listOf())
|
||||
|
||||
MainPlayer(
|
||||
currentServer = curServer,
|
||||
servers = servers,
|
||||
drawerFolders = drawerFolders,
|
||||
currentFolder = curFolder,
|
||||
folders = folders,
|
||||
songs = songs,
|
||||
addServerActionTriggered = {
|
||||
@ -49,7 +53,7 @@ fun NavGraph(
|
||||
onServerItemIconClicked = { server ->
|
||||
viewModel.fetchServer(server)
|
||||
},
|
||||
onDrawerFolderItemClicked = { folder ->
|
||||
onFolderItemClicked = { folder ->
|
||||
viewModel.fetchFolder(folder)
|
||||
},
|
||||
settingsActionTriggered = {
|
||||
|
@ -0,0 +1,74 @@
|
||||
package net.blumia.pcmdroid.ui.screen.main
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.NavigateNext
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.blumia.pcmdroid.model.Folder
|
||||
|
||||
@Composable
|
||||
fun Breadcrumb(
|
||||
folder: Folder? = null,
|
||||
onFolderClicked: (Folder) -> Unit = {}
|
||||
) {
|
||||
val iconLeftPadding = 16.dp
|
||||
val iconVerticalPadding = 12.dp
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.horizontalScroll(rememberScrollState())
|
||||
.padding(
|
||||
horizontal = iconLeftPadding,
|
||||
vertical = iconVerticalPadding,
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
val folderPath = folder?.folderPath ?: ""
|
||||
val pathSeg = Uri.parse(folderPath).pathSegments
|
||||
|
||||
pathSeg.forEachIndexed { idx, seg ->
|
||||
val isLastSeg = seg == pathSeg.last()
|
||||
|
||||
Text(
|
||||
modifier = Modifier.clickable {
|
||||
val segList = pathSeg.take(idx + 1)
|
||||
val clickedFolder = Folder(
|
||||
folderPath = segList.joinToString("/")
|
||||
)
|
||||
|
||||
onFolderClicked(clickedFolder)
|
||||
},
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun BreadcrumbPreview() {
|
||||
Breadcrumb(Folder("""Deep/Dark/Folder"""))
|
||||
}
|
@ -73,6 +73,7 @@ fun NowPlaying() {
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun DrawerContent(
|
||||
currentServer: Server? = null,
|
||||
servers: List<Server> = listOf(),
|
||||
drawerFolders: List<Folder> = listOf(),
|
||||
addServerActionTriggered: () -> Unit = {},
|
||||
@ -80,8 +81,9 @@ fun DrawerContent(
|
||||
onDrawerFolderItemClicked: (Folder) -> Unit = {},
|
||||
settingsActionTriggered: () -> Unit = {},
|
||||
) {
|
||||
val currentServerApiUrl = currentServer?.url
|
||||
|
||||
Row(modifier = Modifier.fillMaxSize()) {
|
||||
var selectedItem by remember { mutableStateOf<Int?>(0) }
|
||||
NavigationRail {
|
||||
servers.forEachIndexed { index, server ->
|
||||
NavigationRailItem(
|
||||
@ -91,9 +93,9 @@ fun DrawerContent(
|
||||
)
|
||||
},
|
||||
label = {
|
||||
Text(server.name)
|
||||
Text(server.displayName())
|
||||
},
|
||||
selected = selectedItem == index,
|
||||
selected = server.url == currentServerApiUrl,
|
||||
onClick = {
|
||||
onServerItemIconClicked(server)
|
||||
}
|
||||
@ -117,11 +119,14 @@ fun DrawerContent(
|
||||
)
|
||||
}
|
||||
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
) {
|
||||
ListItem(
|
||||
text = {
|
||||
Text(
|
||||
text = "No server selected",
|
||||
text = currentServer?.displayName() ?: "No server selected",
|
||||
style = MaterialTheme.typography.subtitle1
|
||||
)
|
||||
},
|
||||
@ -134,18 +139,24 @@ fun DrawerContent(
|
||||
|
||||
Divider()
|
||||
|
||||
drawerFolders.forEach { folder ->
|
||||
ListItem(
|
||||
modifier = Modifier.clickable{
|
||||
onDrawerFolderItemClicked(folder)
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
text = folder.displayName(),
|
||||
style = MaterialTheme.typography.subtitle1
|
||||
)
|
||||
}
|
||||
)
|
||||
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
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -155,13 +166,15 @@ fun DrawerContent(
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun MainPlayer(
|
||||
currentServer: Server? = null,
|
||||
servers: List<Server> = listOf(),
|
||||
drawerFolders: List<Folder> = listOf(),
|
||||
currentFolder: Folder? = null,
|
||||
folders: List<Folder> = listOf(),
|
||||
songs: List<Song> = listOf(),
|
||||
addServerActionTriggered: () -> Unit = {},
|
||||
onServerItemIconClicked: (Server) -> Unit = {},
|
||||
onDrawerFolderItemClicked: (Folder) -> Unit = {},
|
||||
onFolderItemClicked: (Folder) -> Unit = {},
|
||||
settingsActionTriggered: () -> Unit = {},
|
||||
) {
|
||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||
@ -170,11 +183,12 @@ fun MainPlayer(
|
||||
drawerState = drawerState,
|
||||
drawerContent = {
|
||||
DrawerContent(
|
||||
currentServer = currentServer,
|
||||
servers = servers,
|
||||
drawerFolders = drawerFolders,
|
||||
addServerActionTriggered = addServerActionTriggered,
|
||||
onServerItemIconClicked = onServerItemIconClicked,
|
||||
onDrawerFolderItemClicked = onDrawerFolderItemClicked,
|
||||
onDrawerFolderItemClicked = onFolderItemClicked,
|
||||
settingsActionTriggered = settingsActionTriggered,
|
||||
)
|
||||
}
|
||||
@ -209,41 +223,16 @@ fun MainPlayer(
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
|
||||
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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Breadcrumb(
|
||||
folder = currentFolder,
|
||||
onFolderClicked = onFolderItemClicked,
|
||||
)
|
||||
|
||||
folders.forEach { folder ->
|
||||
ListItem(
|
||||
modifier = Modifier.clickable { },
|
||||
modifier = Modifier.clickable {
|
||||
onFolderItemClicked(folder)
|
||||
},
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.FolderOpen,
|
||||
|
Loading…
Reference in New Issue
Block a user