From 5b1bf8a68eca5a6a3442e22bb5e171d1928dcf60 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 19 Oct 2022 11:40:43 +0200 Subject: [PATCH] Select devices with basic UI for tests --- .../settings/devices/v2/DeviceFullInfo.kt | 1 + .../devices/v2/list/OtherSessionItem.kt | 9 +++++ .../v2/list/OtherSessionsController.kt | 1 + .../v2/othersessions/OtherSessionsAction.kt | 3 +- .../v2/othersessions/OtherSessionsFragment.kt | 34 ++++++++++------- .../othersessions/OtherSessionsViewModel.kt | 35 +++++++++++++++-- .../main/res/layout/item_other_session.xml | 38 +++++++++++++------ .../main/res/layout/view_other_sessions.xml | 2 +- 8 files changed, 93 insertions(+), 30 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt index a47ea7e917..4864c41394 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt @@ -30,4 +30,5 @@ data class DeviceFullInfo( val isCurrentDevice: Boolean, val deviceExtendedInfo: DeviceExtendedInfo, val matrixClientInfo: MatrixClientInfoContent?, + val isSelected: Boolean = false, ) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionItem.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionItem.kt index 6397a42f7f..888305fb4e 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionItem.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionItem.kt @@ -17,10 +17,12 @@ package im.vector.app.features.settings.devices.v2.list import android.graphics.drawable.Drawable +import android.view.View import android.view.View.OnLongClickListener import android.widget.ImageView import android.widget.TextView import androidx.annotation.ColorInt +import androidx.core.content.ContextCompat import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.app.R @@ -57,6 +59,9 @@ abstract class OtherSessionItem : VectorEpoxyModel(R.la @EpoxyAttribute lateinit var stringProvider: StringProvider + @EpoxyAttribute + var selected: Boolean = false + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var clickListener: ClickListener? = null @@ -81,6 +86,9 @@ abstract class OtherSessionItem : VectorEpoxyModel(R.la holder.otherSessionDescriptionTextView.setTextColor(it) } holder.otherSessionDescriptionTextView.setCompoundDrawablesWithIntrinsicBounds(sessionDescriptionDrawable, null, null, null) + // TODO set drawable with correct color and corners + val color = if (selected) R.color.alert_default_error_background else android.R.color.transparent + holder.otherSessionItemBackgroundView.setBackgroundColor(ContextCompat.getColor(holder.view.context, color)) } class Holder : VectorEpoxyHolder() { @@ -88,5 +96,6 @@ abstract class OtherSessionItem : VectorEpoxyModel(R.la val otherSessionVerificationStatusImageView by bind(R.id.otherSessionVerificationStatusImageView) val otherSessionNameTextView by bind(R.id.otherSessionNameTextView) val otherSessionDescriptionTextView by bind(R.id.otherSessionDescriptionTextView) + val otherSessionItemBackgroundView by bind(R.id.otherSessionItemBackground) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt index d7166d02d2..b50abaaf7d 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt @@ -73,6 +73,7 @@ class OtherSessionsController @Inject constructor( sessionDescriptionDrawable(descriptionDrawable) sessionDescriptionColor(descriptionColor) stringProvider(this@OtherSessionsController.stringProvider) + selected(device.isSelected) clickListener { device.deviceInfo.deviceId?.let { host.callback?.onItemClicked(it) } } onLongClickListener(View.OnLongClickListener { device.deviceInfo.deviceId?.let { host.callback?.onItemLongClicked(it) } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsAction.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsAction.kt index 2d184ffeaa..becac467ec 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsAction.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsAction.kt @@ -21,6 +21,7 @@ import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType sealed class OtherSessionsAction : VectorViewModelAction { data class FilterDevices(val filterType: DeviceManagerFilterType) : OtherSessionsAction() - object EnableSelectMode : OtherSessionsAction() + data class EnableSelectMode(val deviceId: String?) : OtherSessionsAction() object DisableSelectMode : OtherSessionsAction() + data class ToggleSelectionForDevice(val deviceId: String) : OtherSessionsAction() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt index 77aac4d91d..1a0d63f04a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt @@ -89,8 +89,8 @@ class OtherSessionsFragment : } } - private fun enableSelectMode(isEnabled: Boolean) { - val action = if (isEnabled) OtherSessionsAction.EnableSelectMode else OtherSessionsAction.DisableSelectMode + private fun enableSelectMode(isEnabled: Boolean, deviceId: String? = null) { + val action = if (isEnabled) OtherSessionsAction.EnableSelectMode(deviceId) else OtherSessionsAction.DisableSelectMode viewModel.handle(action) } @@ -153,23 +153,25 @@ class OtherSessionsFragment : } override fun invalidate() = withState(viewModel) { state -> - updateToolbar(state.isSelectModeEnabled) if (state.devices is Success) { - renderDevices(state.devices(), state.currentFilter) + val devices = state.devices().orEmpty() + renderDevices(devices, state.currentFilter) + updateToolbar(devices, state.isSelectModeEnabled) } } - private fun updateToolbar(isSelectModeEnabled: Boolean) { + private fun updateToolbar(devices: List, isSelectModeEnabled: Boolean) { invalidateOptionsMenu() val title = if (isSelectModeEnabled) { - stringProvider.getQuantityString(R.plurals.device_manager_other_sessions_selected, 0, 0) + val selection = devices.count { it.isSelected } + stringProvider.getQuantityString(R.plurals.device_manager_other_sessions_selected, selection, selection) } else { getString(args.titleResourceId) } toolbar?.title = title } - private fun renderDevices(devices: List?, currentFilter: DeviceManagerFilterType) { + private fun renderDevices(devices: List, currentFilter: DeviceManagerFilterType) { views.otherSessionsFilterBadgeImageView.isVisible = currentFilter != DeviceManagerFilterType.ALL_SESSIONS views.otherSessionsSecurityRecommendationView.isVisible = currentFilter != DeviceManagerFilterType.ALL_SESSIONS views.deviceListHeaderOtherSessions.isVisible = currentFilter == DeviceManagerFilterType.ALL_SESSIONS @@ -222,7 +224,7 @@ class OtherSessionsFragment : } } - if (devices.isNullOrEmpty()) { + if (devices.isEmpty()) { views.deviceListOtherSessions.isVisible = false views.otherSessionsNotFoundLayout.isVisible = true } else { @@ -254,15 +256,19 @@ class OtherSessionsFragment : override fun onOtherSessionLongClicked(deviceId: String) = withState(viewModel) { state -> if (!state.isSelectModeEnabled) { - enableSelectMode(true) + enableSelectMode(true, deviceId) } } - override fun onOtherSessionClicked(deviceId: String) { - viewNavigator.navigateToSessionOverview( - context = requireActivity(), - deviceId = deviceId - ) + override fun onOtherSessionClicked(deviceId: String) = withState(viewModel) { state -> + if (state.isSelectModeEnabled) { + viewModel.handle(OtherSessionsAction.ToggleSelectionForDevice(deviceId)) + } else { + viewNavigator.navigateToSessionOverview( + context = requireActivity(), + deviceId = deviceId + ) + } } override fun onViewAllOtherSessionsClicked() { diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt index 21291fc082..4a00f0ab2b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt @@ -17,6 +17,7 @@ package im.vector.app.features.settings.devices.v2.othersessions import com.airbnb.mvrx.MavericksViewModelFactory +import com.airbnb.mvrx.Success import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject @@ -69,7 +70,8 @@ class OtherSessionsViewModel @AssistedInject constructor( when (action) { is OtherSessionsAction.FilterDevices -> handleFilterDevices(action) OtherSessionsAction.DisableSelectMode -> handleDisableSelectMode() - OtherSessionsAction.EnableSelectMode -> handleEnableSelectMode() + is OtherSessionsAction.EnableSelectMode -> handleEnableSelectMode(action.deviceId) + is OtherSessionsAction.ToggleSelectionForDevice -> handleToggleSelectionForDevice(action.deviceId) } } @@ -83,10 +85,37 @@ class OtherSessionsViewModel @AssistedInject constructor( } private fun handleDisableSelectMode() { + // TODO deselect all selected sessions setState { copy(isSelectModeEnabled = false) } } - private fun handleEnableSelectMode() { - setState { copy(isSelectModeEnabled = true) } + private fun handleEnableSelectMode(deviceId: String?) { + toggleSelectionForDevice(deviceId, true) + } + + private fun handleToggleSelectionForDevice(deviceId: String) = withState { state -> + toggleSelectionForDevice(deviceId, state.isSelectModeEnabled) + } + + private fun toggleSelectionForDevice(deviceId: String?, enableSelectMode: Boolean) = withState { state -> + val updatedDevices = if (state.devices is Success) { + val devices = state.devices.invoke().toMutableList() + val indexToUpdate = devices.indexOfFirst { it.deviceInfo.deviceId == deviceId } + if (indexToUpdate >= 0) { + val currentInfo = devices[indexToUpdate] + val updatedInfo = currentInfo.copy(isSelected = !currentInfo.isSelected) + devices[indexToUpdate] = updatedInfo + } + Success(devices) + } else { + state.devices + } + + setState { + copy( + devices = updatedDevices, + isSelectModeEnabled = enableSelectMode + ) + } } } diff --git a/vector/src/main/res/layout/item_other_session.xml b/vector/src/main/res/layout/item_other_session.xml index 2f93c2be5d..29f6fafcbc 100644 --- a/vector/src/main/res/layout/item_other_session.xml +++ b/vector/src/main/res/layout/item_other_session.xml @@ -5,30 +5,44 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:foreground="?selectableItemBackground" - android:paddingTop="16dp"> + android:paddingTop="8dp" + android:paddingHorizontal="8dp"> + + @@ -59,10 +75,10 @@ + app:layout_constraintTop_toBottomOf="@+id/otherSessionItemBackground" /> diff --git a/vector/src/main/res/layout/view_other_sessions.xml b/vector/src/main/res/layout/view_other_sessions.xml index aacbbe8ffe..2d02870174 100644 --- a/vector/src/main/res/layout/view_other_sessions.xml +++ b/vector/src/main/res/layout/view_other_sessions.xml @@ -9,7 +9,6 @@ android:id="@+id/otherSessionsRecyclerView" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginStart="16dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -21,6 +20,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="0dp" + android:layout_marginStart="16dp" app:layout_constraintStart_toStartOf="@id/otherSessionsRecyclerView" app:layout_constraintTop_toBottomOf="@id/otherSessionsRecyclerView" tools:text="@string/device_manager_other_sessions_view_all" />