Merge "Move click handler from XML to ViewModel (1/2)" into tm-qpr-dev

This commit is contained in:
Jordan Demeulenaere
2022-07-26 09:19:48 +00:00
committed by Android (Google) Code Review
4 changed files with 57 additions and 48 deletions

View File

@@ -54,7 +54,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:background="@drawable/rounded_bg_full_large_radius" android:background="@drawable/rounded_bg_full_large_radius"
android:onClick="dismissActivity"
android:text="@string/got_it" android:text="@string/got_it"
android:textColor="?androidprv:attr/textColorOnAccent" android:textColor="?androidprv:attr/textColorOnAccent"
android:layout_marginBottom="60dp" android:layout_marginBottom="60dp"

View File

@@ -22,7 +22,6 @@ import static android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.activity.ComponentActivity; import androidx.activity.ComponentActivity;
@@ -40,7 +39,6 @@ public class PeopleSpaceActivity extends ComponentActivity {
private static final boolean DEBUG = PeopleSpaceUtils.DEBUG; private static final boolean DEBUG = PeopleSpaceUtils.DEBUG;
private final PeopleViewModel.Factory mViewModelFactory; private final PeopleViewModel.Factory mViewModelFactory;
private PeopleViewModel mViewModel;
@Inject @Inject
public PeopleSpaceActivity(PeopleViewModel.Factory viewModelFactory) { public PeopleSpaceActivity(PeopleViewModel.Factory viewModelFactory) {
@@ -52,38 +50,32 @@ public class PeopleSpaceActivity extends ComponentActivity {
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setResult(RESULT_CANCELED); setResult(RESULT_CANCELED);
mViewModel = new ViewModelProvider(this, mViewModelFactory).get(PeopleViewModel.class);
PeopleViewModel viewModel = new ViewModelProvider(this, mViewModelFactory).get(
PeopleViewModel.class);
// Update the widget ID coming from the intent. // Update the widget ID coming from the intent.
int widgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID, INVALID_APPWIDGET_ID); int widgetId = getIntent().getIntExtra(EXTRA_APPWIDGET_ID, INVALID_APPWIDGET_ID);
mViewModel.onWidgetIdChanged(widgetId); viewModel.onWidgetIdChanged(widgetId);
ViewGroup view = PeopleViewBinder.create(this); ViewGroup view = PeopleViewBinder.create(this);
PeopleViewBinder.bind(view, mViewModel, /* lifecycleOwner= */ this, PeopleViewBinder.bind(view, viewModel, /* lifecycleOwner= */ this,
() -> { (result) -> {
finishActivity(); finishActivity(result);
return null; return null;
}); });
setContentView(view); setContentView(view);
} }
/** Finish activity with a successful widget configuration result. */ private void finishActivity(PeopleViewModel.Result result) {
private void finishActivity() { if (result instanceof PeopleViewModel.Result.Success) {
if (DEBUG) Log.d(TAG, "Widget added!"); if (DEBUG) Log.d(TAG, "Widget added!");
setActivityResult(RESULT_OK); Intent data = ((PeopleViewModel.Result.Success) result).getData();
finish(); setResult(RESULT_OK, data);
} } else {
/** Finish activity without choosing a widget. */
public void dismissActivity(View v) {
if (DEBUG) Log.d(TAG, "Activity dismissed with no widgets added!"); if (DEBUG) Log.d(TAG, "Activity dismissed with no widgets added!");
setResult(RESULT_CANCELED); setResult(RESULT_CANCELED);
}
finish(); finish();
} }
private void setActivityResult(int result) {
Intent resultValue = new Intent();
resultValue.putExtra(EXTRA_APPWIDGET_ID, mViewModel.getAppWidgetId().getValue());
setResult(result, resultValue);
}
} }

View File

