android: Refactor settings UI into screens and add a bottom bar.
This puts Status, logs, and settings all on different tabs. This gives us plenty more room to work to improve these views going forward
This commit is contained in:
parent
380e0abbe4
commit
5b7de2bc2f
@ -61,6 +61,7 @@ dependencies {
|
||||
implementation("androidx.compose.material:material-icons-extended")
|
||||
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.6.2")
|
||||
implementation("androidx.navigation:navigation-compose:2.7.6")
|
||||
|
||||
implementation("com.github.alorma:compose-settings-ui-m3:1.0.3")
|
||||
implementation("com.github.alorma:compose-settings-storage-preferences:1.0.3")
|
||||
|
@ -28,7 +28,7 @@
|
||||
android:theme="@style/Theme.MPD"
|
||||
android:name=".MPDApplication">
|
||||
<activity
|
||||
android:name=".ui.SettingsActivity"
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
@ -27,7 +27,6 @@ import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.session.MediaSession;
|
||||
|
||||
import org.musicpd.data.LoggingRepository;
|
||||
import org.musicpd.ui.SettingsActivity;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
@ -208,7 +207,7 @@ public class Main extends Service implements Runnable {
|
||||
}
|
||||
}, filter);
|
||||
|
||||
final Intent mainIntent = new Intent(this, SettingsActivity.class);
|
||||
final Intent mainIntent = new Intent(this, MainActivity.class);
|
||||
mainIntent.setAction("android.intent.action.MAIN");
|
||||
mainIntent.addCategory("android.intent.category.LAUNCHER");
|
||||
final PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
||||
|
57
android/app/src/main/java/org/musicpd/MainActivity.kt
Normal file
57
android/app/src/main/java/org/musicpd/MainActivity.kt
Normal file
@ -0,0 +1,57 @@
|
||||
package org.musicpd
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.core.view.WindowCompat
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.musicpd.ui.MPDApp
|
||||
import org.musicpd.ui.SettingsViewModel
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : ComponentActivity() {
|
||||
private val settingsViewModel: SettingsViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
setContent {
|
||||
MaterialTheme {
|
||||
MPDApp(settingsViewModel = settingsViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun connectClient() {
|
||||
val client = Main.Client(this, object : Main.Client.Callback {
|
||||
override fun onStopped() {
|
||||
settingsViewModel.updateStatus("", false)
|
||||
}
|
||||
|
||||
override fun onStarted() {
|
||||
settingsViewModel.updateStatus("MPD Service Started", true)
|
||||
}
|
||||
|
||||
override fun onError(error: String) {
|
||||
settingsViewModel.removeClient()
|
||||
settingsViewModel.updateStatus(error, false)
|
||||
connectClient()
|
||||
}
|
||||
})
|
||||
|
||||
settingsViewModel.setClient(client)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
//mFirstRun = false
|
||||
connectClient()
|
||||
super.onStart()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
settingsViewModel.removeClient()
|
||||
super.onStop()
|
||||
}
|
||||
}
|
36
android/app/src/main/java/org/musicpd/ui/LogScreen.kt
Normal file
36
android/app/src/main/java/org/musicpd/ui/LogScreen.kt
Normal file
@ -0,0 +1,36 @@
|
||||
package org.musicpd.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun LogView(messages: State<List<String>>) {
|
||||
val state = rememberLazyListState()
|
||||
|
||||
Column(Modifier.fillMaxSize()) {
|
||||
LazyColumn(
|
||||
Modifier.padding(4.dp),
|
||||
state
|
||||
) {
|
||||
items(messages.value) { message ->
|
||||
Text(text = message, fontFamily = FontFamily.Monospace)
|
||||
}
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
state.scrollToItem(messages.value.count(), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
112
android/app/src/main/java/org/musicpd/ui/MainScreen.kt
Normal file
112
android/app/src/main/java/org/musicpd/ui/MainScreen.kt
Normal file
@ -0,0 +1,112 @@
|
||||
package org.musicpd.ui
|
||||
|
||||
import MPDSettings
|
||||
import android.graphics.drawable.Icon
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Circle
|
||||
import androidx.compose.material.icons.filled.Home
|
||||
import androidx.compose.material.icons.filled.List
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavController
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
|
||||
enum class Screen {
|
||||
HOME,
|
||||
LOGS,
|
||||
SETTINGS,
|
||||
}
|
||||
sealed class NavigationItem(val route: String, val label: String, val icon: ImageVector) {
|
||||
data object Home : NavigationItem(
|
||||
Screen.HOME.name,
|
||||
"Home",
|
||||
Icons.Default.Home
|
||||
)
|
||||
data object Logs : NavigationItem(
|
||||
Screen.LOGS.name,
|
||||
"Logs",
|
||||
Icons.Default.List)
|
||||
data object Settings : NavigationItem(
|
||||
Screen.SETTINGS.name,
|
||||
"Settings",
|
||||
Icons.Default.Settings)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MPDApp(
|
||||
navController: NavHostController = rememberNavController(),
|
||||
settingsViewModel: SettingsViewModel = viewModel()
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
|
||||
},
|
||||
bottomBar = {
|
||||
BottomNavigationBar(navController)
|
||||
},
|
||||
) { innerPadding ->
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = NavigationItem.Home.route,
|
||||
modifier = Modifier.padding(innerPadding)
|
||||
) {
|
||||
composable(NavigationItem.Home.route) {
|
||||
StatusScreen(settingsViewModel)
|
||||
}
|
||||
composable(NavigationItem.Logs.route) {
|
||||
LogView(settingsViewModel.getLogs().collectAsStateWithLifecycle())
|
||||
}
|
||||
composable(NavigationItem.Settings.route) {
|
||||
MPDSettings(settingsViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BottomNavigationBar(navController: NavController) {
|
||||
val navBackStackEntry by navController.currentBackStackEntryAsState()
|
||||
val currentRoute = navBackStackEntry?.destination?.route
|
||||
|
||||
val items = listOf(
|
||||
NavigationItem.Home,
|
||||
NavigationItem.Logs,
|
||||
NavigationItem.Settings,
|
||||
)
|
||||
|
||||
NavigationBar {
|
||||
items.forEach { item ->
|
||||
NavigationBarItem(
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = item.icon,
|
||||
contentDescription = null
|
||||
)
|
||||
},
|
||||
label = { Text (item.label) },
|
||||
onClick = {
|
||||
navController.navigate(item.route) {
|
||||
popUpTo(navController.graph.startDestinationId)
|
||||
launchSingleTop = true
|
||||
}
|
||||
},
|
||||
selected = currentRoute == item.route,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,210 +0,0 @@
|
||||
package org.musicpd.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Circle
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.isGranted
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import com.google.accompanist.permissions.shouldShowRationale
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.musicpd.Main
|
||||
import org.musicpd.R
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SettingsActivity : ComponentActivity() {
|
||||
|
||||
private val settingsViewModel: SettingsViewModel by viewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContent {
|
||||
MaterialTheme {
|
||||
SettingsContainer(settingsViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun connectClient() {
|
||||
val client = Main.Client(this, object : Main.Client.Callback {
|
||||
override fun onStopped() {
|
||||
settingsViewModel.updateStatus("", false)
|
||||
}
|
||||
|
||||
override fun onStarted() {
|
||||
settingsViewModel.updateStatus("MPD Service Started", true)
|
||||
}
|
||||
|
||||
override fun onError(error: String) {
|
||||
settingsViewModel.removeClient()
|
||||
settingsViewModel.updateStatus(error, false)
|
||||
connectClient()
|
||||
}
|
||||
})
|
||||
|
||||
settingsViewModel.setClient(client)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
//mFirstRun = false
|
||||
connectClient()
|
||||
super.onStart()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
settingsViewModel.removeClient()
|
||||
super.onStop()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
fun SettingsContainer(settingsViewModel: SettingsViewModel = viewModel()) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val storagePermissionState = rememberPermissionState(
|
||||
android.Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
)
|
||||
|
||||
if (storagePermissionState.status.shouldShowRationale) {
|
||||
Column(Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(stringResource(id = R.string.external_files_permission_request))
|
||||
Button(onClick = { }) {
|
||||
Text("Request permission")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Column {
|
||||
NetworkAddress()
|
||||
ServerStatus(settingsViewModel)
|
||||
if (!storagePermissionState.status.isGranted) {
|
||||
OutlinedButton(onClick = { storagePermissionState.launchPermissionRequest() }, Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxWidth()) {
|
||||
Text("Request external storage permission", color = MaterialTheme.colorScheme.secondary)
|
||||
}
|
||||
}
|
||||
SettingsOptions(
|
||||
onBootChanged = { newValue ->
|
||||
if (newValue) {
|
||||
settingsViewModel.startMPD(context)
|
||||
}
|
||||
},
|
||||
onWakeLockChanged = { newValue ->
|
||||
settingsViewModel.setWakelockEnabled(newValue)
|
||||
},
|
||||
onHeadphonesChanged = { newValue ->
|
||||
settingsViewModel.setPauseOnHeadphonesDisconnect(newValue)
|
||||
}
|
||||
)
|
||||
LogView(settingsViewModel.getLogs().collectAsStateWithLifecycle())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ServerStatus(settingsViewModel: SettingsViewModel) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val statusUiState by settingsViewModel.statusUIState.collectAsState()
|
||||
|
||||
Column {
|
||||
Row(
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
Row {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Circle,
|
||||
contentDescription = "",
|
||||
tint = if (statusUiState.running) Color(0xFFB8F397) else Color(0xFFFFDAD6)
|
||||
)
|
||||
Text(text = if (statusUiState.running) "Running" else "Stopped")
|
||||
}
|
||||
Button(onClick = {
|
||||
if (statusUiState.running)
|
||||
settingsViewModel.stopMPD()
|
||||
else
|
||||
settingsViewModel.startMPD(context)
|
||||
}) {
|
||||
Text(text = if (statusUiState.running) "Stop MPD" else "Start MPD")
|
||||
}
|
||||
}
|
||||
Row(
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
Text(text = statusUiState.statusMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LogView(messages: State<List<String>>) {
|
||||
val state = rememberLazyListState()
|
||||
|
||||
LazyColumn(
|
||||
Modifier.padding(4.dp),
|
||||
state
|
||||
) {
|
||||
items(messages.value) { message ->
|
||||
Text(text = message, fontFamily = FontFamily.Monospace)
|
||||
}
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
state.scrollToItem(messages.value.count(), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun SettingsPreview() {
|
||||
MaterialTheme {
|
||||
SettingsContainer()
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
package org.musicpd.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.BatteryAlert
|
||||
import androidx.compose.material.icons.filled.Headphones
|
||||
@ -7,11 +7,35 @@ import androidx.compose.material.icons.filled.PowerSettingsNew
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.alorma.compose.settings.storage.preferences.rememberPreferenceBooleanSettingState
|
||||
import com.alorma.compose.settings.ui.SettingsSwitch
|
||||
import org.musicpd.Preferences
|
||||
import org.musicpd.R
|
||||
import org.musicpd.ui.SettingsViewModel
|
||||
|
||||
@Composable
|
||||
fun MPDSettings(settingsViewModel: SettingsViewModel) {
|
||||
val context = LocalContext.current
|
||||
|
||||
Column(Modifier.fillMaxSize()) {
|
||||
SettingsOptions(
|
||||
onBootChanged = { newValue ->
|
||||
if (newValue) {
|
||||
settingsViewModel.startMPD(context)
|
||||
}
|
||||
},
|
||||
onWakeLockChanged = { newValue ->
|
||||
settingsViewModel.setWakelockEnabled(newValue)
|
||||
},
|
||||
onHeadphonesChanged = { newValue ->
|
||||
settingsViewModel.setPauseOnHeadphonesDisconnect(newValue)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsOptions(
|
||||
@ -49,4 +73,4 @@ fun SettingsOptions(
|
||||
state = headphoneState
|
||||
)
|
||||
|
||||
}
|
||||
}
|
119
android/app/src/main/java/org/musicpd/ui/StatusScreen.kt
Normal file
119
android/app/src/main/java/org/musicpd/ui/StatusScreen.kt
Normal file
@ -0,0 +1,119 @@
|
||||
package org.musicpd.ui
|
||||
|
||||
import android.Manifest
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Circle
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.isGranted
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
import com.google.accompanist.permissions.shouldShowRationale
|
||||
import org.musicpd.R
|
||||
|
||||
@OptIn(ExperimentalPermissionsApi::class)
|
||||
@Composable
|
||||
fun StatusScreen(settingsViewModel: SettingsViewModel) {
|
||||
val storagePermissionState = rememberPermissionState(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
)
|
||||
|
||||
if (storagePermissionState.status.shouldShowRationale) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(stringResource(id = R.string.external_files_permission_request))
|
||||
Button(onClick = { }) {
|
||||
Text("Request permission")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
NetworkAddress()
|
||||
ServerStatus(settingsViewModel)
|
||||
if (!storagePermissionState.status.isGranted) {
|
||||
OutlinedButton(
|
||||
onClick = { storagePermissionState.launchPermissionRequest() }, Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
"Request external storage permission",
|
||||
color = MaterialTheme.colorScheme.secondary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ServerStatus(settingsViewModel: SettingsViewModel) {
|
||||
val context = LocalContext.current
|
||||
|
||||
val statusUiState by settingsViewModel.statusUIState.collectAsState()
|
||||
|
||||
Column {
|
||||
Row(
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
Row {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Circle,
|
||||
contentDescription = "",
|
||||
tint = if (statusUiState.running) Color(0xFFB8F397) else Color(0xFFFFDAD6)
|
||||
)
|
||||
Text(text = if (statusUiState.running) "Running" else "Stopped")
|
||||
}
|
||||
Button(onClick = {
|
||||
if (statusUiState.running)
|
||||
settingsViewModel.stopMPD()
|
||||
else
|
||||
settingsViewModel.startMPD(context)
|
||||
}) {
|
||||
Text(text = if (statusUiState.running) "Stop MPD" else "Start MPD")
|
||||
}
|
||||
}
|
||||
Row(
|
||||
Modifier
|
||||
.padding(4.dp)
|
||||
.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
Text(text = statusUiState.statusMessage)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user