pre-build

This commit is contained in:
Assasinnys 2022-11-17 22:26:50 +03:00
parent 0500756be8
commit 75baf06c46
4 changed files with 110 additions and 119 deletions

View File

@ -68,4 +68,6 @@ dependencies {
implementation "com.squareup.moshi:moshi:1.14.0"
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.14.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1"
}

View File

@ -1,105 +1,45 @@
package com.dmitryzenevich.remoteaudiocontrol.presentation
import android.annotation.SuppressLint
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
import androidx.lifecycle.lifecycleScope
import com.dmitryzenevich.remoteaudiocontrol.presentation.theme.RemoteAudioControlTheme
import androidx.lifecycle.viewmodel.compose.viewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlin.math.roundToInt
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
private val viewModel by viewModels<MainViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
RemoteAudioControlTheme {
val uiState by viewModel.uiState.collectAsState()
LazyRow {
items(uiState.volumes) { itemState ->
VolumeItem(itemState, viewModel)
}
}
MainScreen()
}
}
}
}
@Composable
fun VolumeItem(volumeItemState: VolumeItemState, viewModel: MainViewModel) {
var volume by remember { mutableStateOf(volumeItemState.volume) }
volume = volumeItemState.volume
val onValueChanged = { newValue: Float ->
Log.i("debug", "new value: $newValue")
viewModel.onVolumeChanged(volumeItemState, newValue.toInt())
volume = newValue.toInt()
}
fun MainScreen(viewModel: MainViewModel = viewModel()) {
val uiState by viewModel.uiState.collectAsState()
Column(
modifier = Modifier
.padding(8.dp)
.wrapContentSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "${volumeItemState.name}\nVolume: ${volumeItemState.volume}"
)
VerticalSlider(
value = /*volumeItemState.volume.toFloat()*/volume.toFloat(),
onValueChanged = onValueChanged
)
}
}
@Composable
fun VerticalSlider(
value: Float,
onValueChanged: (Float) -> Unit
) {
Slider(
value = value,
valueRange = 0f..100f,
steps = 99,
onValueChange = onValueChanged,
modifier = Modifier
.graphicsLayer {
rotationZ = 270f
transformOrigin = TransformOrigin(0f, 0f)
}
.layout { measurable, constraints ->
val placeable = measurable.measure(
Constraints(
minWidth = constraints.minHeight,
maxWidth = constraints.maxHeight,
minHeight = constraints.minWidth,
maxHeight = constraints.maxHeight,
)
)
layout(placeable.height, placeable.width) {
placeable.place(-placeable.width, 0)
LazyRow {
items(
items = uiState.volumes,
key = { item -> item.pid }
) { itemState ->
VolumeItem(
volumeItemState = itemState,
onValueChanged = { newValue: Float ->
Log.i("debug", "new value: $newValue")
viewModel.onVolumeChanged(itemState, newValue.toInt())
}
}
.padding(horizontal = 24.dp)
)
)
}
}
}

View File

@ -1,6 +1,11 @@
package com.dmitryzenevich.remoteaudiocontrol.presentation
import android.util.Log
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dmitryzenevich.remoteaudiocontrol.data.SocketRepositoryImpl
@ -9,7 +14,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import javax.inject.Inject
import kotlin.math.absoluteValue
@HiltViewModel
class MainViewModel @Inject constructor(
@ -23,7 +27,7 @@ class MainViewModel @Inject constructor(
init {
viewModelScope.launch {
val isReady = socketRepositoryImpl.openSocketConnection("10.0.2.2", 54683)
val isReady = socketRepositoryImpl.openSocketConnection(/*"10.0.2.2"*/"192.168.100.9", 54683)
if (isReady) {
socketRepositoryImpl.bindSocketInput()
.filterNotNull()
@ -39,23 +43,18 @@ class MainViewModel @Inject constructor(
}
private fun proceedEvent(event: Event) {
val volumes = _uiState.value.volumes.toMutableList()
val volumes = _uiState.value.volumes
when(event) {
is NewSessionEvent -> {
// if (_uiState.value.volumes.find { it.pid == event.PID } == null) {
// _uiState.value = MainScreenUiState(volumes = _uiState.value.volumes + event.toVolumeItemState())
// }
}
is NewSessionEvent -> addIfNotExist(event)
is MuteStateChangedEvent -> {
volumes.find { event.PID == it.pid }?.let { item ->
val newItem = item.copy(isMuted = event.isMuted)
volumes.set(
volumes.set(
index = volumes.indexOfFirst { it.pid == newItem.pid },
element = newItem
)
}
_uiState.value = _uiState.value.copy(volumes = volumes)
}
is SetNameEvent -> {
volumes.find { event.PID == it.pid }?.let { item ->
@ -65,7 +64,6 @@ class MainViewModel @Inject constructor(
element = newItem
)
}
_uiState.value = _uiState.value.copy(volumes = volumes)
}
is StateChangedEvent -> {
volumes.find { event.PID == it.pid }?.let { item ->
@ -75,40 +73,24 @@ class MainViewModel @Inject constructor(
element = newItem
)
}
_uiState.value = _uiState.value.copy(volumes = volumes)
}
is VolumeChangedEvent -> {
addIfNotExist(event)
val v = _uiState.value.volumes.toMutableList()
v.find { event.PID == it.pid }?.let { item ->
val newItem = item.copy(volume = event.volume)
v.set(
index = v.indexOfFirst { it.pid == newItem.pid },
element = newItem
)
volumes.find { event.PID == it.pid }?.let { item ->
// val newItem = item.copy(volume = event.volume)
// volumes.set(
// index = volumes.indexOfFirst { it.pid == newItem.pid },
// element = newItem
// )
item.volume.value = event.volume
}
_uiState.value = _uiState.value.copy(volumes = v)
}
UnknownEvent -> _uiState.value = _uiState.value.copy(isError = true)
UnknownEvent -> _uiState.value.isError // TODO: implement error state
}
}
fun onVolumeChanged(volumeItemState: VolumeItemState, newVolume: Int) {
Log.i(javaClass.simpleName, "old volume: ${volumeItemState.volume}, newVolume: $newVolume")
val increment = newVolume.minus(volumeItemState.volume)
Log.i(javaClass.simpleName, "increment: $increment")
// val volumes = _uiState.value.volumes.toMutableList()
// volumes.find { volumeItemState.pid == it.pid }?.let { item ->
// val newItem = item.copy(volume = newVolume)
// volumes.set(
// index = volumes.indexOfFirst { it.pid == newItem.pid },
// element = newItem
// )
// }
// _uiState.value = _uiState.value.copy(volumes = volumes)
volumeItemState.volume.value = newVolume
sendCommand(SetVolumeCommand(volumeItemState.pid, newVolume))
}
@ -117,27 +99,27 @@ class MainViewModel @Inject constructor(
commandJob = viewModelScope.launch { socketRepositoryImpl.sendCommand(command) }
}
private fun addIfNotExist(event: VolumeChangedEvent) {
private fun addIfNotExist(event: NewSessionEvent) {
if (_uiState.value.volumes.find { it.pid == event.PID } == null) {
_uiState.value = MainScreenUiState(volumes = _uiState.value.volumes + event.toVolumeItemState())
_uiState.value.volumes.add(event.toVolumeItemState())
}
}
}
data class MainScreenUiState(
val volumes: List<VolumeItemState> = emptyList(),
class MainScreenUiState(
val volumes: SnapshotStateList<VolumeItemState> = mutableStateListOf(),
val isError: Boolean = false
)
data class VolumeItemState(
val pid: Long,
val name: String = "",
val volume: Int = 0,
val volume: MutableState<Int> = mutableStateOf(0),
val isMuted: Boolean = false,
val isActive: Boolean = false
)
fun NewSessionEvent.toVolumeItemState() = VolumeItemState(pid = PID)
fun VolumeChangedEvent.toVolumeItemState() = VolumeItemState(pid = PID, volume = volume)
//fun VolumeChangedEvent.toVolumeItemState() = VolumeItemState(pid = PID, volume = volume)

View File

@ -0,0 +1,67 @@
package com.dmitryzenevich.remoteaudiocontrol.presentation
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
@Composable
fun VolumeItem(
volumeItemState: VolumeItemState,
onValueChanged: (Float) -> Unit
) {
Column(
modifier = Modifier
.padding(8.dp)
.wrapContentSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "${volumeItemState.name}\nVolume: ${volumeItemState.volume.value}"
)
VerticalSlider(
value = volumeItemState.volume.value.toFloat(),
onValueChanged = onValueChanged
)
}
}
@Composable
fun VerticalSlider(
value: Float,
onValueChanged: (Float) -> Unit
) {
Slider(
value = value,
valueRange = 0f..100f,
onValueChange = onValueChanged,
modifier = Modifier
.graphicsLayer {
rotationZ = 270f
transformOrigin = TransformOrigin(0f, 0f)
}
.layout { measurable, constraints ->
val placeable = measurable.measure(
Constraints(
minWidth = constraints.minHeight,
maxWidth = constraints.maxHeight,
minHeight = constraints.minWidth,
maxHeight = constraints.maxHeight,
)
)
layout(placeable.height, placeable.width) {
placeable.place(-placeable.width, 0)
}
}
.padding(horizontal = 24.dp)
)
}