@@ -41,7 +41,7 @@ import kotlinx.coroutines.launch
/** A ViewBinder for [PeopleViewModel]. */ /** A ViewBinder for [PeopleViewModel]. */
object PeopleViewBinder { object PeopleViewBinder {
private const val TAG = "PeopleSpaceViewBinder" private const val TAG = "PeopleViewBinder"
/** /**
* The [ViewOutlineProvider] used to clip the corner radius of the recent and priority lists. * The [ViewOutlineProvider] used to clip the corner radius of the recent and priority lists.
@@ -72,15 +72,15 @@ object PeopleViewBinder {
view: ViewGroup, view: ViewGroup,
viewModel: PeopleViewModel, viewModel: PeopleViewModel,
lifecycleOwner: LifecycleOwner, lifecycleOwner: LifecycleOwner,
onFinish: () -> Unit, onResult: (PeopleViewModel.Result) -> Unit,
) { ) {
// Call [onFinish] this activity when the ViewModel tells us so. // Call [onResult] as soon as a result is available.
lifecycleOwner.lifecycleScope.launch { lifecycleOwner.lifecycleScope.launch {
lifecycleOwner.repeatOnLifecycle(CREATED) { lifecycleOwner.repeatOnLifecycle(CREATED) {
viewModel.isFinished.collect { isFinished -> viewModel.result.collect { result ->
if (isFinished) { if (result != null) {
viewModel.clearIsFinished() viewModel.clearResult()
onFinish() onResult(result)
} }
} }
} }
@@ -104,7 +104,7 @@ object PeopleViewBinder {
viewModel::onTileClicked, viewModel::onTileClicked,
) )
} else { } else {
setNoConversationsContent(view) setNoConversationsContent(view, viewModel::onUserJourneyCancelled)
} }
} }
} }
@@ -119,7 +119,7 @@ object PeopleViewBinder {
} }
} }
private fun setNoConversationsContent(view: ViewGroup) { private fun setNoConversationsContent(view: ViewGroup, onGotItClicked: () -> Unit) {
// This should never happen. // This should never happen.
if (view.childCount > 1) { if (view.childCount > 1) {
error("view has ${view.childCount} children, it should have maximum 1") error("view has ${view.childCount} children, it should have maximum 1")
@@ -140,6 +140,10 @@ object PeopleViewBinder {
LayoutInflater.from(context) LayoutInflater.from(context)
.inflate(R.layout.people_space_activity_no_conversations, /* root= */ view) .inflate(R.layout.people_space_activity_no_conversations, /* root= */ view)
noConversationsView.findViewById<View>(R.id.got_it_button).setOnClickListener {
onGotItClicked()
}
// The Tile preview has colorBackground as its background. Change it so it's different than // The Tile preview has colorBackground as its background. Change it so it's different than
// the activity's background. // the activity's background.
val item = noConversationsView.findViewById<LinearLayout>(android.R.id.background) val item = noConversationsView.findViewById<LinearLayout>(android.R.id.background)

View File

@@ -16,8 +16,10 @@
package com.android.systemui.people.ui.viewmodel package com.android.systemui.people.ui.viewmodel
import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID
import android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID import android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID
import android.content.Context import android.content.Context
import android.content.Intent
import android.util.Log import android.util.Log
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
@@ -32,6 +34,7 @@ import javax.inject.Inject
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
/** /**
* Models UI state for the people space, allowing the user to select which conversation should be * Models UI state for the people space, allowing the user to select which conversation should be
@@ -49,7 +52,7 @@ class PeopleViewModel(
* reactive and you have to manually call [onTileRefreshRequested] to refresh the tiles. * reactive and you have to manually call [onTileRefreshRequested] to refresh the tiles.
*/ */
private val _priorityTiles = MutableStateFlow(priorityTiles()) private val _priorityTiles = MutableStateFlow(priorityTiles())
val priorityTiles: Flow<List<PeopleTileViewModel>> = _priorityTiles val priorityTiles: Flow<List<PeopleTileViewModel>> = _priorityTiles.asStateFlow()
/** /**
* The list of the priority tiles/conversations. * The list of the priority tiles/conversations.
@@ -58,15 +61,15 @@ class PeopleViewModel(
* reactive and you have to manually call [onTileRefreshRequested] to refresh the tiles. * reactive and you have to manually call [onTileRefreshRequested] to refresh the tiles.
*/ */
private val _recentTiles = MutableStateFlow(recentTiles()) private val _recentTiles = MutableStateFlow(recentTiles())
val recentTiles: Flow<List<PeopleTileViewModel>> = _recentTiles val recentTiles: Flow<List<PeopleTileViewModel>> = _recentTiles.asStateFlow()
/** The ID of the widget currently being edited/added. */ /** The ID of the widget currently being edited/added. */
private val _appWidgetId = MutableStateFlow(INVALID_APPWIDGET_ID) private val _appWidgetId = MutableStateFlow(INVALID_APPWIDGET_ID)
val appWidgetId: StateFlow<Int> = _appWidgetId val appWidgetId: StateFlow<Int> = _appWidgetId.asStateFlow()
/** Whether the user journey is complete. */ /** The result of this user journey. */
private val _isFinished = MutableStateFlow(false) private val _result = MutableStateFlow<Result?>(null)
val isFinished: StateFlow<Boolean> = _isFinished val result: StateFlow<Result?> = _result.asStateFlow()
/** Refresh the [priorityTiles] and [recentTiles]. */ /** Refresh the [priorityTiles] and [recentTiles]. */
fun onTileRefreshRequested() { fun onTileRefreshRequested() {
@@ -79,22 +82,28 @@ class PeopleViewModel(
_appWidgetId.value = widgetId _appWidgetId.value = widgetId
} }
/** Clear [isFinished], setting it to false. */ /** Clear [result], setting it to null. */
fun clearIsFinished() { fun clearResult() {
_isFinished.value = false _result.value = null
} }
/** Called when a tile is clicked. */ /** Called when a tile is clicked. */
fun onTileClicked(tile: PeopleTileViewModel) { fun onTileClicked(tile: PeopleTileViewModel) {
val widgetId = _appWidgetId.value
if (PeopleSpaceUtils.DEBUG) { if (PeopleSpaceUtils.DEBUG) {
Log.d( Log.d(
TAG, TAG,
"Put ${tile.username}'s shortcut ID: ${tile.key.shortcutId} for widget ID: " + "Put ${tile.username}'s shortcut ID: ${tile.key.shortcutId} for widget ID $widgetId"
_appWidgetId.value
) )
} }
widgetRepository.setWidgetTile(_appWidgetId.value, tile.key) widgetRepository.setWidgetTile(widgetId, tile.key)
_isFinished.value = true _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
} }
private fun priorityTiles(): List<PeopleTileViewModel> { private fun priorityTiles(): List<PeopleTileViewModel> {
@@ -143,7 +152,12 @@ class PeopleViewModel(
} }
} }
sealed class Result {
class Success(val data: Intent) : Result()
object Cancelled : Result()
}
companion object { companion object {
private const val TAG = "PeopleSpaceViewModel" private const val TAG = "PeopleViewModel"
} }
} }