From e3155b6c980b7792a38529fdd65793dcf13df30f Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Fri, 3 Dec 2021 15:47:45 +0000 Subject: [PATCH 01/70] removing notifications v1, v2 is live --- vector/build.gradle | 1 - .../settings/SettingsNotificationsRobot.kt | 24 ++----- .../im/vector/app/features/VectorFeatures.kt | 2 - .../RoomListQuickActionsEpoxyController.kt | 70 +++++++------------ .../roomprofile/RoomProfileFragment.kt | 17 +---- .../features/settings/VectorPreferences.kt | 4 -- ...rSettingsNotificationPreferenceFragment.kt | 14 +--- .../res/xml/vector_settings_notifications.xml | 8 --- 8 files changed, 36 insertions(+), 104 deletions(-) diff --git a/vector/build.gradle b/vector/build.gradle index d29f36c877..9664d85bf2 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -141,7 +141,6 @@ android { resValue "string", "build_number", "\"${buildNumber}\"" buildConfigField "im.vector.app.features.VectorFeatures.LoginVersion", "LOGIN_VERSION", "im.vector.app.features.VectorFeatures.LoginVersion.V1" - buildConfigField "im.vector.app.features.VectorFeatures.NotificationSettingsVersion", "NOTIFICATION_SETTINGS_VERSION", "im.vector.app.features.VectorFeatures.NotificationSettingsVersion.V2" buildConfigField "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy", "outboundSessionKeySharingStrategy", "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy.WhenTyping" diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt index 4dddc4c9cc..433a70b5e3 100644 --- a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt +++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt @@ -18,29 +18,19 @@ package im.vector.app.ui.robot.settings import androidx.test.espresso.Espresso.pressBack import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn -import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.espresso.tools.clickOnPreference -import im.vector.app.features.VectorFeatures class SettingsNotificationsRobot { fun crawl() { - when (BuildConfig.NOTIFICATION_SETTINGS_VERSION!!) { - VectorFeatures.NotificationSettingsVersion.V1 -> { - clickOn(R.string.settings_notification_advanced) - pressBack() - } - VectorFeatures.NotificationSettingsVersion.V2 -> { - clickOn(R.string.settings_notification_default) - pressBack() - clickOn(R.string.settings_notification_mentions_and_keywords) - // TODO Test adding a keyword? - pressBack() - clickOn(R.string.settings_notification_other) - pressBack() - } - } + clickOn(R.string.settings_notification_default) + pressBack() + clickOn(R.string.settings_notification_mentions_and_keywords) + // TODO Test adding a keyword? + pressBack() + clickOn(R.string.settings_notification_other) + pressBack() /* clickOn(R.string.settings_noisy_notifications_preferences) diff --git a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt index b40d2d02f2..e106f7f75f 100644 --- a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt +++ b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt @@ -21,7 +21,6 @@ import im.vector.app.BuildConfig interface VectorFeatures { fun loginVersion(): LoginVersion - fun notificationSettingsVersion(): NotificationSettingsVersion enum class LoginVersion { V1, @@ -36,5 +35,4 @@ interface VectorFeatures { class DefaultVectorFeatures : VectorFeatures { override fun loginVersion(): VectorFeatures.LoginVersion = BuildConfig.LOGIN_VERSION - override fun notificationSettingsVersion(): VectorFeatures.NotificationSettingsVersion = BuildConfig.NOTIFICATION_SETTINGS_VERSION } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt index a2d10cf818..433fca5430 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt @@ -24,7 +24,6 @@ import im.vector.app.core.epoxy.bottomsheet.bottomSheetRoomPreviewItem import im.vector.app.core.epoxy.profiles.notifications.radioButtonItem import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.StringProvider -import im.vector.app.features.VectorFeatures import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.roomprofile.notifications.notificationOptions import im.vector.app.features.roomprofile.notifications.notificationStateMapped @@ -39,7 +38,6 @@ class RoomListQuickActionsEpoxyController @Inject constructor( private val avatarRenderer: AvatarRenderer, private val colorProvider: ColorProvider, private val stringProvider: StringProvider, - private val features: VectorFeatures ) : TypedEpoxyController() { var listener: Listener? = null @@ -48,54 +46,38 @@ class RoomListQuickActionsEpoxyController @Inject constructor( val notificationViewState = state.notificationSettingsViewState val roomSummary = notificationViewState.roomSummary() ?: return val host = this - val isV2 = features.notificationSettingsVersion() == VectorFeatures.NotificationSettingsVersion.V2 - // V2 always shows full details as we no longer display the sheet from RoomProfile > Notifications - val showFull = state.roomListActionsArgs.mode == RoomListActionsArgs.Mode.FULL || isV2 - - if (showFull) { - // Preview, favorite, settings - bottomSheetRoomPreviewItem { - id("room_preview") - avatarRenderer(host.avatarRenderer) - matrixItem(roomSummary.toMatrixItem()) - stringProvider(host.stringProvider) - colorProvider(host.colorProvider) - izLowPriority(roomSummary.isLowPriority) - izFavorite(roomSummary.isFavorite) - settingsClickListener { host.listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Settings(roomSummary.roomId)) } - favoriteClickListener { host.listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Favorite(roomSummary.roomId)) } - lowPriorityClickListener { host.listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.LowPriority(roomSummary.roomId)) } - } - - // Notifications - bottomSheetDividerItem { - id("notifications_separator") - } + // Preview, favorite, settings + bottomSheetRoomPreviewItem { + id("room_preview") + avatarRenderer(host.avatarRenderer) + matrixItem(roomSummary.toMatrixItem()) + stringProvider(host.stringProvider) + colorProvider(host.colorProvider) + izLowPriority(roomSummary.isLowPriority) + izFavorite(roomSummary.isFavorite) + settingsClickListener { host.listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Settings(roomSummary.roomId)) } + favoriteClickListener { host.listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Favorite(roomSummary.roomId)) } + lowPriorityClickListener { host.listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.LowPriority(roomSummary.roomId)) } } - if (isV2) { - notificationViewState.notificationOptions.forEach { notificationState -> - val title = titleForNotificationState(notificationState) - radioButtonItem { - id(notificationState.name) - titleRes(title) - selected(notificationViewState.notificationStateMapped() == notificationState) - listener { - host.listener?.didSelectRoomNotificationState(notificationState) - } + // Notifications + bottomSheetDividerItem { + id("notifications_separator") + } + + notificationViewState.notificationOptions.forEach { notificationState -> + val title = titleForNotificationState(notificationState) + radioButtonItem { + id(notificationState.name) + titleRes(title) + selected(notificationViewState.notificationStateMapped() == notificationState) + listener { + host.listener?.didSelectRoomNotificationState(notificationState) } } - } else { - val selectedRoomState = notificationViewState.notificationState() - RoomListQuickActionsSharedAction.NotificationsAllNoisy(roomSummary.roomId).toBottomSheetItem(0, selectedRoomState) - RoomListQuickActionsSharedAction.NotificationsAll(roomSummary.roomId).toBottomSheetItem(1, selectedRoomState) - RoomListQuickActionsSharedAction.NotificationsMentionsOnly(roomSummary.roomId).toBottomSheetItem(2, selectedRoomState) - RoomListQuickActionsSharedAction.NotificationsMute(roomSummary.roomId).toBottomSheetItem(3, selectedRoomState) } - if (showFull) { - RoomListQuickActionsSharedAction.Leave(roomSummary.roomId, showIcon = !isV2).toBottomSheetItem(5) - } + RoomListQuickActionsSharedAction.Leave(roomSummary.roomId, showIcon = !true).toBottomSheetItem(5) } @StringRes diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index 4dac4be489..35088b6e07 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -44,13 +44,10 @@ import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.databinding.FragmentMatrixProfileBinding import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding -import im.vector.app.features.VectorFeatures import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.RoomDetailPendingAction import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet -import im.vector.app.features.home.room.list.actions.RoomListActionsArgs -import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import kotlinx.coroutines.flow.launchIn @@ -69,8 +66,7 @@ data class RoomProfileArgs( class RoomProfileFragment @Inject constructor( private val roomProfileController: RoomProfileController, private val avatarRenderer: AvatarRenderer, - private val roomDetailPendingActionStore: RoomDetailPendingActionStore, - private val features: VectorFeatures + private val roomDetailPendingActionStore: RoomDetailPendingActionStore ) : VectorBaseFragment(), RoomProfileController.Callback { @@ -259,16 +255,7 @@ class RoomProfileFragment @Inject constructor( } override fun onNotificationsClicked() { - when (features.notificationSettingsVersion()) { - VectorFeatures.NotificationSettingsVersion.V1 -> { - RoomListQuickActionsBottomSheet - .newInstance(roomProfileArgs.roomId, RoomListActionsArgs.Mode.NOTIFICATIONS) - .show(childFragmentManager, "ROOM_PROFILE_NOTIFICATIONS") - } - VectorFeatures.NotificationSettingsVersion.V2 -> { - roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomNotificationSettings) - } - } + roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomNotificationSettings) } override fun onUploadsClicked() { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 6eb8d7c195..47c9af3168 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -46,10 +46,6 @@ class VectorPreferences @Inject constructor(private val context: Context) { const val SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY = "SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY" const val SETTINGS_DISCOVERY_PREFERENCE_KEY = "SETTINGS_DISCOVERY_PREFERENCE_KEY" - const val SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY" - const val SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY" - const val SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY" - const val SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY" const val SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY" const val SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY" const val SETTINGS_COPYRIGHT_PREFERENCE_KEY = "SETTINGS_COPYRIGHT_PREFERENCE_KEY" diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index 3004d30913..4199bd1753 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -40,7 +40,6 @@ import im.vector.app.core.pushers.PushersManager import im.vector.app.core.services.GuardServiceStarter import im.vector.app.core.utils.isIgnoringBatteryOptimizations import im.vector.app.core.utils.requestDisablingBatteryOptimization -import im.vector.app.features.VectorFeatures import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.BackgroundSyncModeChooserDialog @@ -64,8 +63,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( private val pushManager: PushersManager, private val activeSessionHolder: ActiveSessionHolder, private val vectorPreferences: VectorPreferences, - private val guardServiceStarter: GuardServiceStarter, - private val features: VectorFeatures + private val guardServiceStarter: GuardServiceStarter ) : VectorSettingsBaseFragment(), BackgroundSyncModeChooserDialog.InteractionListener { @@ -147,7 +145,6 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( refreshBackgroundSyncPrefs() handleSystemPreference() - handleVersionedSettings() } private fun bindEmailNotifications() { @@ -312,15 +309,6 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( } } - private fun handleVersionedSettings() { - val isNotificationSettingsV2Enabled = features.notificationSettingsVersion() == VectorFeatures.NotificationSettingsVersion.V2 - - findPreference(VectorPreferences.SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY)?.isVisible = !isNotificationSettingsV2Enabled - findPreference(VectorPreferences.SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled - findPreference(VectorPreferences.SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled - findPreference(VectorPreferences.SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled - } - override fun onResume() { super.onResume() activeSessionHolder.getSafeActiveSession()?.refreshPushers() diff --git a/vector/src/main/res/xml/vector_settings_notifications.xml b/vector/src/main/res/xml/vector_settings_notifications.xml index 154e7cca0d..66ac93a4f9 100644 --- a/vector/src/main/res/xml/vector_settings_notifications.xml +++ b/vector/src/main/res/xml/vector_settings_notifications.xml @@ -20,14 +20,6 @@ - - Date: Mon, 6 Dec 2021 10:14:20 +0000 Subject: [PATCH 02/70] removing now longer needed Mode argument --- .../features/home/room/list/RoomListFragment.kt | 3 +-- .../actions/RoomListQuickActionsBottomSheet.kt | 15 ++++----------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt index 6543cc8795..f67abfbc88 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt @@ -44,7 +44,6 @@ import im.vector.app.core.resources.UserPreferencesProvider import im.vector.app.databinding.FragmentRoomListBinding import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.home.room.filtered.FilteredRoomFooterItem -import im.vector.app.features.home.room.list.actions.RoomListActionsArgs import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel @@ -476,7 +475,7 @@ class RoomListFragment @Inject constructor( footerController.setData(it) } RoomListQuickActionsBottomSheet - .newInstance(room.roomId, RoomListActionsArgs.Mode.FULL) + .newInstance(room.roomId) .show(childFragmentManager, "ROOM_LIST_QUICK_ACTIONS") return true } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt index 014ce14c95..5d8cda94ae 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt @@ -43,15 +43,8 @@ import javax.inject.Inject @Parcelize data class RoomListActionsArgs( - val roomId: String, - val mode: Mode -) : Parcelable { - - enum class Mode { - FULL, - NOTIFICATIONS - } -} + val roomId: String +) : Parcelable /** * Bottom sheet fragment that shows room information with list of contextual actions @@ -124,9 +117,9 @@ class RoomListQuickActionsBottomSheet : } companion object { - fun newInstance(roomId: String, mode: RoomListActionsArgs.Mode): RoomListQuickActionsBottomSheet { + fun newInstance(roomId: String): RoomListQuickActionsBottomSheet { return RoomListQuickActionsBottomSheet().apply { - setArguments(RoomListActionsArgs(roomId, mode)) + setArguments(RoomListActionsArgs(roomId)) } } } From 952ceced05c3f055806f326b51827503bec94314 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 1 Dec 2021 17:17:11 +0000 Subject: [PATCH 03/70] updating url preview to match new designs --- .../drawable/ic_close_with_circular_bg.xml | 23 +++ .../src/main/res/layout/view_url_preview.xml | 142 +++++++++--------- 2 files changed, 92 insertions(+), 73 deletions(-) create mode 100644 vector/src/main/res/drawable/ic_close_with_circular_bg.xml diff --git a/vector/src/main/res/drawable/ic_close_with_circular_bg.xml b/vector/src/main/res/drawable/ic_close_with_circular_bg.xml new file mode 100644 index 0000000000..a38416674a --- /dev/null +++ b/vector/src/main/res/drawable/ic_close_with_circular_bg.xml @@ -0,0 +1,23 @@ + + + + + diff --git a/vector/src/main/res/layout/view_url_preview.xml b/vector/src/main/res/layout/view_url_preview.xml index 45c35279c8..772bd7d48b 100644 --- a/vector/src/main/res/layout/view_url_preview.xml +++ b/vector/src/main/res/layout/view_url_preview.xml @@ -7,83 +7,79 @@ android:layout_height="wrap_content" tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout"> - + - + - + - + - + - + + + + + + + \ No newline at end of file From 6a749f106da71bdb7b7fa17355f264701e0af101 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 1 Dec 2021 17:27:59 +0000 Subject: [PATCH 04/70] adding changelog entry --- changelog.d/4278.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/4278.feature diff --git a/changelog.d/4278.feature b/changelog.d/4278.feature new file mode 100644 index 0000000000..fe82755186 --- /dev/null +++ b/changelog.d/4278.feature @@ -0,0 +1 @@ +Updates URL previews to match latest designs \ No newline at end of file From 0150d830d4a28d90d708ef9a35103cbe92e8aada Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Dec 2021 09:46:36 +0000 Subject: [PATCH 05/70] flattening preview url view layout with custom view to reduce view hierarchy --- .../ui-styles/src/main/res/values/dimens.xml | 3 + .../detail/timeline/url/PreviewUrlView.kt | 8 +- .../src/main/res/layout/view_url_preview.xml | 136 +++++++++--------- 3 files changed, 73 insertions(+), 74 deletions(-) diff --git a/library/ui-styles/src/main/res/values/dimens.xml b/library/ui-styles/src/main/res/values/dimens.xml index 519920786c..864f3d3d7f 100644 --- a/library/ui-styles/src/main/res/values/dimens.xml +++ b/library/ui-styles/src/main/res/values/dimens.xml @@ -39,4 +39,7 @@ 320dp + + + 8dp \ No newline at end of file diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt index 3e08ce5589..1a81362618 100755 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt @@ -19,13 +19,14 @@ package im.vector.app.features.home.room.detail.timeline.url import android.content.Context import android.util.AttributeSet import android.view.View -import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible +import com.google.android.material.card.MaterialCardView import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide import im.vector.app.databinding.ViewUrlPreviewBinding import im.vector.app.features.home.room.detail.timeline.TimelineEventController import im.vector.app.features.media.ImageContentRenderer +import im.vector.app.features.themes.ThemeUtils import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.media.PreviewUrlData @@ -36,7 +37,7 @@ class PreviewUrlView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener { +) : MaterialCardView(context, attrs, defStyleAttr), View.OnClickListener { private lateinit var views: ViewUrlPreviewBinding @@ -44,6 +45,9 @@ class PreviewUrlView @JvmOverloads constructor( init { setupView() + radius = resources.getDimensionPixelSize(R.dimen.preview_url_view_corner_radius).toFloat() + cardElevation = 0f + setCardBackgroundColor(ThemeUtils.getColor(context, R.attr.vctr_system)) } private var state: PreviewUrlUiState = PreviewUrlUiState.Unknown diff --git a/vector/src/main/res/layout/view_url_preview.xml b/vector/src/main/res/layout/view_url_preview.xml index 772bd7d48b..f40316b77b 100644 --- a/vector/src/main/res/layout/view_url_preview.xml +++ b/vector/src/main/res/layout/view_url_preview.xml @@ -1,85 +1,77 @@ + tools:parentTag="com.google.android.material.card.MaterialCardView"> - - - - - - - - - - - - - + android:layout_height="wrap_content" + android:orientation="vertical"> + android:id="@+id/url_preview_image" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:adjustViewBounds="true" + android:importantForAccessibility="no" + android:scaleType="fitXY" + tools:src="@tools:sample/backgrounds/scenic" /> - + + + + + + + + + \ No newline at end of file From f3f28f3989c4b946213b1c9f868e2a2a0191bbae Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Dec 2021 10:09:31 +0000 Subject: [PATCH 06/70] limiting title to avoid overlapping with close icon --- vector/src/main/res/layout/view_url_preview.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/res/layout/view_url_preview.xml b/vector/src/main/res/layout/view_url_preview.xml index f40316b77b..5636068fdb 100644 --- a/vector/src/main/res/layout/view_url_preview.xml +++ b/vector/src/main/res/layout/view_url_preview.xml @@ -41,7 +41,7 @@ android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="4dp" - android:layout_marginEnd="8dp" + android:layout_marginEnd="@dimen/layout_touch_size" android:ellipsize="end" android:maxLines="2" android:textColor="?vctr_content_primary" From 170f34639bdcc758388e698fdc03add2c8ba2ca0 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Dec 2021 10:19:14 +0000 Subject: [PATCH 07/70] using themed colours for the close button --- vector/src/main/res/drawable/ic_close_with_circular_bg.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/res/drawable/ic_close_with_circular_bg.xml b/vector/src/main/res/drawable/ic_close_with_circular_bg.xml index a38416674a..5e54b638a0 100644 --- a/vector/src/main/res/drawable/ic_close_with_circular_bg.xml +++ b/vector/src/main/res/drawable/ic_close_with_circular_bg.xml @@ -5,19 +5,19 @@ android:viewportHeight="24"> From 9094173b52ddd6728e4d39008330826b6449520f Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Dec 2021 11:01:03 +0000 Subject: [PATCH 08/70] matching iOS max line rules for the preview description --- .../home/room/detail/timeline/url/PreviewUrlView.kt | 6 ++++++ vector/src/main/res/layout/view_url_preview.xml | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt index 1a81362618..631f00819c 100755 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt @@ -125,9 +125,15 @@ class PreviewUrlView @JvmOverloads constructor( private fun renderData(previewUrlData: PreviewUrlData, imageContentRenderer: ImageContentRenderer) { isVisible = true + views.urlPreviewTitle.setTextOrHide(previewUrlData.title) views.urlPreviewImage.isVisible = previewUrlData.mxcUrl?.let { imageContentRenderer.render(it, views.urlPreviewImage) }.orFalse() views.urlPreviewDescription.setTextOrHide(previewUrlData.description) + views.urlPreviewDescription.maxLines = when { + previewUrlData.mxcUrl != null -> 2 + previewUrlData.title != null -> 3 + else -> 5 + } views.urlPreviewSite.setTextOrHide(previewUrlData.siteName.takeIf { it != previewUrlData.title }) } diff --git a/vector/src/main/res/layout/view_url_preview.xml b/vector/src/main/res/layout/view_url_preview.xml index 5636068fdb..530a8da476 100644 --- a/vector/src/main/res/layout/view_url_preview.xml +++ b/vector/src/main/res/layout/view_url_preview.xml @@ -58,7 +58,6 @@ android:layout_marginEnd="8dp" android:layout_marginBottom="8dp" android:ellipsize="end" - android:maxLines="2" android:textColor="?vctr_content_secondary" tools:text="The British perfumer says removing actor John Boyega from his own advert was “utterly despicable”." /> From 5cfebb764c3b93b75c17f6684a31f99280028b59 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Dec 2021 11:46:26 +0000 Subject: [PATCH 09/70] capping the preview image url based on the height - stops large screens eg tablets from attempting to fill the screen --- .../res/layout/item_timeline_event_text_message_stub.xml | 2 +- vector/src/main/res/layout/view_url_preview.xml | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml b/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml index 39df45989c..8d4bfcf14e 100644 --- a/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml +++ b/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml @@ -16,7 +16,7 @@ From 3ff3507fa1a9627e13a39a6ce5edfb4e572470e5 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 2 Dec 2021 11:50:28 +0000 Subject: [PATCH 10/70] forcing the send spacing to always be taking into account - ensures all message lengths are consistent --- .../vector/app/core/ui/views/SendStateImageView.kt | 12 ++++++------ .../src/main/res/layout/item_timeline_event_base.xml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/ui/views/SendStateImageView.kt b/vector/src/main/java/im/vector/app/core/ui/views/SendStateImageView.kt index cb1d08d2e5..3d710e2b24 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/SendStateImageView.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/SendStateImageView.kt @@ -20,7 +20,7 @@ import android.content.Context import android.content.res.ColorStateList import android.util.AttributeSet import androidx.appcompat.widget.AppCompatImageView -import androidx.core.view.isVisible +import androidx.core.view.isInvisible import im.vector.app.R import im.vector.app.features.home.room.detail.timeline.item.SendStateDecoration import im.vector.app.features.themes.ThemeUtils @@ -38,28 +38,28 @@ class SendStateImageView @JvmOverloads constructor( } fun render(sendState: SendStateDecoration) { - isVisible = when (sendState) { + isInvisible = when (sendState) { SendStateDecoration.SENDING_NON_MEDIA -> { setImageResource(R.drawable.ic_sending_message) imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.vctr_content_tertiary)) contentDescription = context.getString(R.string.event_status_a11y_sending) - true + false } SendStateDecoration.SENT -> { setImageResource(R.drawable.ic_message_sent) imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.vctr_content_tertiary)) contentDescription = context.getString(R.string.event_status_a11y_sent) - true + false } SendStateDecoration.FAILED -> { setImageResource(R.drawable.ic_sending_message_failed) imageTintList = null contentDescription = context.getString(R.string.event_status_a11y_failed) - true + false } SendStateDecoration.SENDING_MEDIA, SendStateDecoration.NONE -> { - false + true } } } diff --git a/vector/src/main/res/layout/item_timeline_event_base.xml b/vector/src/main/res/layout/item_timeline_event_base.xml index ed6e501d49..d85dc5cd0d 100644 --- a/vector/src/main/res/layout/item_timeline_event_base.xml +++ b/vector/src/main/res/layout/item_timeline_event_base.xml @@ -152,7 +152,7 @@ android:layout_marginBottom="4dp" android:contentDescription="@string/event_status_a11y_sending" android:src="@drawable/ic_sending_message" - android:visibility="gone" + android:visibility="invisible" tools:tint="?vctr_content_tertiary" tools:visibility="visible" /> From 9ed72fd1eb37b4e5df0489f3de8c038c34e49ede Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 7 Dec 2021 12:58:46 +0000 Subject: [PATCH 11/70] removing manual end alignment for voice messages as send status gutter is now always present --- .../home/room/detail/timeline/item/BaseEventItem.kt | 10 ---------- .../home/room/detail/timeline/item/MessageVoiceItem.kt | 4 ---- 2 files changed, 14 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt index 6aeb1519a9..5dfbf5d8f6 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt @@ -43,22 +43,12 @@ abstract class BaseEventItem : VectorEpoxyModel @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) lateinit var dimensionConverter: DimensionConverter - protected var ignoreSendStatusVisibility = false - @CallSuper override fun bind(holder: H) { super.bind(holder) holder.leftGuideline.updateLayoutParams { this.marginStart = leftGuideline } - // Ignore visibility of the send status icon? - holder.contentContainer.updateLayoutParams { - if (ignoreSendStatusVisibility) { - addRule(RelativeLayout.ALIGN_PARENT_END) - } else { - removeRule(RelativeLayout.ALIGN_PARENT_END) - } - } holder.checkableBackground.isChecked = highlighted } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceItem.kt index fb7d0cabd5..f006c2aa35 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceItem.kt @@ -33,10 +33,6 @@ import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlayb @EpoxyModelClass(layout = R.layout.item_timeline_event_base) abstract class MessageVoiceItem : AbsMessageItem() { - init { - ignoreSendStatusVisibility = true - } - @EpoxyAttribute var mxcUrl: String = "" From 23bc867b95d7f96e3dc551a2a5374bcb7ba1cfb7 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 7 Dec 2021 13:47:29 +0000 Subject: [PATCH 12/70] removing manual send status spacing - it's no longer needed as the send status is always present (but invisible) --- vector/src/main/res/layout/item_timeline_event_base.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/vector/src/main/res/layout/item_timeline_event_base.xml b/vector/src/main/res/layout/item_timeline_event_base.xml index d85dc5cd0d..6d778e85a4 100644 --- a/vector/src/main/res/layout/item_timeline_event_base.xml +++ b/vector/src/main/res/layout/item_timeline_event_base.xml @@ -115,27 +115,23 @@ android:id="@+id/messageContentRedactedStub" style="@style/TimelineContentStubBaseParams" android:layout_height="wrap_content" - android:layout_marginEnd="56dp" android:layout="@layout/item_timeline_event_redacted_stub" /> From 892d70812f0d6adc9e9495e0c5e79eec6443f5a9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 7 Dec 2021 14:45:48 +0100 Subject: [PATCH 13/70] Upgrade OLM to v3.2.7 and get it from our maven repository. --- build.gradle | 6 +++--- changelog.d/4647.misc | 1 + matrix-sdk-android/build.gradle | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 changelog.d/4647.misc diff --git a/build.gradle b/build.gradle index 4c3734892d..89825428fb 100644 --- a/build.gradle +++ b/build.gradle @@ -38,12 +38,12 @@ allprojects { repositories { // For olm library. This has to be declared first, to ensure that Olm library is not downloaded from another repo + maven { url 'https://gitlab.matrix.org/api/v4/projects/27/packages/maven' } + maven { url 'https://jitpack.io' content { - // Use this repo only for olm library - includeGroupByRegex "org\\.matrix\\.gitlab\\.matrix-org" - // And also for FilePicker + // Use this repo only for FilePicker includeGroupByRegex "com\\.github\\.jaiselrahman" // And monarchy includeGroupByRegex "com\\.github\\.Zhuinden" diff --git a/changelog.d/4647.misc b/changelog.d/4647.misc new file mode 100644 index 0000000000..a33afba138 --- /dev/null +++ b/changelog.d/4647.misc @@ -0,0 +1 @@ + Upgrade OLM to v3.2.7 and get it from our maven repository. \ No newline at end of file diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index e37231097d..cec5982658 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -140,8 +140,8 @@ dependencies { implementation libs.arrow.core implementation libs.arrow.instances - // olm lib is now hosted by jitpack: https://jitpack.io/#org.matrix.gitlab.matrix-org/olm - implementation 'org.matrix.gitlab.matrix-org:olm:3.2.4' + // olm lib is now hosted by maven at https://gitlab.matrix.org/api/v4/projects/27/packages/maven + implementation 'org.matrix.android:olm:3.2.7' // DI implementation libs.dagger.dagger From 7e6a5f944feea75d377dcfc497d153315d4edb12 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 7 Dec 2021 15:14:39 +0000 Subject: [PATCH 14/70] adding a consistent padding to allow message types to avoid touching the side gutter --- vector/src/main/res/layout/item_timeline_event_base.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/src/main/res/layout/item_timeline_event_base.xml b/vector/src/main/res/layout/item_timeline_event_base.xml index 6d778e85a4..6d3d3e8cd5 100644 --- a/vector/src/main/res/layout/item_timeline_event_base.xml +++ b/vector/src/main/res/layout/item_timeline_event_base.xml @@ -80,6 +80,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/messageMemberNameView" + android:layout_marginEnd="8dp" android:layout_toStartOf="@id/messageSendStateImageView" android:layout_toEndOf="@id/messageStartGuideline" android:addStatesFromChildren="true"> From 96295f61028934650dc3e546bdd6ccb73d377ff8 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 7 Dec 2021 10:42:02 +0000 Subject: [PATCH 15/70] removing no longer possible branches --- .../RoomListQuickActionsEpoxyController.kt | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt index 433fca5430..b343013408 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt @@ -77,7 +77,7 @@ class RoomListQuickActionsEpoxyController @Inject constructor( } } - RoomListQuickActionsSharedAction.Leave(roomSummary.roomId, showIcon = !true).toBottomSheetItem(5) + RoomListQuickActionsSharedAction.Leave(roomSummary.roomId, showIcon = !true).toBottomSheetItem() } @StringRes @@ -88,18 +88,11 @@ class RoomListQuickActionsEpoxyController @Inject constructor( else -> null } - private fun RoomListQuickActionsSharedAction.toBottomSheetItem(index: Int, roomNotificationState: RoomNotificationState? = null) { + private fun RoomListQuickActionsSharedAction.Leave.toBottomSheetItem() { val host = this@RoomListQuickActionsEpoxyController - val selected = when (this) { - is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> roomNotificationState == RoomNotificationState.ALL_MESSAGES_NOISY - is RoomListQuickActionsSharedAction.NotificationsAll -> roomNotificationState == RoomNotificationState.ALL_MESSAGES - is RoomListQuickActionsSharedAction.NotificationsMentionsOnly -> roomNotificationState == RoomNotificationState.MENTIONS_ONLY - is RoomListQuickActionsSharedAction.NotificationsMute -> roomNotificationState == RoomNotificationState.MUTE - else -> false - } return bottomSheetActionItem { - id("action_$index") - selected(selected) + id("action_leave") + selected(false) if (iconResId != null) { iconRes(iconResId) } else { From 2d74eb060c6689848d41716ff623d1dd5c75f8d7 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 6 Dec 2021 12:08:34 +0000 Subject: [PATCH 16/70] adding debug screen to override features - adds enum support with persistence via class names --- vector/src/debug/AndroidManifest.xml | 1 + .../app/features/debug/DebugMenuActivity.kt | 2 + .../app/features/debug/di/FeaturesModule.kt | 48 ++++++++++++ .../features/DebugFeaturesSettingsActivity.kt | 78 +++++++++++++++++++ .../debug/features/DebugVectorFeatures.kt | 66 ++++++++++++++++ .../debug/features/EnumFeatureItem.kt | 78 +++++++++++++++++++ .../debug/features/FeaturesController.kt | 52 +++++++++++++ .../debug/res/layout/activity_debug_menu.xml | 6 ++ vector/src/debug/res/layout/item_feature.xml | 30 +++++++ .../im/vector/app/core/di/SingletonModule.kt | 7 -- .../im/vector/app/core/di/FeaturesModule.kt | 34 ++++++++ 11 files changed, 395 insertions(+), 7 deletions(-) create mode 100644 vector/src/debug/java/im/vector/app/features/debug/di/FeaturesModule.kt create mode 100644 vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesSettingsActivity.kt create mode 100644 vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt create mode 100644 vector/src/debug/java/im/vector/app/features/debug/features/EnumFeatureItem.kt create mode 100644 vector/src/debug/java/im/vector/app/features/debug/features/FeaturesController.kt create mode 100644 vector/src/debug/res/layout/item_feature.xml create mode 100644 vector/src/release/java/im/vector/app/core/di/FeaturesModule.kt diff --git a/vector/src/debug/AndroidManifest.xml b/vector/src/debug/AndroidManifest.xml index dba8440602..ceeb0353db 100644 --- a/vector/src/debug/AndroidManifest.xml +++ b/vector/src/debug/AndroidManifest.xml @@ -7,6 +7,7 @@ + diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt index 64de648a23..4916ab1e5d 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt @@ -34,6 +34,7 @@ import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.core.utils.toast import im.vector.app.databinding.ActivityDebugMenuBinding +import im.vector.app.features.debug.features.DebugFeaturesSettingsActivity import im.vector.app.features.debug.sas.DebugSasEmojiActivity import im.vector.app.features.debug.settings.DebugPrivateSettingsActivity import im.vector.app.features.qrcode.QrCodeScannerActivity @@ -76,6 +77,7 @@ class DebugMenuActivity : VectorBaseActivity() { } private fun setupViews() { + views.debugFeatures.setOnClickListener { startActivity(Intent(this, DebugFeaturesSettingsActivity::class.java)) } views.debugPrivateSetting.setOnClickListener { openPrivateSettings() } views.debugTestTextViewLink.setOnClickListener { testTextViewLink() } views.debugOpenButtonStylesLight.setOnClickListener { diff --git a/vector/src/debug/java/im/vector/app/features/debug/di/FeaturesModule.kt b/vector/src/debug/java/im/vector/app/features/debug/di/FeaturesModule.kt new file mode 100644 index 0000000000..57c39d03d8 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/di/FeaturesModule.kt @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.debug.di + +import android.content.Context +import dagger.Binds +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import im.vector.app.features.DefaultVectorFeatures +import im.vector.app.features.VectorFeatures +import im.vector.app.features.debug.features.DebugVectorFeatures + +@InstallIn(SingletonComponent::class) +@Module +interface FeaturesModule { + + @Binds + fun bindNavigator(navigator: DebugVectorFeatures): VectorFeatures + + companion object { + + @Provides + fun providesDefaultVectorFeatures(): DefaultVectorFeatures { + return DefaultVectorFeatures() + } + + @Provides + fun providesDebugVectorFeatures(context: Context, defaultVectorFeatures: DefaultVectorFeatures): DebugVectorFeatures { + return DebugVectorFeatures(context, defaultVectorFeatures) + } + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesSettingsActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesSettingsActivity.kt new file mode 100644 index 0000000000..03d065c982 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesSettingsActivity.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.debug.features + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.extensions.cleanup +import im.vector.app.core.extensions.configureWith +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.features.DefaultVectorFeatures +import im.vector.app.features.themes.ActivityOtherThemes +import im.vector.app.features.themes.ThemeUtils +import javax.inject.Inject + +@AndroidEntryPoint +class DebugFeaturesSettingsActivity : AppCompatActivity() { + + @Inject lateinit var debugFeatures: DebugVectorFeatures + @Inject lateinit var defaultFeatures: DefaultVectorFeatures + + private lateinit var views: FragmentGenericRecyclerBinding + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + ThemeUtils.setActivityTheme(this, ActivityOtherThemes.Default) + views = FragmentGenericRecyclerBinding.inflate(layoutInflater) + setContentView(views.root) + val controller = FeaturesController(object : EnumFeatureItem.Listener { + + @Suppress("UNCHECKED_CAST") + override fun > onOptionSelected(option: Any?, feature: Feature.EnumFeature) { + debugFeatures.overrideEnum(option as? T, feature.type) + } + }) + views.genericRecyclerView.configureWith(controller) + controller.setData(createState()) + } + + private fun createState(): FeaturesState { + return FeaturesState(listOf( + createEnumFeature( + label = "Login version", + selection = debugFeatures.loginVersion(), + default = defaultFeatures.loginVersion() + ) + )) + } + + private inline fun > createEnumFeature(label: String, selection: T, default: T): Feature { + return Feature.EnumFeature( + label = label, + selection = selection.takeIf { debugFeatures.hasEnumOverride(T::class) }, + default = default, + options = enumValues().toList(), + type = T::class + ) + } + + override fun onDestroy() { + views.genericRecyclerView.cleanup() + super.onDestroy() + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt new file mode 100644 index 0000000000..822adcb61f --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.debug.features + +import android.content.Context +import android.content.SharedPreferences +import im.vector.app.features.DefaultVectorFeatures +import im.vector.app.features.VectorFeatures +import kotlin.reflect.KClass + +class DebugVectorFeatures( + context: Context, + private val vectorFeatures: DefaultVectorFeatures +) : VectorFeatures { + + private val featurePrefs = context.getSharedPreferences("debug-features", Context.MODE_PRIVATE) + + override fun loginVersion(): VectorFeatures.LoginVersion { + return featurePrefs.readEnum() ?: vectorFeatures.loginVersion() + } + + fun > hasEnumOverride(type: KClass): Boolean { + return featurePrefs.containsEnum(type) + } + + fun > overrideEnum(value: T?, type: KClass) { + if (value == null) { + featurePrefs.removeEnum(type) + } else { + featurePrefs.putEnum(value, type) + } + } +} + +private fun > SharedPreferences.removeEnum(type: KClass) { + edit().remove("enum-${type.simpleName}").apply() +} + +private fun > SharedPreferences.containsEnum(type: KClass): Boolean { + return contains("enum-${type.simpleName}") +} + +private inline fun > SharedPreferences.readEnum(): T? { + val value = T::class.simpleName + return getString("enum-$value", null)?.let { enumValueOf(it) } +} + +private fun > SharedPreferences.putEnum(value: T, type: KClass) { + edit() + .putString("enum-${type.simpleName}", value.name) + .apply() +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/EnumFeatureItem.kt b/vector/src/debug/java/im/vector/app/features/debug/features/EnumFeatureItem.kt new file mode 100644 index 0000000000..1e2ec56ea8 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/features/EnumFeatureItem.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.debug.features + +import android.view.View +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.Spinner +import android.widget.TextView +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel + +@EpoxyModelClass(layout = im.vector.app.R.layout.item_feature) +abstract class EnumFeatureItem : VectorEpoxyModel() { + + @EpoxyAttribute + lateinit var feature: Feature.EnumFeature<*> + + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) + var listener: Listener? = null + + override fun bind(holder: Holder) { + super.bind(holder) + holder.label.text = feature.label + + holder.optionsSpinner.apply { + val arrayAdapter = ArrayAdapter(context, android.R.layout.simple_spinner_dropdown_item) + arrayAdapter.add("DEFAULT - ${feature.default.name}") + arrayAdapter.addAll(feature.options.map { it.name }) + adapter = arrayAdapter + + feature.selection?.let { + setSelection(feature.options.indexOf(it) + 1, false) + } + + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + when (position) { + 0 -> listener?.onOptionSelected(option = null, feature) + else -> { + val option: Any = feature.options[position - 1] + listener?.onOptionSelected(option, feature) + } + } + } + + override fun onNothingSelected(parent: AdapterView<*>?) { + // do nothing + } + } + } + } + + class Holder : VectorEpoxyHolder() { + val label by bind(im.vector.app.R.id.feature_label) + val optionsSpinner by bind(im.vector.app.R.id.feature_options) + } + + interface Listener { + fun > onOptionSelected(option: Any?, feature: Feature.EnumFeature) + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/FeaturesController.kt b/vector/src/debug/java/im/vector/app/features/debug/features/FeaturesController.kt new file mode 100644 index 0000000000..50897e6bba --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/features/FeaturesController.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.debug.features + +import com.airbnb.epoxy.TypedEpoxyController +import kotlin.reflect.KClass + +data class FeaturesState( + val features: List +) + +sealed interface Feature { + + data class EnumFeature>( + val label: String, + val selection: T?, + val default: T, + val options: List, + val type: KClass + ) : Feature +} + +class FeaturesController(private val listener: EnumFeatureItem.Listener) : TypedEpoxyController() { + + override fun buildModels(data: FeaturesState?) { + if (data == null) return + + data.features.forEachIndexed { index, feature -> + when (feature) { + is Feature.EnumFeature<*> -> enumFeatureItem { + id(index) + feature(feature) + listener(this@FeaturesController.listener) + } + } + } + } +} diff --git a/vector/src/debug/res/layout/activity_debug_menu.xml b/vector/src/debug/res/layout/activity_debug_menu.xml index ac70e4ef0e..7aa69becde 100644 --- a/vector/src/debug/res/layout/activity_debug_menu.xml +++ b/vector/src/debug/res/layout/activity_debug_menu.xml @@ -20,6 +20,12 @@ android:padding="@dimen/layout_horizontal_margin" android:showDividers="middle"> +