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

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

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

parents 9ef43b2f e5787f97
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -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"
+16 −24
Original line number Original line Diff line number Diff line
@@ -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);
    }
    }
}
}
+13 −9
Original line number Original line Diff line number Diff line
@@ -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)
+28 −14
Original line number Original line Diff line number Diff line
@@ -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"
    }
    }
}
}