Switched to LiveData as stated in the specification

This commit is contained in:
Balazs Toldi 2021-11-23 09:02:45 +01:00
parent a4e760f9d1
commit dcac6e7801
Signed by: Bazsalanszky
GPG key ID: 933820884952BE27
4 changed files with 107 additions and 70 deletions

View file

@ -8,7 +8,21 @@
<entry key="../../../../../layout/compose-model-1633594045878.xml" value="1.0" /> <entry key="../../../../../layout/compose-model-1633594045878.xml" value="1.0" />
<entry key="../../../../../layout/compose-model-1633596772266.xml" value="0.18285472972972974" /> <entry key="../../../../../layout/compose-model-1633596772266.xml" value="0.18285472972972974" />
<entry key="../../../../../layout/compose-model-1633601146222.xml" value="0.18285472972972974" /> <entry key="../../../../../layout/compose-model-1633601146222.xml" value="0.18285472972972974" />
<entry key="../../../../../layout/compose-model-1634022040984.xml" value="0.3037037037037037" /> <entry key="../../../../../layout/compose-model-1633617799626.xml" value="0.3095439189189189" />
<entry key="../../../../../layout/compose-model-1633617944748.xml" value="0.4962962962962963" />
<entry key="../../../../../layout/compose-model-1633767363997.xml" value="0.17905405405405406" />
<entry key="../../../../../layout/compose-model-1634889935306.xml" value="0.3095439189189189" />
<entry key="../../../../../layout/compose-model-1634890564069.xml" value="0.4861111111111111" />
<entry key="../../../../../layout/compose-model-1634891321942.xml" value="0.33" />
<entry key="../../../../../layout/compose-model-1634891753898.xml" value="1.0" />
<entry key="../../../../../layout/compose-model-1634893431951.xml" value="0.3095439189189189" />
<entry key="../../../../../layout/compose-model-1634898066813.xml" value="0.3095439189189189" />
<entry key="../../../../../layout/compose-model-1634898107086.xml" value="0.4759259259259259" />
<entry key="../../../../../layout/compose-model-1634990577157.xml" value="0.4703703703703704" />
<entry key="../../../../../layout/compose-model-1637651431048.xml" value="0.3611111111111111" />
<entry key="../../../../../layout/compose-model-1637651867699.xml" value="0.3095439189189189" />
<entry key="../../../../../layout/compose-model-1637652867578.xml" value="0.36018518518518516" />
<entry key="../../../../../layout/compose-model-1637653004789.xml" value="0.45740740740740743" />
</map> </map>
</option> </option>
</component> </component>
@ -19,7 +33,7 @@
<option name="HEAP_SIZE" value="256" /> <option name="HEAP_SIZE" value="256" />
<option name="LOCALE" value="en" /> <option name="LOCALE" value="en" />
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="JDK" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" /> <output url="file://$PROJECT_DIR$/build/classes" />
</component> </component>
<component name="ProjectType"> <component name="ProjectType">

View file

