now able to add server from the UI
This commit is contained in:
parent
9e98340fd2
commit
1d2ded1eee
|
@ -1,6 +0,0 @@
|
||||||
TODO:
|
|
||||||
|
|
||||||
- [ ] Add server
|
|
||||||
- [ ] Music playback
|
|
||||||
- [ ] Download music to local folder
|
|
||||||
- [ ] Back key to navigate folder up
|
|
23
README.org
Normal file
23
README.org
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
TODO
|
||||||
|
|
||||||
|
* TODO Add server
|
||||||
|
|
||||||
|
- [x] Create
|
||||||
|
- [ ] Delete
|
||||||
|
- [ ] Update
|
||||||
|
|
||||||
|
* TODO Music playback
|
||||||
|
|
||||||
|
- [ ] Regular playback
|
||||||
|
- [ ] Playlist
|
||||||
|
- [ ] Media session
|
||||||
|
|
||||||
|
* TODO Download music to local folder
|
||||||
|
|
||||||
|
- [ ] Select and remember selected folder
|
||||||
|
- [ ] Download music
|
||||||
|
|
||||||
|
* TODO Misc.
|
||||||
|
|
||||||
|
- [ ] Back key to navigate folder up
|
||||||
|
|
|
@ -36,33 +36,13 @@ class MainViewModel(private val repository: ServerRepository) : ViewModel() {
|
||||||
_currentFolder.postValue(folder)
|
_currentFolder.postValue(folder)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val _drawerFolders: MutableLiveData<List<Folder>> = MutableLiveData(
|
private val _drawerFolders: MutableLiveData<List<Folder>> = MutableLiveData(listOf())
|
||||||
listOf(
|
|
||||||
Folder("Test/"),
|
|
||||||
Folder("Folder/"),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val drawerFolders: LiveData<List<Folder>> = _drawerFolders
|
val drawerFolders: LiveData<List<Folder>> = _drawerFolders
|
||||||
|
|
||||||
private val _folders: MutableLiveData<List<Folder>> = MutableLiveData(
|
private val _folders: MutableLiveData<List<Folder>> = MutableLiveData(listOf())
|
||||||
listOf(
|
|
||||||
Folder("Test/Converted-Modules/")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val folders: LiveData<List<Folder>> = _folders
|
val folders: LiveData<List<Folder>> = _folders
|
||||||
|
|
||||||
private val _songs: MutableLiveData<List<Song>> = MutableLiveData(
|
private val _songs: MutableLiveData<List<Song>> = MutableLiveData(listOf())
|
||||||
listOf(
|
|
||||||
Song(
|
|
||||||
filePath = "Test/Rick Astley - Never Gonna Give You Up.mp3",
|
|
||||||
url = "http://localhost/rickroll.mp3"
|
|
||||||
),
|
|
||||||
Song(
|
|
||||||
filePath = "Test/哇 好东西一堆.xm",
|
|
||||||
url = "http://localhost/rickroll.mp3"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
val songs: LiveData<List<Song>> = _songs
|
val songs: LiveData<List<Song>> = _songs
|
||||||
|
|
||||||
fun fetchServer(srv: Server) {
|
fun fetchServer(srv: Server) {
|
||||||
|
|
|
@ -26,6 +26,9 @@ interface ServerDao {
|
||||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||||
suspend fun insert(server: Server)
|
suspend fun insert(server: Server)
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
suspend fun delete(server: Server)
|
||||||
|
|
||||||
@Query("DELETE FROM server_table")
|
@Query("DELETE FROM server_table")
|
||||||
suspend fun deleteAll()
|
suspend fun deleteAll()
|
||||||
}
|
}
|
|
@ -66,6 +66,10 @@ fun NavGraph(
|
||||||
AddServerScreen(
|
AddServerScreen(
|
||||||
onCloseActionTriggered = {
|
onCloseActionTriggered = {
|
||||||
navController.navigateUp()
|
navController.navigateUp()
|
||||||
|
},
|
||||||
|
onSubmitServerTriggered = { srv ->
|
||||||
|
viewModel.addServer(srv)
|
||||||
|
navController.navigateUp()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,24 +2,119 @@ package net.blumia.pcmdroid.ui.screen.addserver
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
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.AddCircle
|
import androidx.compose.material.icons.filled.AddCircle
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.rounded.AddCircle
|
import androidx.compose.material.icons.rounded.AddCircle
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.*
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
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.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
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 net.blumia.pcmdroid.model.Server
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun StepEnterApiUrl(
|
||||||
|
urlStr: String = "",
|
||||||
|
onUrlStrChange: (String) -> Unit = {},
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(50.dp),
|
||||||
|
imageVector = Icons.Filled.AddCircle,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 10.dp),
|
||||||
|
text = "Add Server",
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
style = MaterialTheme.typography.h5,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 10.dp),
|
||||||
|
text = "Add Private Cloud Music server",
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
style = MaterialTheme.typography.subtitle2,
|
||||||
|
)
|
||||||
|
OutlinedTextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 10.dp),
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Uri,
|
||||||
|
),
|
||||||
|
value = urlStr,
|
||||||
|
onValueChange = onUrlStrChange,
|
||||||
|
label = { Text("Server API Url") },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun StepOtherDetail(
|
||||||
|
nameStr: String = "",
|
||||||
|
onNameStrChange: (String) -> Unit = {},
|
||||||
|
baseFolderNameStr: String = "",
|
||||||
|
onBaseFolderNameStrChange: (String) -> Unit = {},
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 10.dp),
|
||||||
|
value = nameStr,
|
||||||
|
onValueChange = onNameStrChange,
|
||||||
|
label = { Text("Server name") },
|
||||||
|
)
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 10.dp),
|
||||||
|
value = baseFolderNameStr,
|
||||||
|
onValueChange = onBaseFolderNameStrChange,
|
||||||
|
label = { Text("Base folder name") },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
fun AddServerScreen(
|
fun AddServerScreen(
|
||||||
onCloseActionTriggered: () -> Unit = {},
|
onCloseActionTriggered: () -> Unit = {},
|
||||||
|
onSubmitServerTriggered: (Server) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
|
var stepState by remember { mutableStateOf(0) }
|
||||||
|
val finalStep = 1
|
||||||
|
|
||||||
|
fun onNextStepButtonTriggered() {
|
||||||
|
if (stepState < 1) {
|
||||||
|
stepState++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPreviousStepButtonTriggered() {
|
||||||
|
if (stepState > 0) {
|
||||||
|
stepState--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
|
@ -40,52 +135,69 @@ fun AddServerScreen(
|
||||||
.padding(20.dp),
|
.padding(20.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Icon(
|
var urlStr by rememberSaveable { mutableStateOf("") }
|
||||||
modifier = Modifier.size(50.dp),
|
var nameStr by rememberSaveable { mutableStateOf("") }
|
||||||
imageVector = Icons.Filled.AddCircle,
|
var baseFolderNameStr by rememberSaveable { mutableStateOf("") }
|
||||||
contentDescription = null,
|
|
||||||
)
|
Column(
|
||||||
Text(
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 10.dp),
|
.weight(1f)
|
||||||
text = "Add Server",
|
) {
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
style = MaterialTheme.typography.h5,
|
when (stepState) {
|
||||||
)
|
0 -> {
|
||||||
Text(
|
StepEnterApiUrl(
|
||||||
modifier = Modifier
|
urlStr,
|
||||||
.fillMaxWidth()
|
onUrlStrChange = { value ->
|
||||||
.padding(bottom = 10.dp),
|
urlStr = value
|
||||||
text = "Add Private Cloud Music server",
|
},
|
||||||
textAlign = TextAlign.Center,
|
)
|
||||||
style = MaterialTheme.typography.subtitle2,
|
}
|
||||||
)
|
1 -> {
|
||||||
OutlinedTextField(
|
StepOtherDetail(
|
||||||
modifier = Modifier
|
nameStr,
|
||||||
.fillMaxWidth()
|
onNameStrChange = { value ->
|
||||||
.padding(vertical = 10.dp),
|
nameStr = value
|
||||||
value = "",
|
},
|
||||||
onValueChange = {},
|
baseFolderNameStr,
|
||||||
label = { Text("Server API Url") },
|
onBaseFolderNameStrChange = { value ->
|
||||||
)
|
baseFolderNameStr = value
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = { /*TODO*/ },
|
onClick = ::onPreviousStepButtonTriggered,
|
||||||
enabled = false
|
enabled = stepState != 0,
|
||||||
) {
|
) {
|
||||||
Text("Back")
|
Text("Back")
|
||||||
}
|
}
|
||||||
Button(
|
Button(
|
||||||
onClick = { /*TODO*/ },
|
onClick = {
|
||||||
|
if (stepState != finalStep) {
|
||||||
|
onNextStepButtonTriggered()
|
||||||
|
} else {
|
||||||
|
val srv = Server(
|
||||||
|
url = urlStr,
|
||||||
|
name = nameStr,
|
||||||
|
baseFolderName = baseFolderNameStr,
|
||||||
|
)
|
||||||
|
onSubmitServerTriggered(srv)
|
||||||
|
}
|
||||||
|
},
|
||||||
shape = RoundedCornerShape(50)
|
shape = RoundedCornerShape(50)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "Next",
|
text = if (stepState != finalStep) "Next" else "Done",
|
||||||
modifier = Modifier.padding(horizontal = 5.dp)
|
modifier = Modifier.padding(horizontal = 5.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user