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

Commit d411cb16 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere Committed by Android (Google) Code Review
Browse files

Merge changes from topic "fake-vm-without-mockito" into main

* changes:
  Remove the dependency on Mockito to create QS actions fakes (1/2)
  Remove the dependency on Mockito to create PeopleSpace fakes (1/2)
parents ef18eed3 01b97d27
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -47,10 +47,10 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.systemui.res.R
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.people.ui.viewmodel.PeopleTileViewModel
import com.android.systemui.people.ui.viewmodel.PeopleViewModel
import com.android.systemui.res.R

/**
 * Compose the screen associated to a [PeopleViewModel].
@@ -86,9 +86,9 @@ fun PeopleScreen(
        modifier = Modifier.fillMaxSize(),
    ) {
        if (priorityTiles.isNotEmpty() || recentTiles.isNotEmpty()) {
            PeopleScreenWithConversations(priorityTiles, recentTiles, viewModel::onTileClicked)
            PeopleScreenWithConversations(priorityTiles, recentTiles, viewModel.onTileClicked)
        } else {
            PeopleScreenEmpty(viewModel::onUserJourneyCancelled)
            PeopleScreenEmpty(viewModel.onUserJourneyCancelled)
        }
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -31,10 +31,10 @@ import androidx.lifecycle.Lifecycle.State.CREATED
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.res.R
import com.android.systemui.people.PeopleSpaceTileView
import com.android.systemui.people.ui.viewmodel.PeopleTileViewModel
import com.android.systemui.people.ui.viewmodel.PeopleViewModel
import com.android.systemui.res.R
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -101,10 +101,10 @@ object PeopleViewBinder {
                                view,
                                priorityTiles,
                                recentTiles,
                                viewModel::onTileClicked,
                                viewModel.onTileClicked,
                            )
                        } else {
                            setNoConversationsContent(view, viewModel::onUserJourneyCancelled)
                            setNoConversationsContent(view, viewModel.onUserJourneyCancelled)
                        }
                    }
            }
+95 −69
Original line number Diff line number Diff line
@@ -23,35 +23,32 @@ import android.content.Intent
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.android.systemui.res.R
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.people.PeopleSpaceUtils
import com.android.systemui.people.PeopleTileViewHelper
import com.android.systemui.people.data.model.PeopleTileModel
import com.android.systemui.people.data.repository.PeopleTileRepository
import com.android.systemui.people.data.repository.PeopleWidgetRepository
import com.android.systemui.res.R
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

private const val TAG = "PeopleViewModel"

/**
 * Models UI state for the people space, allowing the user to select which conversation should be
 * associated to a new or existing Conversation widget.
 */
