Skip to content

Commit f7743e0

Browse files
committed
Create basic UI for devices
1 parent cec0311 commit f7743e0

File tree

6 files changed

+81
-38
lines changed

6 files changed

+81
-38
lines changed

app/src/main/java/me/vanpetegem/accentor/devices/Device.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ sealed class Device(
88
) {
99

1010
val friendlyName: String = clingDevice.details.friendlyName
11-
val firstCharacter: String = String(intArrayOf(friendlyName.codePointAt(0)), 0, 1)
11+
val displayString: String = clingDevice.displayString
1212
val type: String = clingDevice.type.displayString
1313

1414
val imageURL: String? = clingDevice
@@ -17,6 +17,10 @@ sealed class Device(
1717
?.let { clingDevice.normalizeURI(it.uri).toString() }
1818

1919

20+
class Ready(clingDevice: RemoteDevice): Device(clingDevice) {}
21+
22+
class Failed(clingDevice: RemoteDevice, val exception: Exception?): Device(clingDevice) {}
23+
2024
class Discovered(clingDevice: RemoteDevice): Device(clingDevice) {
2125
fun failed(exception: Exception?): Failed {
2226
return Failed(clingDevice, exception)
@@ -26,8 +30,6 @@ sealed class Device(
2630
return Ready(clingDevice)
2731
}
2832
}
29-
class Failed(clingDevice: RemoteDevice, val exception: Exception?): Device(clingDevice) {}
30-
class Ready(clingDevice: RemoteDevice): Device(clingDevice) {}
3133
}
3234

3335

app/src/main/java/me/vanpetegem/accentor/devices/DeviceManager.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,24 @@ import android.content.ComponentName
55
import android.content.ServiceConnection
66
import android.os.IBinder
77
import android.util.Log
8-
import androidx.compose.runtime.mutableStateMapOf
9-
import androidx.compose.runtime.snapshots.SnapshotStateMap
108
import androidx.lifecycle.LiveData
119
import androidx.lifecycle.MutableLiveData
12-
import dagger.Reusable
1310
import org.fourthline.cling.android.AndroidUpnpService
1411
import org.fourthline.cling.model.message.header.ServiceTypeHeader
1512
import org.fourthline.cling.model.meta.RemoteDevice
1613
import org.fourthline.cling.model.types.ServiceType
1714
import org.fourthline.cling.model.types.UDN
1815
import org.fourthline.cling.registry.DefaultRegistryListener
1916
import org.fourthline.cling.registry.Registry
20-
import java.lang.Exception
2117
import javax.inject.Inject
2218
import javax.inject.Singleton
2319

2420
@Singleton
2521
class DeviceManager @Inject constructor() {
2622

2723
val devices = MutableLiveData<Map<UDN, Device>>(emptyMap())
24+
val selectedDevice = MutableLiveData<Device?>(null)
25+
2826
val connection = DeviceServiceConnection()
2927

3028
private lateinit var upnp: AndroidUpnpService
Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,85 @@
11
package me.vanpetegem.accentor.ui.devices
22

3+
import androidx.annotation.DrawableRes
4+
import androidx.annotation.StringRes
35
import androidx.compose.foundation.Image
4-
import androidx.compose.foundation.layout.Column
5-
import androidx.compose.foundation.layout.aspectRatio
6-
import androidx.compose.foundation.layout.fillMaxWidth
7-
import androidx.compose.foundation.layout.padding
6+
import androidx.compose.foundation.clickable
7+
import androidx.compose.foundation.layout.*
8+
import androidx.compose.foundation.rememberScrollState
9+
import androidx.compose.foundation.verticalScroll
810
import androidx.compose.material.Card
911
import androidx.compose.material.MaterialTheme
1012
import androidx.compose.material.Text
1113
import androidx.compose.runtime.Composable
1214
import androidx.compose.runtime.getValue
1315
import androidx.compose.runtime.livedata.observeAsState
16+
import androidx.compose.ui.Alignment
1417
import androidx.compose.ui.Modifier
15-
import androidx.compose.ui.layout.ContentScale
1618
import androidx.compose.ui.res.painterResource
1719
import androidx.compose.ui.res.stringResource
1820
import androidx.compose.ui.unit.dp
1921
import androidx.hilt.navigation.compose.hiltViewModel
20-
import coil.compose.rememberImagePainter
2122
import me.vanpetegem.accentor.R
2223
import me.vanpetegem.accentor.devices.Device
23-
import me.vanpetegem.accentor.ui.util.FastScrollableGrid
2424

2525
@Composable
2626
fun Devices(devicesViewModel: DevicesViewModel = hiltViewModel()) {
2727
val devices: List<Device>? by devicesViewModel.devices().observeAsState()
28-
FastScrollableGrid(devices ?: emptyList(), { it.firstCharacter }) { DeviceCard(it) }
28+
DeviceList(devices ?: emptyList())
2929
}
3030

3131
@Composable
32-
fun DeviceCard(device: Device) {
32+
fun DeviceList(devices: List<Device>) {
33+
Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) {
34+
DeviceCard(
35+
name = stringResource(R.string.local_device),
36+
icon = R.drawable.ic_smartphone_sound,
37+
iconDescription = R.string.local_device_description
38+
)
39+
Spacer(Modifier.size(8.dp))
40+
Text(
41+
stringResource(R.string.devices_available),
42+
modifier = Modifier.padding(8.dp),
43+
style = MaterialTheme.typography.h5
44+
)
45+
devices.forEach { device ->
46+
DeviceCard(
47+
name = device.friendlyName,
48+
icon = R.drawable.ic_menu_devices
49+
)
50+
}
51+
}
52+
}
53+
54+
@Composable
55+
fun DeviceCard(
56+
name: String,
57+
@StringRes
58+
iconDescription: Int = R.string.device_image,
59+
@DrawableRes
60+
icon: Int = R.drawable.ic_menu_devices,
61+
onClick: () -> Unit = {}) {
3362
Card(
34-
modifier = Modifier.padding(8.dp),
63+
modifier = Modifier.padding(8.dp).fillMaxWidth().clickable(onClick = onClick)
3564
) {
36-
Column {
65+
Row(
66+
modifier = Modifier.padding(8.dp),
67+
verticalAlignment = Alignment.CenterVertically,
68+
horizontalArrangement = Arrangement.Start
69+
) {
3770
Image(
38-
painter = if (device.imageURL != null) {
39-
rememberImagePainter(device.imageURL) {
40-
placeholder(R.drawable.ic_artist)
41-
}
42-
} else {
43-
painterResource(R.drawable.ic_artist)
44-
},
45-
contentDescription = stringResource(R.string.device_image),
46-
modifier = Modifier.fillMaxWidth().aspectRatio(1f),
47-
contentScale = ContentScale.Crop,
48-
)
49-
Text(
50-
device.friendlyName,
51-
maxLines = 1,
52-
modifier = Modifier.padding(4.dp),
53-
style = MaterialTheme.typography.subtitle1,
54-
)
55-
Text(
56-
device.type
71+
painter = painterResource(icon),
72+
contentDescription = stringResource(iconDescription),
73+
modifier = Modifier.requiredSize(48.dp)
5774
)
75+
Column() {
76+
Text(
77+
name,
78+
maxLines = 1,
79+
modifier = Modifier.padding(16.dp),
80+
style = MaterialTheme.typography.subtitle1
81+
)
82+
}
5883
}
5984
}
6085
}

app/src/main/java/me/vanpetegem/accentor/ui/devices/DevicesViewModel.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ class DevicesViewModel @Inject constructor(
1616
) : AndroidViewModel(application) {
1717

1818
fun devices(): LiveData<List<Device>> = map(deviceManager.devices) { devices ->
19-
devices.values.sortedWith(compareBy({ it.friendlyName }, { it.firstCharacter.uppercase() }))
19+
devices.values.sortedWith(compareBy(
20+
{ when(it) {
21+
is Device.Ready -> 1
22+
is Device.Failed -> 2
23+
is Device.Discovered -> 3
24+
}},
25+
{ it.friendlyName })
26+
)
2027
}
2128
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:height="24dp"
4+
android:width="24dp"
5+
android:viewportWidth="24"
6+
android:viewportHeight="24">
7+
<path android:fillColor="#000" android:pathData="M19.1,8.7C20.9,10.5 20.9,13.3 19.1,15.2L20.1,16.2C22.6,13.9 22.6,10.1 20.1,7.7L19.1,8.7M18,9.8L17,10.8C17.5,11.5 17.5,12.4 17,13.1L18,14.1C19.2,12.9 19.2,11.1 18,9.8M14,1H4A2,2 0 0,0 2,3V21A2,2 0 0,0 4,23H14A2,2 0 0,0 16,21V3A2,2 0 0,0 14,1M14,20H4V4H14V20Z" />
8+
</vector>

app/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,7 @@
7272
<string name="no_on_this_day">No albums were released on this day</string>
7373
<string name="no_artists">No artists could be found</string>
7474
<string name="title_activity_device_view">DeviceView</string>
75+
<string name="local_device">Play on this device</string>
76+
<string name="local_device_description">Sound coming from your device</string>
77+
<string name="devices_available">Stream to devices</string>
7578
</resources>

0 commit comments

Comments
 (0)