@@ -25,7 +25,6 @@ import androidx.compose.runtime.Composable
2525import androidx.compose.runtime.LaunchedEffect
2626import androidx.compose.runtime.collectAsState
2727import androidx.compose.runtime.getValue
28- import androidx.compose.runtime.mutableFloatStateOf
2928import androidx.compose.runtime.mutableStateOf
3029import androidx.compose.runtime.remember
3130import androidx.compose.runtime.setValue
@@ -44,6 +43,7 @@ import androidx.mediarouter.R
4443import androidx.mediarouter.media.MediaRouteSelector
4544import androidx.mediarouter.media.MediaRouter
4645import androidx.mediarouter.media.MediaRouter.RouteInfo
46+ import ch.srgssr.androidx.mediarouter.compose.MediaRouteControllerDialogViewModel.RouteDetail
4747import coil3.compose.AsyncImage
4848import coil3.compose.AsyncImagePainter
4949
@@ -76,14 +76,16 @@ fun MediaRouteControllerDialog(
7676 factory = MediaRouteControllerDialogViewModel .Factory (volumeControlEnabled),
7777 )
7878 val showDialog by viewModel.showDialog.collectAsState()
79- val selectedRoute by viewModel.selectedRoute.collectAsState()
8079 val isDeviceGroupExpanded by viewModel.isDeviceGroupExpanded.collectAsState()
8180 val showPlaybackControl by viewModel.showPlaybackControl.collectAsState()
8281 val showVolumeControl by viewModel.showVolumeControl.collectAsState()
8382 val imageModel by viewModel.imageModel.collectAsState()
8483 val title by viewModel.title.collectAsState()
8584 val subtitle by viewModel.subtitle.collectAsState()
8685 val iconInfo by viewModel.iconInfo.collectAsState()
86+ val routes by viewModel.routes.collectAsState()
87+ val selectedRouteDetail = routes[0 ]
88+ val groupRouteDetails = routes.drop(1 )
8789
8890 LaunchedEffect (showDialog) {
8991 if (! showDialog) {
@@ -92,15 +94,15 @@ fun MediaRouteControllerDialog(
9294 }
9395
9496 ControllerDialog (
95- route = selectedRoute,
96- volumeControlEnabled = volumeControlEnabled,
97+ routeDetail = selectedRouteDetail,
9798 imageModel = imageModel,
9899 title = title,
99100 subtitle = subtitle,
100101 iconInfo = iconInfo,
101102 isDeviceGroupExpanded = isDeviceGroupExpanded,
102103 showPlaybackControl = showPlaybackControl,
103104 showVolumeControl = showVolumeControl,
105+ groupRouteDetails = groupRouteDetails,
104106 modifier = modifier,
105107 customControlView = customControlView,
106108 toggleDeviceGroup = viewModel::toggleDeviceGroup,
@@ -110,20 +112,21 @@ fun MediaRouteControllerDialog(
110112 onStopCasting = viewModel::stopCasting,
111113 onDisconnect = viewModel::disconnect,
112114 onDismissRequest = viewModel::hideDialog,
115+ onVolumeChange = viewModel::setRouteVolume,
113116 )
114117}
115118
116119@Composable
117120internal fun ControllerDialog (
118- route : RouteInfo ,
119- volumeControlEnabled : Boolean ,
121+ routeDetail : RouteDetail ,
120122 imageModel : Any? ,
121123 title : String? ,
122124 subtitle : String? ,
123125 iconInfo : Pair <ImageVector , String >? ,
124126 isDeviceGroupExpanded : Boolean ,
125127 showPlaybackControl : Boolean ,
126128 showVolumeControl : Boolean ,
129+ groupRouteDetails : List <RouteDetail >,
127130 modifier : Modifier = Modifier ,
128131 customControlView : @Composable (() -> Unit )? ,
129132 toggleDeviceGroup : () -> Unit ,
@@ -133,6 +136,7 @@ internal fun ControllerDialog(
133136 onStopCasting : () -> Unit ,
134137 onDisconnect : () -> Unit ,
135138 onDismissRequest : () -> Unit ,
139+ onVolumeChange : (route: RouteInfo , volume: Float ) -> Unit ,
136140) {
137141 AlertDialog (
138142 onDismissRequest = onDismissRequest,
@@ -142,7 +146,7 @@ internal fun ControllerDialog(
142146 }
143147 },
144148 modifier = modifier.onKeyEvent(onKeyEvent),
145- dismissButton = if (route.canDisconnect()) {
149+ dismissButton = if (routeDetail. route.canDisconnect()) {
146150 {
147151 TextButton (onClick = onDisconnect) {
148152 Text (text = stringResource(R .string.mr_controller_disconnect))
@@ -158,7 +162,7 @@ internal fun ControllerDialog(
158162 verticalAlignment = Alignment .CenterVertically ,
159163 ) {
160164 Text (
161- text = route.name,
165+ text = routeDetail. route.name,
162166 overflow = TextOverflow .Ellipsis ,
163167 maxLines = 1 ,
164168 )
@@ -173,41 +177,43 @@ internal fun ControllerDialog(
173177 },
174178 text = {
175179 ControllerDialogContent (
176- route = route,
177- volumeControlEnabled = volumeControlEnabled,
180+ routeDetail = routeDetail,
178181 imageModel = imageModel,
179182 title = title,
180183 subtitle = subtitle,
181184 iconInfo = iconInfo,
182185 isDeviceGroupExpanded = isDeviceGroupExpanded,
183186 showPlaybackControl = showPlaybackControl,
184187 showVolumeControl = showVolumeControl,
188+ groupRouteDetails = groupRouteDetails,
185189 modifier = Modifier .fillMaxWidth(),
186190 customControlView = customControlView,
187191 onToggleDeviceGroup = toggleDeviceGroup,
188192 onPlaybackTitleClick = onPlaybackTitleClick,
189193 onPlaybackIconClick = onPlaybackIconClick,
194+ onVolumeChange = onVolumeChange,
190195 )
191196 },
192197 )
193198}
194199
195200@Composable
196201private fun ControllerDialogContent (
197- route : RouteInfo ,
198- volumeControlEnabled : Boolean ,
202+ routeDetail : RouteDetail ,
199203 imageModel : Any? ,
200204 title : String? ,
201205 subtitle : String? ,
202206 iconInfo : Pair <ImageVector , String >? ,
203207 isDeviceGroupExpanded : Boolean ,
204208 showPlaybackControl : Boolean ,
205209 showVolumeControl : Boolean ,
210+ groupRouteDetails : List <RouteDetail >,
206211 modifier : Modifier = Modifier ,
207212 customControlView : @Composable (() -> Unit )? ,
208213 onToggleDeviceGroup : () -> Unit ,
209214 onPlaybackTitleClick : () -> Unit ,
210215 onPlaybackIconClick : () -> Unit ,
216+ onVolumeChange : (route: RouteInfo , volume: Float ) -> Unit ,
211217) {
212218 @Suppress(" NoNameShadowing" )
213219 val showPlaybackControl = showPlaybackControl && customControlView == null
@@ -242,21 +248,22 @@ private fun ControllerDialogContent(
242248
243249 if (showVolumeControl) {
244250 VolumeControl (
245- route = route ,
251+ routeDetail = routeDetail ,
246252 modifier = Modifier .fillMaxWidth(),
247253 isExpanded = isDeviceGroupExpanded,
248254 onExpandCollapseClick = onToggleDeviceGroup,
255+ onVolumeChange = onVolumeChange,
249256 )
250257 }
251258 }
252259
253260 if (isDeviceGroupExpanded) {
254261 DeviceGroup (
255- routes = route.memberRoutes,
256- volumeControlEnabled = volumeControlEnabled,
262+ routeDetails = groupRouteDetails,
257263 modifier = Modifier
258264 .fillMaxWidth()
259265 .padding(top = 16 .dp),
266+ onVolumeChange = onVolumeChange,
260267 )
261268 }
262269 }
@@ -341,32 +348,30 @@ private fun PlaybackControlRow(
341348
342349@Composable
343350private fun VolumeControl (
344- route : RouteInfo ,
351+ routeDetail : RouteDetail ,
345352 modifier : Modifier = Modifier ,
346353 isExpanded : Boolean ,
347354 onExpandCollapseClick : () -> Unit ,
355+ onVolumeChange : (route: RouteInfo , volume: Float ) -> Unit ,
348356) {
349357 Row (
350358 modifier = modifier,
351359 horizontalArrangement = Arrangement .spacedBy(8 .dp),
352360 verticalAlignment = Alignment .CenterVertically ,
353361 ) {
354- val (volume, setVolume) = remember { mutableFloatStateOf(route.volume.toFloat()) }
355-
356362 Icon (
357363 imageVector = Icons .Audiotrack ,
358364 contentDescription = null ,
359365 )
360366
361367 Slider (
362- value = volume,
363- onValueChange = setVolume ,
368+ value = routeDetail. volume,
369+ onValueChange = { onVolumeChange(routeDetail.route, it) } ,
364370 modifier = Modifier .weight(1f ),
365- valueRange = 0f .. route.volumeMax.toFloat(),
366- onValueChangeFinished = { route.requestSetVolume(volume.toInt()) },
371+ valueRange = routeDetail.volumeRange,
367372 )
368373
369- if (route.isGroup && route.memberRoutes.size > 1 ) {
374+ if (routeDetail. route.isGroup && routeDetail. route.memberRoutes.size > 1 ) {
370375 IconButton (onClick = onExpandCollapseClick) {
371376 val scale by animateFloatAsState(targetValue = if (isExpanded) - 1f else 1f )
372377 val contentDescriptionRes = if (isExpanded) {
@@ -387,27 +392,16 @@ private fun VolumeControl(
387392
388393@Composable
389394private fun DeviceGroup (
390- routes : List <RouteInfo >,
391- volumeControlEnabled : Boolean ,
395+ routeDetails : List <RouteDetail >,
392396 modifier : Modifier = Modifier ,
397+ onVolumeChange : (route: RouteInfo , volume: Float ) -> Unit ,
393398) {
394399 LazyColumn (
395400 modifier = modifier,
396401 verticalArrangement = Arrangement .spacedBy(16 .dp),
397402 ) {
398- items(routes) { route ->
399- val isVolumeControlEnabled = volumeControlEnabled
400- && route.volumeHandling == RouteInfo .PLAYBACK_VOLUME_VARIABLE
401- val volumeMax = if (isVolumeControlEnabled) route.volumeMax else 100
402- val volumeRange = 0f .. volumeMax.toFloat()
403-
404- var volume by remember {
405- mutableFloatStateOf(if (isVolumeControlEnabled) route.volume.toFloat() else 100f )
406- }
407-
408- Column (
409- modifier = Modifier .fillMaxWidth(),
410- ) {
403+ items(routeDetails) { (route, volume, volumeRange) ->
404+ Column (modifier = Modifier .fillMaxWidth()) {
411405 Text (
412406 text = route.name,
413407 maxLines = 1 ,
@@ -426,19 +420,10 @@ private fun DeviceGroup(
426420
427421 Slider (
428422 value = volume,
429- onValueChange = {
430- if (isVolumeControlEnabled) {
431- volume = it
432- }
433- },
423+ onValueChange = { onVolumeChange(route, it) },
434424 modifier = Modifier .weight(1f ),
435425 enabled = route.isEnabled,
436426 valueRange = volumeRange,
437- onValueChangeFinished = {
438- if (isVolumeControlEnabled) {
439- route.requestSetVolume(volume.toInt())
440- }
441- },
442427 )
443428 }
444429 }
0 commit comments