class PeopleViewModel(
    @Application private val context: Context,
    private val tileRepository: PeopleTileRepository,
    private val widgetRepository: PeopleWidgetRepository,
) : ViewModel() {
    /**
     * The list of the priority tiles/conversations.
     *
     * Important: Even though this is a Flow, the underlying API used to populate this Flow is not
     * reactive and you have to manually call [onTileRefreshRequested] to refresh the tiles.
     */
    private val _priorityTiles = MutableStateFlow(priorityTiles())
    val priorityTiles: StateFlow<List<PeopleTileViewModel>> = _priorityTiles.asStateFlow()
    val priorityTiles: StateFlow<List<PeopleTileViewModel>>,

    /**
     * The list of the priority tiles/conversations.
@@ -59,71 +56,124 @@ class PeopleViewModel(
     * Important: Even though this is a Flow, the underlying API used to populate this Flow is not
     * reactive and you have to manually call [onTileRefreshRequested] to refresh the tiles.
     */
    private val _recentTiles = MutableStateFlow(recentTiles())
    val recentTiles: StateFlow<List<PeopleTileViewModel>> = _recentTiles.asStateFlow()
    val recentTiles: StateFlow<List<PeopleTileViewModel>>,

    /** The ID of the widget currently being edited/added. */
    private val _appWidgetId = MutableStateFlow(INVALID_APPWIDGET_ID)
    val appWidgetId: StateFlow<Int> = _appWidgetId.asStateFlow()
    val appWidgetId: StateFlow<Int>,

    /** The result of this user journey. */
    private val _result = MutableStateFlow<Result?>(null)
    val result: StateFlow<Result?> = _result.asStateFlow()
    val result: StateFlow<Result?>,

    /** Refresh the [priorityTiles] and [recentTiles]. */
    fun onTileRefreshRequested() {
        _priorityTiles.value = priorityTiles()
        _recentTiles.value = recentTiles()
    }
    val onTileRefreshRequested: () -> Unit,

    /** Called when the [appWidgetId] should be changed to [widgetId]. */
    fun onWidgetIdChanged(widgetId: Int) {
        _appWidgetId.value = widgetId
    }
    val onWidgetIdChanged: (widgetId: Int) -> Unit,

    /** Clear [result], setting it to null. */
    fun clearResult() {
        _result.value = null
    }
    val clearResult: () -> Unit,

    /** Called when a tile is clicked. */
    fun onTileClicked(tile: PeopleTileViewModel) {
        val widgetId = _appWidgetId.value
        if (PeopleSpaceUtils.DEBUG) {
            Log.d(
                TAG,
                "Put ${tile.username}'s shortcut ID: ${tile.key.shortcutId} for widget ID $widgetId"
            )
    val onTileClicked: (tile: PeopleTileViewModel) -> Unit,

    /** Called when this user journey is cancelled. */
    val onUserJourneyCancelled: () -> Unit,
) : ViewModel() {
    /** The Factory that should be used to create a [PeopleViewModel]. */
    class Factory
    @Inject
    constructor(
        @Application private val context: Context,
        private val tileRepository: PeopleTileRepository,
        private val widgetRepository: PeopleWidgetRepository,
    ) : ViewModelProvider.Factory {
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            check(modelClass == PeopleViewModel::class.java)
            return PeopleViewModel(context, tileRepository, widgetRepository) as T
        }
        widgetRepository.setWidgetTile(widgetId, tile.key)
        _result.value =
            Result.Success(Intent().apply { putExtra(EXTRA_APPWIDGET_ID, appWidgetId.value) })
    }

    /** Called when this user journey is cancelled. */
    fun onUserJourneyCancelled() {
        _result.value = Result.Cancelled
    sealed class Result {
        class Success(val data: Intent) : Result()

        object Cancelled : Result()
    }
}

    private fun priorityTiles(): List<PeopleTileViewModel> {
private fun PeopleViewModel(
    @Application context: Context,
    tileRepository: PeopleTileRepository,
    widgetRepository: PeopleWidgetRepository,
): PeopleViewModel {
    fun priorityTiles(): List<PeopleTileViewModel> {
        return try {
            tileRepository.priorityTiles().map { it.toViewModel() }
            tileRepository.priorityTiles().map { it.toViewModel(context) }
        } catch (e: Exception) {
            Log.e(TAG, "Couldn't retrieve priority conversations", e)
            emptyList()
        }
    }

    private fun recentTiles(): List<PeopleTileViewModel> {
    fun recentTiles(): List<PeopleTileViewModel> {
        return try {
            tileRepository.recentTiles().map { it.toViewModel() }
            tileRepository.recentTiles().map { it.toViewModel(context) }
        } catch (e: Exception) {
            Log.e(TAG, "Couldn't retrieve recent conversations", e)
            emptyList()
        }
    }

    private fun PeopleTileModel.toViewModel(): PeopleTileViewModel {
    val priorityTiles = MutableStateFlow(priorityTiles())
    val recentTiles = MutableStateFlow(recentTiles())
    val appWidgetId = MutableStateFlow(INVALID_APPWIDGET_ID)
    val result = MutableStateFlow<PeopleViewModel.Result?>(null)

    fun onTileRefreshRequested() {
        priorityTiles.value = priorityTiles()
        recentTiles.value = recentTiles()
    }

    fun onWidgetIdChanged(widgetId: Int) {
        appWidgetId.value = widgetId
    }

    fun clearResult() {
        result.value = null
    }

    fun onTileClicked(tile: PeopleTileViewModel) {
        val widgetId = appWidgetId.value
        if (PeopleSpaceUtils.DEBUG) {
            Log.d(
                TAG,
                "Put ${tile.username}'s shortcut ID: ${tile.key.shortcutId} for widget ID $widgetId"
            )
        }
        widgetRepository.setWidgetTile(widgetId, tile.key)
        result.value =
            PeopleViewModel.Result.Success(
                Intent().apply { putExtra(EXTRA_APPWIDGET_ID, appWidgetId.value) }
            )
    }

    fun onUserJourneyCancelled() {
        result.value = PeopleViewModel.Result.Cancelled
    }

    return PeopleViewModel(
        priorityTiles = priorityTiles.asStateFlow(),
        recentTiles = recentTiles.asStateFlow(),
        appWidgetId = appWidgetId.asStateFlow(),
        result = result.asStateFlow(),
        onTileRefreshRequested = ::onTileRefreshRequested,
        onWidgetIdChanged = ::onWidgetIdChanged,
        clearResult = ::clearResult,
        onTileClicked = ::onTileClicked,
        onUserJourneyCancelled = ::onUserJourneyCancelled,
    )
}

fun PeopleTileModel.toViewModel(@Application context: Context): PeopleTileViewModel {
    val icon =
        PeopleTileViewHelper.getPersonIconBitmap(
            context,
@@ -136,27 +186,3 @@ class PeopleViewModel(
        )
    return PeopleTileViewModel(key, icon, username)
}

    /** The Factory that should be used to create a [PeopleViewModel]. */
    class Factory
    @Inject
    constructor(
        @Application private val context: Context,
        private val tileRepository: PeopleTileRepository,
        private val widgetRepository: PeopleWidgetRepository,
    ) : ViewModelProvider.Factory {
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            check(modelClass == PeopleViewModel::class.java)
            return PeopleViewModel(context, tileRepository, widgetRepository) as T
        }
    }

    sealed class Result {
        class Success(val data: Intent) : Result()
        object Cancelled : Result()
    }

    companion object {
        private const val TAG = "PeopleViewModel"
    }
}
+244 −180

File changed.

Preview size limit exceeded, changes collapsed.

+1 −3
Original line number Diff line number Diff line
@@ -367,9 +367,7 @@ class FooterActionsViewModelTest : SysuiTestCase() {
                    ),
            )

        val job = launch {
            underTest.observeDeviceMonitoringDialogRequests(quickSettingsContext = mock())
        }
        val job = launch { underTest.observeDeviceMonitoringDialogRequests(mock()) }

        advanceUntilIdle()
        assertThat(nDialogRequests).isEqualTo(3)