@ -7,23 +7,19 @@ import android.util.Log
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.*
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.LazyColumn
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.Menu import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.Share
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
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 androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import eu.toldi.balazs.caster.model.ChromeCastViewModel import eu.toldi.balazs.caster.model.ChromeCastViewModel
import eu.toldi.balazs.caster.ui.theme.CasterTheme import eu.toldi.balazs.caster.ui.theme.CasterTheme
import kotlinx.coroutines.* import kotlinx.coroutines.*
@ -44,27 +40,33 @@ class MainActivity : ComponentActivity() {
setContent { setContent {
CasterTheme { CasterTheme {
val viewModel = ViewModelProvider(this).get(ChromeCastViewModel::class.java) val viewModel = ViewModelProvider(this).get(ChromeCastViewModel::class.java)
GlobalScope.launch(IO) { viewModel.startScanning()
ChromeCasts.startDiscovery(getIPv4Address())
}
val chromeCasts = viewModel.chromeCasts.value val chromeCastState = viewModel._chromecasts.observeAsState(initial = emptyList())
val chromeCasts = chromeCastState.value
Log.e(null,chromeCasts.toString())
// A surface container using the 'background' color from the theme // A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) { Surface(color = MaterialTheme.colors.background) {
Column { Column {
MenuBar() { MenuBar() {
viewModel.chromeCasts.value = emptyList() viewModel.refresh()
GlobalScope.launch(IO) {
ChromeCasts.restartDiscovery(getIPv4Address())
}
} }
LazyColumn(modifier = Modifier LazyColumn(modifier = Modifier
.padding(all = 4.dp) .padding(all = 4.dp)
.fillMaxWidth(), .fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally) { horizontalAlignment = Alignment.CenterHorizontally) {
item { item {
if (chromeCasts.size > 0) if (chromeCasts.isNotEmpty())
Text(text = "Available chromecasts:") Text(text = "Available chromecasts:")
else {
Column(
modifier = Modifier.fillMaxSize() ,
horizontalAlignment = Alignment.CenterHorizontally
){
Text("Looking for Chromecasts on your network...")
CircularProgressIndicator()
}
}
} }
items(chromeCasts.size) { index -> items(chromeCasts.size) { index ->
showChromeCastButton(chromeCast = chromeCasts[index]) showChromeCastButton(chromeCast = chromeCasts[index])
@ -90,17 +92,6 @@ class MainActivity : ComponentActivity() {
} }
} }
fun getIPv4Address(): InetAddress? {
NetworkInterface.getNetworkInterfaces().toList().forEach { interf ->
interf.inetAddresses.toList().forEach { inetAddress ->
if (!inetAddress.isLoopbackAddress && inetAddress.hostAddress.indexOf(':') < 0) {
return inetAddress
}
}
}
return null
}
@Composable @Composable
fun MenuBar(refresh: () -> Unit) { fun MenuBar(refresh: () -> Unit) {
TopAppBar( TopAppBar(
@ -115,6 +106,15 @@ class MainActivity : ComponentActivity() {
contentDescription = "Refresh" contentDescription = "Refresh"
) )
} }
IconButton(onClick = {
}) {
Icon(
Icons.Filled.Add,
contentDescription = "Add"
)
}
} }
} }
) )

View file

@ -13,10 +13,9 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
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.Menu import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.Share
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -53,15 +52,15 @@ class ShareRecieverActivity : ComponentActivity() {
setContent { setContent {
CasterTheme { CasterTheme {
val viewModel = ViewModelProvider(this).get(ChromeCastViewModel::class.java) val viewModel = ViewModelProvider(this).get(ChromeCastViewModel::class.java)
GlobalScope.launch(IO) { viewModel.startScanning()
ChromeCasts.startDiscovery(getIPv4Address()) val chromeCastState = viewModel.chromeCastsLiveData.observeAsState(emptyList())
} val chromeCasts = chromeCastState.value
val chromeCasts = viewModel.chromeCasts.value
// A surface container using the 'background' color from the theme // A surface container using the 'background' color from the theme
Surface(color = MaterialTheme.colors.background) { Surface(color = MaterialTheme.colors.background) {
Column { Column {
MenuBar() MenuBar{
viewModel.refresh()
}
var enabled by remember { var enabled by remember {
mutableStateOf(true) mutableStateOf(true)
} }
@ -72,7 +71,7 @@ class ShareRecieverActivity : ComponentActivity() {
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
item { item {
if (chromeCasts.size > 0) if (chromeCasts.isNotEmpty())
Text(text = "Available chromecasts:") Text(text = "Available chromecasts:")
} }
items(chromeCasts.size) { index -> items(chromeCasts.size) { index ->
@ -117,37 +116,27 @@ class ShareRecieverActivity : ComponentActivity() {
} }
} }
fun getIPv4Address(): InetAddress? {
NetworkInterface.getNetworkInterfaces().toList().forEach { interf ->
interf.inetAddresses.toList().forEach { inetAddress ->
if (!inetAddress.isLoopbackAddress && inetAddress.hostAddress.indexOf(':') < 0) {
return inetAddress
}
}
}
return null
}
@Composable @Composable
fun MenuBar() { fun MenuBar(refresh: () -> Unit) {
TopAppBar( TopAppBar(
title = { title = {
Text(stringResource(id = R.string.title_activity_share_reciever)) Text(stringResource(id = R.string.title_activity_share_reciever))
}, },
navigationIcon = {
IconButton(onClick = { }) {
Icon(
Icons.Filled.Menu,
contentDescription = "Menu Hamburger"
)
}
},
actions = { actions = {
Row { Row {
IconButton(onClick = {}) { IconButton(onClick = refresh) {
Icon( Icon(
Icons.Filled.Share, Icons.Filled.Refresh,
contentDescription = "Search Article" contentDescription = "Refresh"
)
}
IconButton(onClick = {
}) {
Icon(
Icons.Filled.Add,
contentDescription = "Add"
) )
} }
} }
@ -160,7 +149,7 @@ class ShareRecieverActivity : ComponentActivity() {
@Composable @Composable
fun DefaultPreview() { fun DefaultPreview() {
CasterTheme { CasterTheme {
MenuBar() MenuBar {}
} }
} }
} }

View file

@ -1,5 +1,6 @@
package eu.toldi.balazs.caster.model package eu.toldi.balazs.caster.model
import android.util.Log
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@ -8,28 +9,61 @@ import androidx.compose.runtime.remember
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import su.litvak.chromecast.api.v2.ChromeCast import su.litvak.chromecast.api.v2.ChromeCast
import su.litvak.chromecast.api.v2.ChromeCasts import su.litvak.chromecast.api.v2.ChromeCasts
import su.litvak.chromecast.api.v2.ChromeCastsListener import su.litvak.chromecast.api.v2.ChromeCastsListener
import java.net.InetAddress
import java.net.NetworkInterface
import javax.jmdns.ServiceEvent import javax.jmdns.ServiceEvent
import javax.jmdns.ServiceListener import javax.jmdns.ServiceListener
class ChromeCastViewModel : ViewModel(),ChromeCastsListener { class ChromeCastViewModel : ViewModel(),ChromeCastsListener {
val chromeCasts : MutableState<List<ChromeCast>> = mutableStateOf(ChromeCasts.get()) val _chromecasts : MutableLiveData<List<ChromeCast>> = MutableLiveData<List<ChromeCast>>(listOf())
val chromeCastsLiveData : LiveData<List<ChromeCast>>
get() = _chromecasts
init { init {
ChromeCasts.registerListener(this) ChromeCasts.registerListener(this)
} }
override fun newChromeCastDiscovered(chromeCast: ChromeCast?) { override fun newChromeCastDiscovered(chromeCast: ChromeCast?) {
if(chromeCast != null) if(chromeCast != null) {
chromeCasts.value += chromeCast Log.i(null,"Found ${chromeCast.title}")
_chromecasts.postValue(_chromecasts.value!!.plus(chromeCast))
}
} }
override fun chromeCastRemoved(chromeCast: ChromeCast?) { override fun chromeCastRemoved(chromeCast: ChromeCast?) {
if(chromeCast != null) if(chromeCast != null) {
chromeCasts.value -= chromeCast Log.i(null,"Lost ${chromeCast.title}")
_chromecasts.postValue(_chromecasts.value!!.minus(chromeCast))
}
}
fun refresh() {
_chromecasts.value = emptyList()
viewModelScope.launch(IO) {
ChromeCasts.restartDiscovery(getIPv4Address())
}
}
fun startScanning() {
viewModelScope.launch(IO) {
ChromeCasts.startDiscovery(getIPv4Address())
}
}
fun getIPv4Address(): InetAddress? {
NetworkInterface.getNetworkInterfaces().toList().forEach { interf ->
interf.inetAddresses.toList().forEach { inetAddress ->
if (!inetAddress.isLoopbackAddress && inetAddress.hostAddress.indexOf(':') < 0) {
return inetAddress
}
}
}
return null
} }
} }