Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6f70463 authored by Michael Mikhail's avatar Michael Mikhail
Browse files

Store current carousel position

This CL stores the current index of media carousel to be shared across different locations as long as media carousel is visible to user. Once media is not showing, media carousel should reorder its media sessions and the current index should be 0 in order to make the carousel scroll to the first card in the current media list.

Flag: com.android.systemui.media_controls_in_compose
Bug: 397989775
Test: Checked UI.
Change-Id: I54e7f675631dfe7fa916a353a13de1d46b96cc29
parent aaeccbe7
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -24,7 +24,11 @@ import android.media.MediaMetadata
import android.media.session.MediaController
import android.media.session.PlaybackState
import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.graphics.Color
import com.android.internal.logging.InstanceId
@@ -59,11 +63,22 @@ interface MediaRepository {
    /** Current sorted media sessions. */
    val currentMedia: List<MediaDataModel>

    /** Index of the current visible media session */
    val currentCarouselIndex: Int

    /** Whether media carousel should show first media session. */
    val shouldScrollToFirst: Boolean

    /** Seek to [to], in milliseconds on the media session with the given [sessionKey]. */
    fun seek(sessionKey: InstanceId, to: Long)

    /** Reorders media list when media is not visible to user */
    fun reorderMedia()

    fun storeCarouselIndex(index: Int)

    /** Resets [shouldScrollToFirst] flag. */
    fun resetScrollToFirst()
}

@SysUISingleton
@@ -78,6 +93,10 @@ constructor(

    override val currentMedia: SnapshotStateList<MediaDataModel> = mutableStateListOf()

    override var currentCarouselIndex by mutableIntStateOf(0)

    override var shouldScrollToFirst by mutableStateOf(false)

    private var sortedMedia = TreeMap<MediaSortKeyModel, MediaDataModel>(comparator)

    // To store active controllers and their callbacks
@@ -124,6 +143,15 @@ constructor(
    override fun reorderMedia() {
        currentMedia.clear()
        currentMedia.addAll(sortedMedia.values.toList())
        currentCarouselIndex = 0
    }

    override fun storeCarouselIndex(index: Int) {
        currentCarouselIndex = index
    }

    override fun resetScrollToFirst() {
        shouldScrollToFirst = false
    }

    private fun addToSortedMedia(data: MediaData, updateModel: UpdateArtInfoModel?) {
@@ -175,6 +203,9 @@ constructor(
                    }
                    currentMedia.clear()
                    if (isNewToCurrentMedia && active) {
                        // New media added is at the top of the current media given its priority.
                        // Media carousel should show the first card in the current media list.
                        shouldScrollToFirst = true
                        currentMedia.addAll(sortedMap.values.toList())
                    } else {
                        currentMedia.addAll(currentList)
+24 −0
Original line number Diff line number Diff line
@@ -64,6 +64,12 @@ interface MediaInteractor {
    /** The list of sessions. Needs to be backed by a compose snapshot state. */
    val sessions: List<MediaSessionModel>

    /** Index of the current visible media session */
    val currentCarouselIndex: Int

    /** Whether media carousel should show first media session. */
    val shouldScrollToFirst: Boolean

    /** Seek to [to], in milliseconds on the media session with the given [sessionKey]. */
    fun seek(sessionKey: Any, to: Long)

@@ -74,6 +80,10 @@ interface MediaInteractor {
    fun openMediaSettings()

    fun reorderMedia()

    fun storeCurrentCarouselIndex(index: Int)

    fun resetScrollToFirst()
}

@SysUISingleton
@@ -93,6 +103,12 @@ constructor(
    override val sessions: List<MediaSessionModel>
        get() = repository.currentMedia.map { toMediaSessionModel(it) }

    override val currentCarouselIndex: Int
        get() = repository.currentCarouselIndex

    override val shouldScrollToFirst: Boolean
        get() = repository.shouldScrollToFirst

    override fun seek(sessionKey: Any, to: Long) {
        repository.seek(sessionKey as InstanceId, to)
    }
@@ -109,6 +125,14 @@ constructor(
        repository.reorderMedia()
    }

    override fun storeCurrentCarouselIndex(index: Int) {
        repository.storeCarouselIndex(index)
    }

    override fun resetScrollToFirst() {
        repository.resetScrollToFirst()
    }

    private fun toMediaSessionModel(dataModel: MediaDataModel): MediaSessionModel {
        return object : MediaSessionModel {
            override val key
+12 −1
Original line number Diff line number Diff line
@@ -229,8 +229,12 @@ private fun CardCarouselContent(
    modifier: Modifier = Modifier,
) {
    val pagerState = rememberPagerState { viewModel.cards.size }
    LaunchedEffect(viewModel.currentIndex) {
        if (viewModel.currentIndex != pagerState.currentPage) {
            pagerState.scrollToPage(viewModel.currentIndex)
        }
    }
    LaunchedEffect(pagerState.currentPage) { viewModel.onCardSelected(pagerState.currentPage) }

    var isFalseTouchDetected: Boolean by
        remember(behavior.isCarouselScrollFalseTouch) { mutableStateOf(false) }
    val isSwipingEnabled = behavior.isCarouselScrollingEnabled && !isFalseTouchDetected
@@ -308,6 +312,13 @@ private fun CardCarouselContent(
            )
        }
    }

    LaunchedEffect(viewModel.scrollToFirst) {
        if (viewModel.scrollToFirst && viewModel.cards.isNotEmpty()) {
            pagerState.animateScrollToPage(0)
            viewModel.onScrollToFirstCard()
        }
    }
}

/** Renders the UI of a single media card. */
+12 −0
Original line number Diff line number Diff line
@@ -69,6 +69,12 @@ constructor(
    private var selectedCardIndex: Int by mutableIntStateOf(0)
        private set

    /** The index of the currently visible card across different locations of media carousel */
    val currentIndex: Int by derivedStateOf { interactor.currentCarouselIndex }

    /** Whether media carousel should scroll to the first card in the list after composition */
    val scrollToFirst: Boolean by derivedStateOf { interactor.shouldScrollToFirst }

    /** The current list of cards to show in the UI. */
    val cards: List<MediaCardViewModel> by derivedStateOf {
        interactor.sessions.mapIndexed { sessionIndex, session ->
@@ -307,6 +313,12 @@ constructor(
    fun onCardSelected(cardIndex: Int) {
        check(cardIndex >= 0 && cardIndex < cards.size)
        selectedCardIndex = cardIndex
        interactor.storeCurrentCarouselIndex(selectedCardIndex)
    }

    /** Notifies that the carousel is reordered and first card is now visible on screen. */
    fun onScrollToFirstCard() {
        interactor.resetScrollToFirst()
    }

    override suspend fun onActivated(): Nothing {