now able to add server from the UI

This commit is contained in:
Gary Wang 2021-11-16 23:46:39 +08:00
parent 9e98340fd2
commit 1d2ded1eee
6 changed files with 178 additions and 62 deletions

View File

@ -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
View 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

View File

@ -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) {

View File

@ -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()
} }

View File

@ -66,6 +66,10 @@ fun NavGraph(
AddServerScreen( AddServerScreen(
onCloseActionTriggered = { onCloseActionTriggered = {
navController.navigateUp() navController.navigateUp()
},
onSubmitServerTriggered = { srv ->
viewModel.addServer(srv)
navController.navigateUp()
} }
) )
} }

View File

@ -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)
) )
} }