Loading packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt +24 −10 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor import com.android.systemui.volume.panel.component.mediaoutput.shared.model.SessionWithPlayback import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope import com.android.systemui.volume.panel.shared.model.Result import com.android.systemui.volume.panel.ui.VolumePanelUiEvent import javax.inject.Inject import kotlinx.coroutines.CoroutineScope Loading @@ -34,6 +35,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map Loading @@ -53,32 +55,40 @@ constructor( private val uiEventLogger: UiEventLogger, ) { private val sessionWithPlayback: StateFlow<SessionWithPlayback?> = private val sessionWithPlayback: StateFlow<Result<SessionWithPlayback?>> = interactor.defaultActiveMediaSession .flatMapLatest { session -> if (session == null) { flowOf(null) flowOf(Result.Data<SessionWithPlayback?>(null)) } else { mediaDeviceSessionInteractor.playbackState(session).map { playback -> playback?.let { SessionWithPlayback(session, it) } mediaDeviceSessionInteractor .playbackState(session) .map { playback -> playback?.let { Result.Data<SessionWithPlayback?>(SessionWithPlayback(session, it)) } } .filterNotNull() } } .stateIn( coroutineScope, SharingStarted.Eagerly, null, Result.Loading(), ) val connectedDeviceViewModel: StateFlow<ConnectedDeviceViewModel?> = combine(sessionWithPlayback, interactor.currentConnectedDevice) { mediaDeviceSession, currentConnectedDevice -> if (mediaDeviceSession !is Result.Data) { return@combine null } ConnectedDeviceViewModel( if (mediaDeviceSession?.playback?.isActive == true) { if (mediaDeviceSession.data?.playback?.isActive == true) { context.getString( R.string.media_output_label_title, mediaDeviceSession.session.appLabel mediaDeviceSession.data.session.appLabel ) } else { context.getString(R.string.media_output_title_without_playing) Loading @@ -96,7 +106,10 @@ constructor( combine(sessionWithPlayback, interactor.currentConnectedDevice) { mediaDeviceSession, currentConnectedDevice -> if (mediaDeviceSession?.playback?.isActive == true) { if (mediaDeviceSession !is Result.Data) { return@combine null } if (mediaDeviceSession.data?.playback?.isActive == true) { val icon = currentConnectedDevice?.icon?.let { Icon.Loaded(it, null) } ?: Icon.Resource( Loading Loading @@ -130,6 +143,7 @@ constructor( fun onBarClick(expandable: Expandable) { uiEventLogger.log(VolumePanelUiEvent.VOLUME_PANEL_MEDIA_OUTPUT_CLICKED) actionsInteractor.onBarClick(sessionWithPlayback.value, expandable) val result = sessionWithPlayback.value actionsInteractor.onBarClick((result as? Result.Data)?.data, expandable) } } packages/SystemUI/src/com/android/systemui/volume/panel/shared/model/Result.kt 0 → 100644 +27 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.volume.panel.shared.model /** Models a loadable result */ sealed interface Result<T> { /** The data is still loading */ class Loading<T> : Result<T> /** The data is loaded successfully */ data class Data<T>(val data: T) : Result<T> } Loading
packages/SystemUI/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModel.kt +24 −10 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor import com.android.systemui.volume.panel.component.mediaoutput.shared.model.SessionWithPlayback import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope import com.android.systemui.volume.panel.shared.model.Result import com.android.systemui.volume.panel.ui.VolumePanelUiEvent import javax.inject.Inject import kotlinx.coroutines.CoroutineScope Loading @@ -34,6 +35,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map Loading @@ -53,32 +55,40 @@ constructor( private val uiEventLogger: UiEventLogger, ) { private val sessionWithPlayback: StateFlow<SessionWithPlayback?> = private val sessionWithPlayback: StateFlow<Result<SessionWithPlayback?>> = interactor.defaultActiveMediaSession .flatMapLatest { session -> if (session == null) { flowOf(null) flowOf(Result.Data<SessionWithPlayback?>(null)) } else { mediaDeviceSessionInteractor.playbackState(session).map { playback -> playback?.let { SessionWithPlayback(session, it) } mediaDeviceSessionInteractor .playbackState(session) .map { playback -> playback?.let { Result.Data<SessionWithPlayback?>(SessionWithPlayback(session, it)) } } .filterNotNull() } } .stateIn( coroutineScope, SharingStarted.Eagerly, null, Result.Loading(), ) val connectedDeviceViewModel: StateFlow<ConnectedDeviceViewModel?> = combine(sessionWithPlayback, interactor.currentConnectedDevice) { mediaDeviceSession, currentConnectedDevice -> if (mediaDeviceSession !is Result.Data) { return@combine null } ConnectedDeviceViewModel( if (mediaDeviceSession?.playback?.isActive == true) { if (mediaDeviceSession.data?.playback?.isActive == true) { context.getString( R.string.media_output_label_title, mediaDeviceSession.session.appLabel mediaDeviceSession.data.session.appLabel ) } else { context.getString(R.string.media_output_title_without_playing) Loading @@ -96,7 +106,10 @@ constructor( combine(sessionWithPlayback, interactor.currentConnectedDevice) { mediaDeviceSession, currentConnectedDevice -> if (mediaDeviceSession?.playback?.isActive == true) { if (mediaDeviceSession !is Result.Data) { return@combine null } if (mediaDeviceSession.data?.playback?.isActive == true) { val icon = currentConnectedDevice?.icon?.let { Icon.Loaded(it, null) } ?: Icon.Resource( Loading Loading @@ -130,6 +143,7 @@ constructor( fun onBarClick(expandable: Expandable) { uiEventLogger.log(VolumePanelUiEvent.VOLUME_PANEL_MEDIA_OUTPUT_CLICKED) actionsInteractor.onBarClick(sessionWithPlayback.value, expandable) val result = sessionWithPlayback.value actionsInteractor.onBarClick((result as? Result.Data)?.data, expandable) } }
packages/SystemUI/src/com/android/systemui/volume/panel/shared/model/Result.kt 0 → 100644 +27 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.volume.panel.shared.model /** Models a loadable result */ sealed interface Result<T> { /** The data is still loading */ class Loading<T> : Result<T> /** The data is loaded successfully */ data class Data<T>(val data: T) : Result<T> }