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,43 +2,31 @@ 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
@Preview(showBackground = true)
@Composable @Composable
fun AddServerScreen( fun StepEnterApiUrl(
onCloseActionTriggered: () -> Unit = {}, urlStr: String = "",
onUrlStrChange: (String) -> Unit = {},
) { ) {
Scaffold(
topBar = {
TopAppBar(
backgroundColor = Color.Transparent,
elevation = 0.dp,
title = {},
navigationIcon = {
IconButton(onClick = onCloseActionTriggered) {
Icon(imageVector = Icons.Filled.Close, contentDescription = "Close")
}
},
)
}
) {
Column( Column(
modifier = Modifier modifier = Modifier.fillMaxSize(),
.fillMaxSize() horizontalAlignment = Alignment.CenterHorizontally,
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Icon( Icon(
modifier = Modifier.size(50.dp), modifier = Modifier.size(50.dp),
@ -65,27 +53,151 @@ fun AddServerScreen(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(vertical = 10.dp), .padding(vertical = 10.dp),
value = "", keyboardOptions = KeyboardOptions(
onValueChange = {}, keyboardType = KeyboardType.Uri,
),
value = urlStr,
onValueChange = onUrlStrChange,
label = { Text("Server API Url") }, label = { Text("Server API Url") },
) )
Spacer(modifier = Modifier.weight(1f)) }
}
@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)
@Composable
fun AddServerScreen(
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(
topBar = {
TopAppBar(
backgroundColor = Color.Transparent,
elevation = 0.dp,
title = {},
navigationIcon = {
IconButton(onClick = onCloseActionTriggered) {
Icon(imageVector = Icons.Filled.Close, contentDescription = "Close")
}
},
)
}
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
var urlStr by rememberSaveable { mutableStateOf("") }
var nameStr by rememberSaveable { mutableStateOf("") }
var baseFolderNameStr by rememberSaveable { mutableStateOf("") }
Column(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
) {
when (stepState) {
0 -> {
StepEnterApiUrl(
urlStr,
onUrlStrChange = { value ->
urlStr = value
},
)
}
1 -> {
StepOtherDetail(
nameStr,
onNameStrChange = { value ->
nameStr = value
},
baseFolderNameStr,
onBaseFolderNameStrChange = { value ->
baseFolderNameStr = value
},
)
}
}
}
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)
) )
} }