From f0165f69d377df31ae8278c63a784eb43e27f052 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Jul 2022 13:21:00 +0000 Subject: [PATCH 001/191] Bump realm-gradle-plugin from 10.11.0 to 10.11.1 Bumps [realm-gradle-plugin](https://github.com/realm/realm-java) from 10.11.0 to 10.11.1. - [Release notes](https://github.com/realm/realm-java/releases) - [Changelog](https://github.com/realm/realm-java/blob/v10.11.1/CHANGELOG.md) - [Commits](https://github.com/realm/realm-java/compare/v10.11.0...v10.11.1) --- updated-dependencies: - dependency-name: io.realm:realm-gradle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- matrix-sdk-android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index ee58db748c..7260d30f5d 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -17,7 +17,7 @@ buildscript { } } dependencies { - classpath "io.realm:realm-gradle-plugin:10.11.0" + classpath "io.realm:realm-gradle-plugin:10.11.1" } } From d49f10433296c8dc97a1bc5cb4a0a6e0e660e8c6 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Thu, 28 Jul 2022 15:09:57 +0200 Subject: [PATCH 002/191] Adds fab buttons --- .../src/main/res/values/styles_buttons.xml | 4 ++ .../home/room/list/RoomListFragment.kt | 14 +++--- vector/src/main/res/drawable/ic_new_chat.xml | 10 +++++ .../src/main/res/drawable/ic_open_spaces.xml | 14 ++++++ .../main/res/layout/fragment_room_list.xml | 44 +++++++++++++++++++ vector/src/main/res/values/strings.xml | 1 + 6 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 vector/src/main/res/drawable/ic_new_chat.xml create mode 100644 vector/src/main/res/drawable/ic_open_spaces.xml diff --git a/library/ui-styles/src/main/res/values/styles_buttons.xml b/library/ui-styles/src/main/res/values/styles_buttons.xml index c8dcacb8ed..702f427cc0 100644 --- a/library/ui-styles/src/main/res/values/styles_buttons.xml +++ b/library/ui-styles/src/main/res/values/styles_buttons.xml @@ -65,4 +65,8 @@ ?colorOnPrimary + + 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 c25fe546c3..80f545b166 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 @@ -211,12 +211,14 @@ class RoomListFragment @Inject constructor( } private fun setupCreateRoomButton() { - when (roomListParams.displayMode) { - RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.isVisible = true - RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.isVisible = true - RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.isVisible = true - RoomListDisplayMode.FILTERED -> Unit // No button in this mode - } + // TODO: Uncomment +// when (roomListParams.displayMode) { +// RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.isVisible = true +// RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.isVisible = false +// RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.isVisible = true +// RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.isVisible = true +// RoomListDisplayMode.FILTERED -> Unit // No button in this mode +// } views.createChatRoomButton.debouncedClicks { fabCreateDirectChat() diff --git a/vector/src/main/res/drawable/ic_new_chat.xml b/vector/src/main/res/drawable/ic_new_chat.xml new file mode 100644 index 0000000000..ec3ef46fa4 --- /dev/null +++ b/vector/src/main/res/drawable/ic_new_chat.xml @@ -0,0 +1,10 @@ + + + diff --git a/vector/src/main/res/drawable/ic_open_spaces.xml b/vector/src/main/res/drawable/ic_open_spaces.xml new file mode 100644 index 0000000000..180f71f1cd --- /dev/null +++ b/vector/src/main/res/drawable/ic_open_spaces.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/vector/src/main/res/layout/fragment_room_list.xml b/vector/src/main/res/layout/fragment_room_list.xml index a8eec6ff3a..97e2725a1f 100644 --- a/vector/src/main/res/layout/fragment_room_list.xml +++ b/vector/src/main/res/layout/fragment_room_list.xml @@ -55,4 +55,48 @@ tools:layout_marginEnd="144dp" tools:visibility="visible" /> + + + + + + + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 770df1f770..4157f173c2 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1810,6 +1810,7 @@ Open the create room menu Close the create room menu… Create a new direct conversation + Create a new conversation or room Create a new room Close keys backup banner Jump to bottom From 8e7e320e40448074d1f36d09005187be2811a9aa Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 29 Jul 2022 15:28:55 +0200 Subject: [PATCH 003/191] Finalises new layout FABs --- .../home/room/list/RoomListFragment.kt | 14 +++-- .../room/list/home/HomeRoomListFragment.kt | 15 ++++++ .../main/res/layout/fragment_room_list.xml | 51 +++++++++---------- 3 files changed, 46 insertions(+), 34 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 80f545b166..c25fe546c3 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 @@ -211,14 +211,12 @@ class RoomListFragment @Inject constructor( } private fun setupCreateRoomButton() { - // TODO: Uncomment -// when (roomListParams.displayMode) { -// RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.isVisible = true -// RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.isVisible = false -// RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.isVisible = true -// RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.isVisible = true -// RoomListDisplayMode.FILTERED -> Unit // No button in this mode -// } + when (roomListParams.displayMode) { + RoomListDisplayMode.NOTIFICATIONS -> views.createChatFabMenu.isVisible = true + RoomListDisplayMode.PEOPLE -> views.createChatRoomButton.isVisible = true + RoomListDisplayMode.ROOMS -> views.createGroupRoomButton.isVisible = true + RoomListDisplayMode.FILTERED -> Unit // No button in this mode + } views.createChatRoomButton.debouncedClicks { fabCreateDirectChat() diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt index f0eb027785..cc211a31fa 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt @@ -20,6 +20,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.LinearLayoutManager @@ -90,6 +91,7 @@ class HomeRoomListFragment @Inject constructor( } setupRecyclerView() + setupFabs() } private fun setupRecyclerView() { @@ -108,6 +110,19 @@ class HomeRoomListFragment @Inject constructor( views.roomListView.adapter = concatAdapter } + private fun setupFabs() { + views.newLayoutCreateChatButton.isVisible = true + views.newLayoutOpenSpacesButton.isVisible = true + + views.newLayoutCreateChatButton.setOnClickListener { + // Click action for create chat modal goes here + } + + views.newLayoutOpenSpacesButton.setOnClickListener { + // Click action for open spaces modal goes here + } + } + override fun invalidate() = withState(roomListViewModel) { state -> views.stateView.state = state.state } diff --git a/vector/src/main/res/layout/fragment_room_list.xml b/vector/src/main/res/layout/fragment_room_list.xml index 97e2725a1f..631602bb14 100644 --- a/vector/src/main/res/layout/fragment_room_list.xml +++ b/vector/src/main/res/layout/fragment_room_list.xml @@ -56,46 +56,45 @@ tools:visibility="visible" /> - - + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="bottom|end"> + tools:visibility="visible" + tools:targetApi="lollipop_mr1" /> + + + From 406a67827c35ef53c9d1004e1d754f0d14d76b6f Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 29 Jul 2022 15:48:21 +0200 Subject: [PATCH 004/191] Adds scroll behaviour to FABs --- .../room/list/home/HomeRoomListFragment.kt | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt index cc211a31fa..e7882ff36f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt @@ -20,10 +20,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import com.airbnb.epoxy.EpoxyControllerAdapter import com.airbnb.epoxy.OnModelBuildFinishedListener import com.airbnb.mvrx.fragmentViewModel @@ -72,7 +72,7 @@ class HomeRoomListFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - sharedActionViewModel = activityViewModelProvider.get(RoomListQuickActionsSharedActionViewModel::class.java) + sharedActionViewModel = activityViewModelProvider[RoomListQuickActionsSharedActionViewModel::class.java] sharedActionViewModel .stream() .onEach { handleQuickActions(it) } @@ -111,8 +111,7 @@ class HomeRoomListFragment @Inject constructor( } private fun setupFabs() { - views.newLayoutCreateChatButton.isVisible = true - views.newLayoutOpenSpacesButton.isVisible = true + showFABs() views.newLayoutCreateChatButton.setOnClickListener { // Click action for create chat modal goes here @@ -121,6 +120,29 @@ class HomeRoomListFragment @Inject constructor( views.newLayoutOpenSpacesButton.setOnClickListener { // Click action for open spaces modal goes here } + + // Hide FABs when list is scrolling + views.roomListView.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + views.createChatFabMenu.handler.removeCallbacksAndMessages(null) + + when (newState) { + RecyclerView.SCROLL_STATE_IDLE -> views.createChatFabMenu.postDelayed(::showFABs, 250) + RecyclerView.SCROLL_STATE_DRAGGING, + RecyclerView.SCROLL_STATE_SETTLING -> hideFABs() + } + } + }) + } + + private fun showFABs() { + views.newLayoutCreateChatButton.show() + views.newLayoutOpenSpacesButton.show() + } + + private fun hideFABs() { + views.newLayoutCreateChatButton.hide() + views.newLayoutOpenSpacesButton.hide() } override fun invalidate() = withState(roomListViewModel) { state -> From d116d980809c1dd31c25d252a567502b428fd1d4 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 29 Jul 2022 15:48:58 +0200 Subject: [PATCH 005/191] Adds changelog file --- changelog.d/6693.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6693.feature diff --git a/changelog.d/6693.feature b/changelog.d/6693.feature new file mode 100644 index 0000000000..5e905766a9 --- /dev/null +++ b/changelog.d/6693.feature @@ -0,0 +1 @@ +Adds New App Layout FABs (hidden behind feature flag) From 927b51413cfc216b537d90446c65d526fb38a36c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Aug 2022 11:57:41 +0000 Subject: [PATCH 006/191] Bump com.autonomousapps.dependency-analysis from 1.11.2 to 1.12.0 Bumps com.autonomousapps.dependency-analysis from 1.11.2 to 1.12.0. --- updated-dependencies: - dependency-name: com.autonomousapps.dependency-analysis dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index afe51cc734..115b21a23d 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ plugins { id "io.gitlab.arturbosch.detekt" version "1.21.0" // Dependency Analysis - id 'com.autonomousapps.dependency-analysis' version "1.11.2" + id 'com.autonomousapps.dependency-analysis' version "1.12.0" } // https://github.com/jeremylong/DependencyCheck From b0a9b482e78ec61514f20ad3d9e352a3517d0789 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Tue, 2 Aug 2022 15:18:45 +0200 Subject: [PATCH 007/191] Adds issue numbers to unimplemented FAB clicks --- .../app/features/home/room/list/home/HomeRoomListFragment.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt index e7882ff36f..deaebac4f3 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt @@ -114,11 +114,11 @@ class HomeRoomListFragment @Inject constructor( showFABs() views.newLayoutCreateChatButton.setOnClickListener { - // Click action for create chat modal goes here + // Click action for create chat modal goes here (Issue #6717) } views.newLayoutOpenSpacesButton.setOnClickListener { - // Click action for open spaces modal goes here + // Click action for open spaces modal goes here (Issue #6499) } // Hide FABs when list is scrolling From ab4eda18bfc1c489f82613ada40666870bf85be3 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Tue, 2 Aug 2022 17:44:27 +0200 Subject: [PATCH 008/191] Adds SpacesBottomSheet --- .../room/list/home/HomeRoomListFragment.kt | 2 + .../app/features/spaces/SpacesBottomSheet.kt | 46 +++++++++++++++++++ .../layout/fragment_spaces_bottom_sheet.xml | 11 +++++ 3 files changed, 59 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/features/spaces/SpacesBottomSheet.kt create mode 100644 vector/src/main/res/layout/fragment_spaces_bottom_sheet.xml diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt index e7882ff36f..68143ddc7d 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt @@ -44,6 +44,7 @@ import im.vector.app.features.home.room.list.RoomSummaryPagedController 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 im.vector.app.features.spaces.SpacesBottomSheet import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -119,6 +120,7 @@ class HomeRoomListFragment @Inject constructor( views.newLayoutOpenSpacesButton.setOnClickListener { // Click action for open spaces modal goes here + SpacesBottomSheet().show(requireActivity().supportFragmentManager, SpacesBottomSheet.TAG) } // Hide FABs when list is scrolling diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpacesBottomSheet.kt b/vector/src/main/java/im/vector/app/features/spaces/SpacesBottomSheet.kt new file mode 100644 index 0000000000..c50e4b6387 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/spaces/SpacesBottomSheet.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 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.spaces + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import im.vector.app.R +import im.vector.app.core.extensions.replaceChildFragment +import im.vector.app.databinding.FragmentSpacesBottomSheetBinding + +class SpacesBottomSheet : BottomSheetDialogFragment() { + + private lateinit var binding: FragmentSpacesBottomSheetBinding + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + binding = FragmentSpacesBottomSheetBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + if (savedInstanceState == null) { + replaceChildFragment(R.id.space_list, SpaceListFragment::class.java) + } + } + + companion object { + const val TAG = "SpacesBottomSheet" + } +} diff --git a/vector/src/main/res/layout/fragment_spaces_bottom_sheet.xml b/vector/src/main/res/layout/fragment_spaces_bottom_sheet.xml new file mode 100644 index 0000000000..27324c852f --- /dev/null +++ b/vector/src/main/res/layout/fragment_spaces_bottom_sheet.xml @@ -0,0 +1,11 @@ + + + + + + From aa24debd870be2e2bc78c49876dc84a8a1531bea Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Tue, 2 Aug 2022 22:49:58 +0200 Subject: [PATCH 009/191] Adds new space list controller --- .../grouplist/HomeSpaceSummaryItem.kt | 1 + .../features/home/NewHomeDetailFragment.kt | 17 +-- .../app/features/spaces/NewSpaceAddItem.kt | 38 ++++++ .../features/spaces/NewSpaceListHeaderItem.kt | 27 +++++ .../spaces/NewSpaceSummaryController.kt | 111 ++++++++++++++++++ .../features/spaces/NewSpaceSummaryItem.kt | 71 +++++++++++ .../app/features/spaces/SpaceListFragment.kt | 48 ++++++-- vector/src/main/res/drawable/ic_plus.xml | 11 ++ vector/src/main/res/layout/item_new_space.xml | 77 ++++++++++++ .../main/res/layout/item_new_space_add.xml | 54 +++++++++ .../res/layout/item_new_space_list_header.xml | 13 ++ 11 files changed, 447 insertions(+), 21 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/spaces/NewSpaceAddItem.kt create mode 100644 vector/src/main/java/im/vector/app/features/spaces/NewSpaceListHeaderItem.kt create mode 100644 vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt create mode 100644 vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryItem.kt create mode 100644 vector/src/main/res/drawable/ic_plus.xml create mode 100644 vector/src/main/res/layout/item_new_space.xml create mode 100644 vector/src/main/res/layout/item_new_space_add.xml create mode 100644 vector/src/main/res/layout/item_new_space_list_header.xml diff --git a/vector/src/main/java/im/vector/app/features/grouplist/HomeSpaceSummaryItem.kt b/vector/src/main/java/im/vector/app/features/grouplist/HomeSpaceSummaryItem.kt index 816b9acb24..8ca217636a 100644 --- a/vector/src/main/java/im/vector/app/features/grouplist/HomeSpaceSummaryItem.kt +++ b/vector/src/main/java/im/vector/app/features/grouplist/HomeSpaceSummaryItem.kt @@ -37,6 +37,7 @@ import im.vector.app.features.themes.ThemeUtils @EpoxyModelClass abstract class HomeSpaceSummaryItem : VectorEpoxyModel(R.layout.item_space) { + @EpoxyAttribute var text: String = "" @EpoxyAttribute var selected: Boolean = false @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null @EpoxyAttribute var countState: UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false) diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index 36372fc73a..55fb3daafa 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -28,8 +28,8 @@ import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import com.google.android.material.badge.BadgeDrawable -import im.vector.app.AppStateHandler import im.vector.app.R +import im.vector.app.SpaceStateHandler import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.extensions.toMvRxBundle import im.vector.app.core.platform.OnBackPressed @@ -47,6 +47,7 @@ import im.vector.app.features.call.dialpad.DialPadFragment import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.home.room.list.RoomListFragment import im.vector.app.features.home.room.list.RoomListParams +import im.vector.app.features.home.room.list.home.HomeRoomListFragment import im.vector.app.features.popup.PopupAlertManager import im.vector.app.features.popup.VerificationVectorAlert import im.vector.app.features.settings.VectorLocale @@ -69,7 +70,7 @@ class NewHomeDetailFragment @Inject constructor( private val alertManager: PopupAlertManager, private val callManager: WebRtcCallManager, private val vectorPreferences: VectorPreferences, - private val appStateHandler: AppStateHandler, + private val spaceStateHandler: SpaceStateHandler, private val session: Session, ) : VectorBaseFragment(), KeysBackupBanner.Delegate, @@ -178,13 +179,13 @@ class NewHomeDetailFragment @Inject constructor( } private fun navigateBack() { - val previousSpaceId = appStateHandler.getSpaceBackstack().removeLastOrNull() - val parentSpaceId = appStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull() + val previousSpaceId = spaceStateHandler.getSpaceBackstack().removeLastOrNull() + val parentSpaceId = spaceStateHandler.getCurrentSpace()?.flattenParentIds?.lastOrNull() setCurrentSpace(previousSpaceId ?: parentSpaceId) } private fun setCurrentSpace(spaceId: String?) { - appStateHandler.setCurrentSpace(spaceId, isForwardNavigation = false) + spaceStateHandler.setCurrentSpace(spaceId, isForwardNavigation = false) sharedActionViewModel.post(HomeActivitySharedAction.OnCloseSpace) } @@ -207,7 +208,7 @@ class NewHomeDetailFragment @Inject constructor( } private fun refreshSpaceState() { - appStateHandler.getCurrentSpace()?.let { + spaceStateHandler.getCurrentSpace()?.let { onSpaceChange(it) } } @@ -340,7 +341,7 @@ class NewHomeDetailFragment @Inject constructor( when (tab) { is HomeTab.RoomList -> { val params = RoomListParams(tab.displayMode) - add(R.id.roomListContainer, RoomListFragment::class.java, params.toMvRxBundle(), fragmentTag) + add(R.id.roomListContainer, HomeRoomListFragment::class.java, params.toMvRxBundle(), fragmentTag) } is HomeTab.DialPad -> { add(R.id.roomListContainer, createDialPadFragment(), fragmentTag) @@ -453,7 +454,7 @@ class NewHomeDetailFragment @Inject constructor( return this } - override fun onBackPressed(toolbarButton: Boolean) = if (appStateHandler.getCurrentSpace() != null) { + override fun onBackPressed(toolbarButton: Boolean) = if (spaceStateHandler.getCurrentSpace() != null) { navigateBack() true } else { diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceAddItem.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceAddItem.kt new file mode 100644 index 0000000000..d90cb5bc67 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceAddItem.kt @@ -0,0 +1,38 @@ +/* + * 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.spaces + +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.R +import im.vector.app.core.epoxy.ClickListener +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel +import im.vector.app.core.epoxy.onClick + +@EpoxyModelClass +abstract class NewSpaceAddItem : VectorEpoxyModel(R.layout.item_new_space_add) { + + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null + + override fun bind(holder: Holder) { + super.bind(holder) + holder.view.onClick(listener) + } + + class Holder : VectorEpoxyHolder() +} diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceListHeaderItem.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceListHeaderItem.kt new file mode 100644 index 0000000000..8fc53f07d4 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceListHeaderItem.kt @@ -0,0 +1,27 @@ +/* + * 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.spaces + +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.R +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel + +@EpoxyModelClass +abstract class NewSpaceListHeaderItem : VectorEpoxyModel(R.layout.item_new_space_list_header) { + class Holder : VectorEpoxyHolder() +} diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt new file mode 100644 index 0000000000..80a8acb1bb --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt @@ -0,0 +1,111 @@ +/* + * 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.spaces + +import com.airbnb.epoxy.EpoxyController +import im.vector.app.R +import im.vector.app.core.resources.StringProvider +import im.vector.app.features.grouplist.homeSpaceSummaryItem +import im.vector.app.features.home.AvatarRenderer +import im.vector.app.features.home.room.list.UnreadCounterBadgeView +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.session.room.model.Membership +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo +import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount +import org.matrix.android.sdk.api.util.toMatrixItem +import javax.inject.Inject + +class NewSpaceSummaryController @Inject constructor( + private val avatarRenderer: AvatarRenderer, + private val stringProvider: StringProvider, +) : EpoxyController() { + + var callback: Callback? = null + private var viewState: SpaceListViewState? = null + + private val subSpaceComparator: Comparator = compareBy { it.order }.thenBy { it.childRoomId } + + fun update(viewState: SpaceListViewState) { + this.viewState = viewState + requestModelBuild() + } + + override fun buildModels() { + val nonNullViewState = viewState ?: return + buildGroupModels( + nonNullViewState.selectedSpace, + nonNullViewState.rootSpacesOrdered, + nonNullViewState.homeAggregateCount + ) + } + + private fun buildGroupModels( + selectedSpace: RoomSummary?, + rootSpaces: List?, + homeCount: RoomAggregateNotificationCount + ) { + val host = this + + newSpaceListHeaderItem { + id("space_list_header") + } + + homeSpaceSummaryItem { + id("space_home") + text(this@NewSpaceSummaryController.stringProvider.getString(R.string.all_chats)) + selected(selectedSpace == null) + countState(UnreadCounterBadgeView.State(homeCount.totalCount, homeCount.isHighlight)) + listener { host.callback?.onSpaceSelected(null) } + } + + rootSpaces + ?.filter { it.membership != Membership.INVITE } + ?.forEach { roomSummary -> + val isSelected = roomSummary.roomId == selectedSpace?.roomId + + newSpaceSummaryItem { + avatarRenderer(host.avatarRenderer) + id(roomSummary.roomId) + matrixItem(roomSummary.toMatrixItem()) + selected(isSelected) + canDrag(true) + onMore { host.callback?.onSpaceSettings(roomSummary) } + listener { host.callback?.onSpaceSelected(roomSummary) } + countState( + UnreadCounterBadgeView.State( + roomSummary.notificationCount, + roomSummary.highlightCount > 0 + ) + ) + } + } + + newSpaceAddItem { + id("create") + listener { host.callback?.onAddSpaceSelected() } + } + } + + interface Callback { + fun onSpaceSelected(spaceSummary: RoomSummary?) + fun onSpaceInviteSelected(spaceSummary: RoomSummary) + fun onSpaceSettings(spaceSummary: RoomSummary) + fun onAddSpaceSelected() + fun sendFeedBack() + } +} diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryItem.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryItem.kt new file mode 100644 index 0000000000..eecb02b320 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryItem.kt @@ -0,0 +1,71 @@ +/* + * 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.spaces + +import android.widget.ImageView +import android.widget.TextView +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.R +import im.vector.app.core.epoxy.ClickListener +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel +import im.vector.app.core.epoxy.onClick +import im.vector.app.core.platform.CheckableConstraintLayout +import im.vector.app.features.home.AvatarRenderer +import im.vector.app.features.home.room.list.UnreadCounterBadgeView +import org.matrix.android.sdk.api.util.MatrixItem + +@EpoxyModelClass +abstract class NewSpaceSummaryItem : VectorEpoxyModel(R.layout.item_new_space) { + + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) lateinit var avatarRenderer: AvatarRenderer + @EpoxyAttribute lateinit var matrixItem: MatrixItem + @EpoxyAttribute var selected: Boolean = false + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var onMore: ClickListener? = null + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var toggleExpand: ClickListener? = null + @EpoxyAttribute var expanded: Boolean = false + @EpoxyAttribute var hasChildren: Boolean = false + @EpoxyAttribute var indent: Int = 0 + @EpoxyAttribute var countState: UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false) + @EpoxyAttribute var description: String? = null + @EpoxyAttribute var showSeparator: Boolean = false + @EpoxyAttribute var canDrag: Boolean = true + + override fun bind(holder: Holder) { + super.bind(holder) + holder.rootView.onClick(listener) + holder.groupNameView.text = matrixItem.displayName + holder.rootView.isChecked = selected + + avatarRenderer.render(matrixItem, holder.avatarImageView) + holder.counterBadgeView.render(countState) + } + + override fun unbind(holder: Holder) { + avatarRenderer.clear(holder.avatarImageView) + super.unbind(holder) + } + + class Holder : VectorEpoxyHolder() { + val rootView by bind(R.id.root) + val avatarImageView by bind(R.id.avatar) + val groupNameView by bind(R.id.name) + val counterBadgeView by bind(R.id.unread_counter) + } +} diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt index b358a8c1a6..bf76c2eecd 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt @@ -32,6 +32,7 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentSpaceListBinding +import im.vector.app.features.VectorFeatures import im.vector.app.features.home.HomeActivitySharedAction import im.vector.app.features.home.HomeSharedActionViewModel import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -42,8 +43,10 @@ import javax.inject.Inject * is displaying the space hierarchy, with some actions on Spaces. */ class SpaceListFragment @Inject constructor( - private val spaceController: SpaceSummaryController -) : VectorBaseFragment(), SpaceSummaryController.Callback { + private val spaceController: SpaceSummaryController, + private val newSpaceController: NewSpaceSummaryController, + private val vectorFeatures: VectorFeatures, +) : VectorBaseFragment(), SpaceSummaryController.Callback, NewSpaceSummaryController.Callback { private lateinit var sharedActionViewModel: HomeSharedActionViewModel private val viewModel: SpaceListViewModel by fragmentViewModel() @@ -54,10 +57,24 @@ class SpaceListFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java) - spaceController.callback = this + sharedActionViewModel = activityViewModelProvider[HomeSharedActionViewModel::class.java] views.stateView.contentView = views.groupListView - views.groupListView.configureWith(spaceController) + setupSpaceController() + enableDragAndDrop() + observeViewEvents() + } + + private fun setupSpaceController() { + if (vectorFeatures.isNewAppLayoutEnabled()) { + newSpaceController.callback = this + views.groupListView.configureWith(newSpaceController) + } else { + spaceController.callback = this + views.groupListView.configureWith(spaceController) + } + } + + private fun enableDragAndDrop() { EpoxyTouchHelper.initDragging(spaceController) .withRecyclerView(views.groupListView) .forVerticalList() @@ -100,14 +117,14 @@ class SpaceListFragment @Inject constructor( return model?.canDrag == true } }) + } - viewModel.observeViewEvents { - when (it) { - is SpaceListViewEvents.OpenSpaceSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpacePreview(it.id)) - is SpaceListViewEvents.AddSpace -> sharedActionViewModel.post(HomeActivitySharedAction.AddSpace) - is SpaceListViewEvents.OpenSpaceInvite -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpaceInvite(it.id)) - SpaceListViewEvents.CloseDrawer -> sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer) - } + private fun observeViewEvents() = viewModel.observeViewEvents { + when (it) { + is SpaceListViewEvents.OpenSpaceSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpacePreview(it.id)) + is SpaceListViewEvents.AddSpace -> sharedActionViewModel.post(HomeActivitySharedAction.AddSpace) + is SpaceListViewEvents.OpenSpaceInvite -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpaceInvite(it.id)) + SpaceListViewEvents.CloseDrawer -> sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer) } } @@ -124,7 +141,12 @@ class SpaceListFragment @Inject constructor( is Success -> views.stateView.state = StateView.State.Content else -> Unit } - spaceController.update(state) + + if (vectorFeatures.isNewAppLayoutEnabled()) { + newSpaceController.update(state) + } else { + spaceController.update(state) + } } override fun onSpaceSelected(spaceSummary: RoomSummary?) { diff --git a/vector/src/main/res/drawable/ic_plus.xml b/vector/src/main/res/drawable/ic_plus.xml new file mode 100644 index 0000000000..25a611472b --- /dev/null +++ b/vector/src/main/res/drawable/ic_plus.xml @@ -0,0 +1,11 @@ + + + + diff --git a/vector/src/main/res/layout/item_new_space.xml b/vector/src/main/res/layout/item_new_space.xml new file mode 100644 index 0000000000..367d69ce69 --- /dev/null +++ b/vector/src/main/res/layout/item_new_space.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + diff --git a/vector/src/main/res/layout/item_new_space_add.xml b/vector/src/main/res/layout/item_new_space_add.xml new file mode 100644 index 0000000000..1033d3c6a0 --- /dev/null +++ b/vector/src/main/res/layout/item_new_space_add.xml @@ -0,0 +1,54 @@ + + + + + + + + + + diff --git a/vector/src/main/res/layout/item_new_space_list_header.xml b/vector/src/main/res/layout/item_new_space_list_header.xml new file mode 100644 index 0000000000..51edd8de59 --- /dev/null +++ b/vector/src/main/res/layout/item_new_space_list_header.xml @@ -0,0 +1,13 @@ + + From 5d183654b1992f6ab53a9f76bf3d94e8c686a4f6 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Wed, 3 Aug 2022 21:54:05 +0200 Subject: [PATCH 010/191] Fixes bug where bottom sheet sometimes renders with the wrong height --- .../room/list/home/HomeRoomListFragment.kt | 4 +- .../app/features/spaces/SpaceListFragment.kt | 2 +- .../app/features/spaces/SpacesBottomSheet.kt | 5 +- .../main/res/layout/fragment_room_list.xml | 166 +++++++++--------- 4 files changed, 91 insertions(+), 86 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt index 68143ddc7d..fae6ddb0c8 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt @@ -64,6 +64,8 @@ class HomeRoomListFragment @Inject constructor( private var concatAdapter = ConcatAdapter() private var modelBuildListener: OnModelBuildFinishedListener? = null + private val spacesBottomSheet = SpacesBottomSheet() + private lateinit var stateRestorer: LayoutManagerStateRestorer override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomListBinding { @@ -120,7 +122,7 @@ class HomeRoomListFragment @Inject constructor( views.newLayoutOpenSpacesButton.setOnClickListener { // Click action for open spaces modal goes here - SpacesBottomSheet().show(requireActivity().supportFragmentManager, SpacesBottomSheet.TAG) + spacesBottomSheet.show(requireActivity().supportFragmentManager, SpacesBottomSheet.TAG) } // Hide FABs when list is scrolling diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt index bf76c2eecd..51fbaad757 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt @@ -143,7 +143,7 @@ class SpaceListFragment @Inject constructor( } if (vectorFeatures.isNewAppLayoutEnabled()) { - newSpaceController.update(state) + newSpaceController.update(state).also { onUpdate?.invoke() } } else { spaceController.update(state) } diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpacesBottomSheet.kt b/vector/src/main/java/im/vector/app/features/spaces/SpacesBottomSheet.kt index c50e4b6387..757e39b85a 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpacesBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpacesBottomSheet.kt @@ -31,13 +31,10 @@ class SpacesBottomSheet : BottomSheetDialogFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { binding = FragmentSpacesBottomSheetBinding.inflate(inflater, container, false) - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { if (savedInstanceState == null) { replaceChildFragment(R.id.space_list, SpaceListFragment::class.java) } + return binding.root } companion object { diff --git a/vector/src/main/res/layout/fragment_room_list.xml b/vector/src/main/res/layout/fragment_room_list.xml index 631602bb14..6107482f72 100644 --- a/vector/src/main/res/layout/fragment_room_list.xml +++ b/vector/src/main/res/layout/fragment_room_list.xml @@ -1,101 +1,107 @@ - + android:layout_height="match_parent"> - + android:background="?android:colorBackground"> - + - - - - - - - - + app:layoutDescription="@xml/motion_scene_notifs_fab_menu" + tools:showPaths="true" + tools:visibility="visible" /> + + + app:maxImageSize="32dp" + tools:layout_marginEnd="144dp" + tools:visibility="visible" /> - + - + + + + + + + + + + From b4ed380caf73d448f98ca3a7b55f0f4287bcd014 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Wed, 3 Aug 2022 22:49:21 +0200 Subject: [PATCH 011/191] Finalises home and add bottom sheet buttons --- .../grouplist/NewHomeSpaceSummaryItem.kt | 69 +++++++++++++++++++ .../app/features/spaces/NewSpaceAddItem.kt | 9 ++- .../spaces/NewSpaceSummaryController.kt | 3 +- .../app/features/spaces/SpaceListFragment.kt | 2 +- .../drawable/new_space_home_background.xml | 11 +++ .../res/drawable/space_home_background.xml | 2 +- .../main/res/layout/item_new_space_add.xml | 4 +- .../res/layout/item_new_space_list_header.xml | 1 + 8 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/grouplist/NewHomeSpaceSummaryItem.kt create mode 100644 vector/src/main/res/drawable/new_space_home_background.xml diff --git a/vector/src/main/java/im/vector/app/features/grouplist/NewHomeSpaceSummaryItem.kt b/vector/src/main/java/im/vector/app/features/grouplist/NewHomeSpaceSummaryItem.kt new file mode 100644 index 0000000000..1f967db7ad --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/grouplist/NewHomeSpaceSummaryItem.kt @@ -0,0 +1,69 @@ +/* + * 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.grouplist + +import android.content.res.ColorStateList +import android.widget.ImageView +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.core.graphics.ColorUtils +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.R +import im.vector.app.core.epoxy.ClickListener +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel +import im.vector.app.core.epoxy.onClick +import im.vector.app.core.platform.CheckableConstraintLayout +import im.vector.app.features.home.room.list.UnreadCounterBadgeView +import im.vector.app.features.themes.ThemeUtils + +@EpoxyModelClass +abstract class NewHomeSpaceSummaryItem : VectorEpoxyModel(R.layout.item_new_space) { + + @EpoxyAttribute var text: String = "" + @EpoxyAttribute var selected: Boolean = false + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) var listener: ClickListener? = null + @EpoxyAttribute var countState: UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false) + @EpoxyAttribute var showSeparator: Boolean = false + + override fun getViewType() = R.id.space_item_home + + override fun bind(holder: Holder) { + super.bind(holder) + holder.root.onClick(listener) + holder.name.text = holder.view.context.getString(R.string.all_chats) + holder.root.isChecked = selected + holder.root.context.resources + holder.avatar.background = ContextCompat.getDrawable(holder.view.context, R.drawable.new_space_home_background) + holder.avatar.backgroundTintList = ColorStateList.valueOf( + ColorUtils.setAlphaComponent(ThemeUtils.getColor(holder.view.context, R.attr.vctr_content_tertiary), (255 * 0.3).toInt())) + holder.avatar.setImageResource(R.drawable.ic_space_home) + holder.avatar.imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(holder.view.context, R.attr.vctr_content_primary)) + holder.avatar.scaleType = ImageView.ScaleType.CENTER_INSIDE + + holder.unreadCounter.render(countState) + } + + class Holder : VectorEpoxyHolder() { + val root by bind(R.id.root) + val avatar by bind(R.id.avatar) + val name by bind(R.id.name) + val unreadCounter by bind(R.id.unread_counter) + } +} diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceAddItem.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceAddItem.kt index d90cb5bc67..60816df9c0 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceAddItem.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceAddItem.kt @@ -16,6 +16,8 @@ package im.vector.app.features.spaces +import android.content.res.ColorStateList +import android.widget.ImageView import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.app.R @@ -23,6 +25,7 @@ import im.vector.app.core.epoxy.ClickListener import im.vector.app.core.epoxy.VectorEpoxyHolder import im.vector.app.core.epoxy.VectorEpoxyModel import im.vector.app.core.epoxy.onClick +import im.vector.app.features.themes.ThemeUtils @EpoxyModelClass abstract class NewSpaceAddItem : VectorEpoxyModel(R.layout.item_new_space_add) { @@ -32,7 +35,11 @@ abstract class NewSpaceAddItem : VectorEpoxyModel(R.layo override fun bind(holder: Holder) { super.bind(holder) holder.view.onClick(listener) + + holder.plus.imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(holder.view.context, R.attr.vctr_content_primary)) } - class Holder : VectorEpoxyHolder() + class Holder : VectorEpoxyHolder() { + val plus by bind(R.id.plus) + } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt index 80a8acb1bb..6690e92b50 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt @@ -20,6 +20,7 @@ import com.airbnb.epoxy.EpoxyController import im.vector.app.R import im.vector.app.core.resources.StringProvider import im.vector.app.features.grouplist.homeSpaceSummaryItem +import im.vector.app.features.grouplist.newHomeSpaceSummaryItem import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.list.UnreadCounterBadgeView import org.matrix.android.sdk.api.extensions.orFalse @@ -65,7 +66,7 @@ class NewSpaceSummaryController @Inject constructor( id("space_list_header") } - homeSpaceSummaryItem { + newHomeSpaceSummaryItem { id("space_home") text(this@NewSpaceSummaryController.stringProvider.getString(R.string.all_chats)) selected(selectedSpace == null) diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt index 51fbaad757..bf76c2eecd 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt @@ -143,7 +143,7 @@ class SpaceListFragment @Inject constructor( } if (vectorFeatures.isNewAppLayoutEnabled()) { - newSpaceController.update(state).also { onUpdate?.invoke() } + newSpaceController.update(state) } else { spaceController.update(state) } diff --git a/vector/src/main/res/drawable/new_space_home_background.xml b/vector/src/main/res/drawable/new_space_home_background.xml new file mode 100644 index 0000000000..47fdeb0226 --- /dev/null +++ b/vector/src/main/res/drawable/new_space_home_background.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/vector/src/main/res/drawable/space_home_background.xml b/vector/src/main/res/drawable/space_home_background.xml index 2efd6d407c..c7fc727267 100644 --- a/vector/src/main/res/drawable/space_home_background.xml +++ b/vector/src/main/res/drawable/space_home_background.xml @@ -10,4 +10,4 @@ - \ No newline at end of file + diff --git a/vector/src/main/res/layout/item_new_space_add.xml b/vector/src/main/res/layout/item_new_space_add.xml index 1033d3c6a0..5a62abd740 100644 --- a/vector/src/main/res/layout/item_new_space_add.xml +++ b/vector/src/main/res/layout/item_new_space_add.xml @@ -20,7 +20,7 @@ app:layout_constraintTop_toTopOf="parent" /> diff --git a/vector/src/main/res/layout/item_new_space_list_header.xml b/vector/src/main/res/layout/item_new_space_list_header.xml index 51edd8de59..103d1a1b83 100644 --- a/vector/src/main/res/layout/item_new_space_list_header.xml +++ b/vector/src/main/res/layout/item_new_space_list_header.xml @@ -4,6 +4,7 @@ style="@style/TextAppearance.Vector.Body.Medium" android:layout_width="match_parent" android:layout_height="wrap_content" + android:background="@drawable/bg_space_item" android:orientation="vertical" android:padding="16dp" android:text="@string/all_chats" From b73c097f3c8733deff57a89d71e9e2ec04a74037 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Aug 2022 23:08:10 +0000 Subject: [PATCH 012/191] Bump dagger from 2.42 to 2.43.2 Bumps `dagger` from 2.42 to 2.43.2. Updates `hilt-android-gradle-plugin` from 2.42 to 2.43.2 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.42...dagger-2.43.2) Updates `dagger` from 2.42 to 2.43.2 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.42...dagger-2.43.2) Updates `dagger-compiler` from 2.42 to 2.43.2 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.42...dagger-2.43.2) Updates `hilt-android` from 2.42 to 2.43.2 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.42...dagger-2.43.2) Updates `hilt-android-testing` from 2.42 to 2.43.2 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.42...dagger-2.43.2) Updates `hilt-compiler` from 2.42 to 2.43.2 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.42...dagger-2.43.2) --- updated-dependencies: - dependency-name: com.google.dagger:hilt-android-gradle-plugin dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.google.dagger:dagger dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.google.dagger:dagger-compiler dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.google.dagger:hilt-android dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.google.dagger:hilt-android-testing dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.google.dagger:hilt-compiler dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 93a62a548e..e319fd2629 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -14,7 +14,7 @@ def gradle = "7.1.3" // Ref: https://kotlinlang.org/releases.html def kotlin = "1.6.21" def kotlinCoroutines = "1.6.4" -def dagger = "2.42" +def dagger = "2.43.2" def appDistribution = "16.0.0-beta03" def retrofit = "2.9.0" def arrow = "0.8.2" From 7bf8a419599b4a6851692e6a84536d5f244340a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Aug 2022 23:09:11 +0000 Subject: [PATCH 013/191] Bump flipper from 0.156.0 to 0.157.0 Bumps `flipper` from 0.156.0 to 0.157.0. Updates `flipper` from 0.156.0 to 0.157.0 - [Release notes](https://github.com/facebook/flipper/releases) - [Commits](https://github.com/facebook/flipper/compare/v0.156.0...v0.157.0) Updates `flipper-network-plugin` from 0.156.0 to 0.157.0 - [Release notes](https://github.com/facebook/flipper/releases) - [Commits](https://github.com/facebook/flipper/compare/v0.156.0...v0.157.0) --- updated-dependencies: - dependency-name: com.facebook.flipper:flipper dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.facebook.flipper:flipper-network-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 93a62a548e..8bef583874 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -22,7 +22,7 @@ def markwon = "4.6.2" def moshi = "1.13.0" def lifecycle = "2.5.1" def flowBinding = "1.2.0" -def flipper = "0.156.0" +def flipper = "0.157.0" def epoxy = "4.6.2" def mavericks = "2.7.0" def glide = "4.13.2" From 79e6dd074ace3eaadb24aecc3f768330dc5dbcea Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Thu, 4 Aug 2022 11:41:00 +0200 Subject: [PATCH 014/191] Makes bottom sheet dismiss on space change --- .../im/vector/app/core/di/ViewModelModule.kt | 6 ++ .../RoomListQuickActionsSharedAction.kt | 3 +- .../room/list/actions/RoomListSharedAction.kt | 24 +++++ .../actions/RoomListSharedActionViewModel.kt | 22 +++++ .../room/list/home/HomeRoomListFragment.kt | 95 +++++++++++-------- .../app/features/spaces/SpaceListFragment.kt | 21 ++-- 6 files changed, 122 insertions(+), 49 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedAction.kt create mode 100644 vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedActionViewModel.kt diff --git a/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt index d90e934d0a..c08f939524 100644 --- a/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/ViewModelModule.kt @@ -34,6 +34,7 @@ import im.vector.app.features.home.HomeSharedActionViewModel import im.vector.app.features.home.room.detail.RoomDetailSharedActionViewModel import im.vector.app.features.home.room.detail.timeline.action.MessageSharedActionViewModel import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel +import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel import im.vector.app.features.reactions.EmojiChooserViewModel import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel import im.vector.app.features.roomprofile.RoomProfileSharedActionViewModel @@ -157,4 +158,9 @@ interface ViewModelModule { @IntoMap @ViewModelKey(SpacePeopleSharedActionViewModel::class) fun bindSpacePeopleSharedActionViewModel(viewModel: SpacePeopleSharedActionViewModel): ViewModel + + @Binds + @IntoMap + @ViewModelKey(RoomListSharedActionViewModel::class) + fun bindRoomListSharedActionViewModel(viewModel: RoomListSharedActionViewModel): ViewModel } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt index 0423a8fffc..8c84aa55e1 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt @@ -25,8 +25,7 @@ sealed class RoomListQuickActionsSharedAction( @StringRes val titleRes: Int, @DrawableRes val iconResId: Int?, val destructive: Boolean = false -) : - VectorSharedAction { +) : VectorSharedAction { data class NotificationsAllNoisy(val roomId: String) : RoomListQuickActionsSharedAction( R.string.room_list_quick_actions_notifications_all_noisy, diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedAction.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedAction.kt new file mode 100644 index 0000000000..766bc6eea1 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedAction.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022 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.home.room.list.actions + +import im.vector.app.core.platform.VectorSharedAction + +sealed class RoomListSharedAction : VectorSharedAction { + + object CloseBottomSheet : RoomListSharedAction() +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedActionViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedActionViewModel.kt new file mode 100644 index 0000000000..e2545accc8 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListSharedActionViewModel.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 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.home.room.list.actions + +import im.vector.app.core.platform.VectorSharedActionViewModel +import javax.inject.Inject + +class RoomListSharedActionViewModel @Inject constructor() : VectorSharedActionViewModel() diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt index fae6ddb0c8..a329d52ad6 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt @@ -44,6 +44,8 @@ import im.vector.app.features.home.room.list.RoomSummaryPagedController 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 im.vector.app.features.home.room.list.actions.RoomListSharedAction +import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel import im.vector.app.features.spaces.SpacesBottomSheet import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -60,7 +62,8 @@ class HomeRoomListFragment @Inject constructor( RoomListListener { private val roomListViewModel: HomeRoomListViewModel by fragmentViewModel() - private lateinit var sharedActionViewModel: RoomListQuickActionsSharedActionViewModel + private lateinit var sharedQuickActionsViewModel: RoomListQuickActionsSharedActionViewModel + private lateinit var sharedActionViewModel: RoomListSharedActionViewModel private var concatAdapter = ConcatAdapter() private var modelBuildListener: OnModelBuildFinishedListener? = null @@ -74,15 +77,25 @@ class HomeRoomListFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - - sharedActionViewModel = activityViewModelProvider[RoomListQuickActionsSharedActionViewModel::class.java] - sharedActionViewModel - .stream() - .onEach { handleQuickActions(it) } - .launchIn(viewLifecycleOwner.lifecycleScope) - views.stateView.contentView = views.roomListView views.stateView.state = StateView.State.Loading + setupObservers() + setupRecyclerView() + setupFabs() + } + + private fun setupObservers() { + sharedQuickActionsViewModel = activityViewModelProvider[RoomListQuickActionsSharedActionViewModel::class.java] + sharedActionViewModel = activityViewModelProvider[RoomListSharedActionViewModel::class.java] + + sharedActionViewModel + .stream() + .onEach(::handleSharedAction) + .launchIn(viewLifecycleOwner.lifecycleScope) + sharedQuickActionsViewModel + .stream() + .onEach(::handleQuickActions) + .launchIn(viewLifecycleOwner.lifecycleScope) roomListViewModel.observeViewEvents { when (it) { @@ -92,9 +105,42 @@ class HomeRoomListFragment @Inject constructor( is HomeRoomListViewEvents.Done -> Unit } } + } - setupRecyclerView() - setupFabs() + private fun handleSharedAction(action: RoomListSharedAction) { + when (action) { + RoomListSharedAction.CloseBottomSheet -> spacesBottomSheet.dismiss() + } + } + + private fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) { + when (quickAction) { + is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> { + roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES_NOISY)) + } + is RoomListQuickActionsSharedAction.NotificationsAll -> { + roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES)) + } + is RoomListQuickActionsSharedAction.NotificationsMentionsOnly -> { + roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.MENTIONS_ONLY)) + } + is RoomListQuickActionsSharedAction.NotificationsMute -> { + roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.MUTE)) + } + is RoomListQuickActionsSharedAction.Settings -> { + navigator.openRoomProfile(requireActivity(), quickAction.roomId) + } + is RoomListQuickActionsSharedAction.Favorite -> { + roomListViewModel.handle(HomeRoomListAction.ToggleTag(quickAction.roomId, RoomTag.ROOM_TAG_FAVOURITE)) + } + is RoomListQuickActionsSharedAction.LowPriority -> { + roomListViewModel.handle(HomeRoomListAction.ToggleTag(quickAction.roomId, RoomTag.ROOM_TAG_LOW_PRIORITY)) + } + is RoomListQuickActionsSharedAction.Leave -> { + roomListViewModel.handle(HomeRoomListAction.LeaveRoom(quickAction.roomId)) + promptLeaveRoom(quickAction.roomId) + } + } } private fun setupRecyclerView() { @@ -159,35 +205,6 @@ class HomeRoomListFragment @Inject constructor( } } - private fun handleQuickActions(quickAction: RoomListQuickActionsSharedAction) { - when (quickAction) { - is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> { - roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES_NOISY)) - } - is RoomListQuickActionsSharedAction.NotificationsAll -> { - roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.ALL_MESSAGES)) - } - is RoomListQuickActionsSharedAction.NotificationsMentionsOnly -> { - roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.MENTIONS_ONLY)) - } - is RoomListQuickActionsSharedAction.NotificationsMute -> { - roomListViewModel.handle(HomeRoomListAction.ChangeRoomNotificationState(quickAction.roomId, RoomNotificationState.MUTE)) - } - is RoomListQuickActionsSharedAction.Settings -> { - navigator.openRoomProfile(requireActivity(), quickAction.roomId) - } - is RoomListQuickActionsSharedAction.Favorite -> { - roomListViewModel.handle(HomeRoomListAction.ToggleTag(quickAction.roomId, RoomTag.ROOM_TAG_FAVOURITE)) - } - is RoomListQuickActionsSharedAction.LowPriority -> { - roomListViewModel.handle(HomeRoomListAction.ToggleTag(quickAction.roomId, RoomTag.ROOM_TAG_LOW_PRIORITY)) - } - is RoomListQuickActionsSharedAction.Leave -> { - roomListViewModel.handle(HomeRoomListAction.LeaveRoom(quickAction.roomId)) - promptLeaveRoom(quickAction.roomId) - } - } - } private fun promptLeaveRoom(roomId: String) { val isPublicRoom = roomListViewModel.isPublicRoom(roomId) diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt index bf76c2eecd..770fe1ec52 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt @@ -35,6 +35,8 @@ import im.vector.app.databinding.FragmentSpaceListBinding import im.vector.app.features.VectorFeatures import im.vector.app.features.home.HomeActivitySharedAction import im.vector.app.features.home.HomeSharedActionViewModel +import im.vector.app.features.home.room.list.actions.RoomListSharedAction +import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel import org.matrix.android.sdk.api.session.room.model.RoomSummary import javax.inject.Inject @@ -48,7 +50,8 @@ class SpaceListFragment @Inject constructor( private val vectorFeatures: VectorFeatures, ) : VectorBaseFragment(), SpaceSummaryController.Callback, NewSpaceSummaryController.Callback { - private lateinit var sharedActionViewModel: HomeSharedActionViewModel + private lateinit var homeActivitySharedActionViewModel: HomeSharedActionViewModel + private lateinit var roomListSharedActionViewModel: RoomListSharedActionViewModel private val viewModel: SpaceListViewModel by fragmentViewModel() override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSpaceListBinding { @@ -57,7 +60,8 @@ class SpaceListFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - sharedActionViewModel = activityViewModelProvider[HomeSharedActionViewModel::class.java] + homeActivitySharedActionViewModel = activityViewModelProvider[HomeSharedActionViewModel::class.java] + roomListSharedActionViewModel = activityViewModelProvider[RoomListSharedActionViewModel::class.java] views.stateView.contentView = views.groupListView setupSpaceController() enableDragAndDrop() @@ -121,10 +125,10 @@ class SpaceListFragment @Inject constructor( private fun observeViewEvents() = viewModel.observeViewEvents { when (it) { - is SpaceListViewEvents.OpenSpaceSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpacePreview(it.id)) - is SpaceListViewEvents.AddSpace -> sharedActionViewModel.post(HomeActivitySharedAction.AddSpace) - is SpaceListViewEvents.OpenSpaceInvite -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpaceInvite(it.id)) - SpaceListViewEvents.CloseDrawer -> sharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer) + is SpaceListViewEvents.OpenSpaceSummary -> homeActivitySharedActionViewModel.post(HomeActivitySharedAction.OpenSpacePreview(it.id)) + is SpaceListViewEvents.AddSpace -> homeActivitySharedActionViewModel.post(HomeActivitySharedAction.AddSpace) + is SpaceListViewEvents.OpenSpaceInvite -> homeActivitySharedActionViewModel.post(HomeActivitySharedAction.OpenSpaceInvite(it.id)) + SpaceListViewEvents.CloseDrawer -> homeActivitySharedActionViewModel.post(HomeActivitySharedAction.CloseDrawer) } } @@ -151,6 +155,7 @@ class SpaceListFragment @Inject constructor( override fun onSpaceSelected(spaceSummary: RoomSummary?) { viewModel.handle(SpaceListAction.SelectSpace(spaceSummary)) + roomListSharedActionViewModel.post(RoomListSharedAction.CloseBottomSheet) } override fun onSpaceInviteSelected(spaceSummary: RoomSummary) { @@ -158,7 +163,7 @@ class SpaceListFragment @Inject constructor( } override fun onSpaceSettings(spaceSummary: RoomSummary) { - sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(spaceSummary.roomId)) + homeActivitySharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(spaceSummary.roomId)) } override fun onToggleExpand(spaceSummary: RoomSummary) { @@ -170,6 +175,6 @@ class SpaceListFragment @Inject constructor( } override fun sendFeedBack() { - sharedActionViewModel.post(HomeActivitySharedAction.SendSpaceFeedBack) + homeActivitySharedActionViewModel.post(HomeActivitySharedAction.SendSpaceFeedBack) } } From 68e55c01f9a1b7751a517bef204d459ae60cc7c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Aug 2022 23:09:28 +0000 Subject: [PATCH 015/191] Bump firebase-appdistribution-gradle from 3.0.2 to 3.0.3 Bumps firebase-appdistribution-gradle from 3.0.2 to 3.0.3. --- updated-dependencies: - dependency-name: com.google.firebase:firebase-appdistribution-gradle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index afe51cc734..b91af784d9 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ buildscript { classpath libs.gradle.gradlePlugin classpath libs.gradle.kotlinPlugin classpath libs.gradle.hiltPlugin - classpath 'com.google.firebase:firebase-appdistribution-gradle:3.0.2' + classpath 'com.google.firebase:firebase-appdistribution-gradle:3.0.3' classpath 'com.google.gms:google-services:4.3.13' classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513' classpath 'com.google.android.gms:oss-licenses-plugin:0.10.5' From ff71e69b0ee9ffdfe574775fd3e3ddad3d559dde Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 5 Aug 2022 11:48:11 +0200 Subject: [PATCH 016/191] Makes space list work inside spaces --- .../spaces/NewSpaceSummaryController.kt | 103 ++++++++++++------ 1 file changed, 72 insertions(+), 31 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt index 6690e92b50..5c346be0de 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt @@ -19,11 +19,9 @@ package im.vector.app.features.spaces import com.airbnb.epoxy.EpoxyController import im.vector.app.R import im.vector.app.core.resources.StringProvider -import im.vector.app.features.grouplist.homeSpaceSummaryItem import im.vector.app.features.grouplist.newHomeSpaceSummaryItem import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.list.UnreadCounterBadgeView -import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo @@ -49,6 +47,7 @@ class NewSpaceSummaryController @Inject constructor( override fun buildModels() { val nonNullViewState = viewState ?: return buildGroupModels( + nonNullViewState.asyncSpaces(), nonNullViewState.selectedSpace, nonNullViewState.rootSpacesOrdered, nonNullViewState.homeAggregateCount @@ -56,52 +55,94 @@ class NewSpaceSummaryController @Inject constructor( } private fun buildGroupModels( + spaceSummaries: List?, selectedSpace: RoomSummary?, rootSpaces: List?, homeCount: RoomAggregateNotificationCount ) { val host = this - newSpaceListHeaderItem { id("space_list_header") } - newHomeSpaceSummaryItem { - id("space_home") - text(this@NewSpaceSummaryController.stringProvider.getString(R.string.all_chats)) - selected(selectedSpace == null) - countState(UnreadCounterBadgeView.State(homeCount.totalCount, homeCount.isHighlight)) - listener { host.callback?.onSpaceSelected(null) } + if (selectedSpace != null) { + addSubSpaces(selectedSpace, spaceSummaries, homeCount) + } else { + addHomeItem(true, homeCount) + addRootSpaces(rootSpaces) } - rootSpaces - ?.filter { it.membership != Membership.INVITE } - ?.forEach { roomSummary -> - val isSelected = roomSummary.roomId == selectedSpace?.roomId - - newSpaceSummaryItem { - avatarRenderer(host.avatarRenderer) - id(roomSummary.roomId) - matrixItem(roomSummary.toMatrixItem()) - selected(isSelected) - canDrag(true) - onMore { host.callback?.onSpaceSettings(roomSummary) } - listener { host.callback?.onSpaceSelected(roomSummary) } - countState( - UnreadCounterBadgeView.State( - roomSummary.notificationCount, - roomSummary.highlightCount > 0 - ) - ) - } - } - newSpaceAddItem { id("create") listener { host.callback?.onAddSpaceSelected() } } } + private fun addHomeItem(selected: Boolean, homeCount: RoomAggregateNotificationCount) { + val host = this + newHomeSpaceSummaryItem { + id("space_home") + text(host.stringProvider.getString(R.string.all_chats)) + selected(selected) + countState(UnreadCounterBadgeView.State(homeCount.totalCount, homeCount.isHighlight)) + listener { host.callback?.onSpaceSelected(null) } + } + } + + private fun addSubSpaces( + selectedSpace: RoomSummary, + spaceSummaries: List?, + homeCount: RoomAggregateNotificationCount, + ) { + val host = this + val spaceChildren = selectedSpace.spaceChildren + var subSpacesAdded = false + + spaceChildren?.sortedWith(subSpaceComparator)?.forEach { spaceChild -> + val subSpaceSummary = spaceSummaries?.firstOrNull { it.roomId == spaceChild.childRoomId } ?: return@forEach + + if (subSpaceSummary.membership != Membership.INVITE) { + subSpacesAdded = true + newSpaceSummaryItem { + avatarRenderer(host.avatarRenderer) + id(subSpaceSummary.roomId) + matrixItem(subSpaceSummary.toMatrixItem()) + selected(false) + canDrag(true) + onMore { host.callback?.onSpaceSettings(subSpaceSummary) } + listener { host.callback?.onSpaceSelected(subSpaceSummary) } + countState( + UnreadCounterBadgeView.State( + subSpaceSummary.notificationCount, + subSpaceSummary.highlightCount > 0 + ) + ) + } + } + } + + if (!subSpacesAdded) { + addHomeItem(false, homeCount) + } + } + + private fun addRootSpaces(rootSpaces: List?) { + val host = this + rootSpaces + ?.filter { it.membership != Membership.INVITE } + ?.forEach { roomSummary -> + newSpaceSummaryItem { + avatarRenderer(host.avatarRenderer) + id(roomSummary.roomId) + matrixItem(roomSummary.toMatrixItem()) + canDrag(true) + onMore { host.callback?.onSpaceSettings(roomSummary) } + listener { host.callback?.onSpaceSelected(roomSummary) } + countState(UnreadCounterBadgeView.State(roomSummary.notificationCount, roomSummary.highlightCount > 0)) + } + } + } + interface Callback { fun onSpaceSelected(spaceSummary: RoomSummary?) fun onSpaceInviteSelected(spaceSummary: RoomSummary) From 0506c9abfdc9b4f90f15b1169ad899b67e9cea01 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 5 Aug 2022 11:59:22 +0200 Subject: [PATCH 017/191] Fixes bottom sheet intermittently not having the correct height --- .../spaces/NewSpaceSummaryController.kt | 2 +- .../app/features/spaces/SpaceListViewModel.kt | 34 +++++++++---------- .../app/features/spaces/SpaceListViewState.kt | 1 + 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt index 5c346be0de..781d6942bc 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt @@ -47,7 +47,7 @@ class NewSpaceSummaryController @Inject constructor( override fun buildModels() { val nonNullViewState = viewState ?: return buildGroupModels( - nonNullViewState.asyncSpaces(), + nonNullViewState.spaces, nonNullViewState.selectedSpace, nonNullViewState.rootSpacesOrdered, nonNullViewState.homeAggregateCount diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt index eea11f9b1b..6aab2521f2 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt @@ -257,29 +257,29 @@ class SpaceListViewModel @AssistedInject constructor( } combine( - session.flow() - .liveSpaceSummaries(params), + session.flow().liveSpaceSummaries(params), session.accountDataService() .getLiveRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER)) .asFlow() ) { spaces, _ -> spaces + }.execute { asyncSpaces -> + val spaces = asyncSpaces.invoke().orEmpty() + val rootSpaces = asyncSpaces.invoke().orEmpty().filter { it.flattenParentIds.isEmpty() } + val orders = rootSpaces.associate { + it.roomId to session.getRoom(it.roomId) + ?.roomAccountDataService() + ?.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER) + ?.content.toModel() + ?.safeOrder() + } + copy( + asyncSpaces = asyncSpaces, + spaces = spaces, + rootSpacesOrdered = rootSpaces.sortedWith(TopLevelSpaceComparator(orders)), + spaceOrderInfo = orders + ) } - .execute { async -> - val rootSpaces = async.invoke().orEmpty().filter { it.flattenParentIds.isEmpty() } - val orders = rootSpaces.associate { - it.roomId to session.getRoom(it.roomId) - ?.roomAccountDataService() - ?.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_SPACE_ORDER) - ?.content.toModel() - ?.safeOrder() - } - copy( - asyncSpaces = async, - rootSpacesOrdered = rootSpaces.sortedWith(TopLevelSpaceComparator(orders)), - spaceOrderInfo = orders - ) - } // clear local echos on update session.accountDataService() diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewState.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewState.kt index 794f1dbd69..f75c336b5d 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewState.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewState.kt @@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.util.MatrixItem data class SpaceListViewState( val myMxItem: Async = Uninitialized, val asyncSpaces: Async> = Uninitialized, + val spaces: List = emptyList(), val selectedSpace: RoomSummary? = null, val rootSpacesOrdered: List? = null, val spaceOrderInfo: Map? = null, From a821f34fc0f80d1c7d159c8bfe35123f97c7cfbc Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 5 Aug 2022 12:37:02 +0200 Subject: [PATCH 018/191] Adds drag and drop to space list --- .../app/features/spaces/SpaceListFragment.kt | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt index 770fe1ec52..c408884bc0 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt @@ -64,21 +64,69 @@ class SpaceListFragment @Inject constructor( roomListSharedActionViewModel = activityViewModelProvider[RoomListSharedActionViewModel::class.java] views.stateView.contentView = views.groupListView setupSpaceController() - enableDragAndDrop() observeViewEvents() } private fun setupSpaceController() { if (vectorFeatures.isNewAppLayoutEnabled()) { + enableDragAndDropForNewSpaceController() newSpaceController.callback = this views.groupListView.configureWith(newSpaceController) } else { + enableDragAndDropForSpaceController() spaceController.callback = this views.groupListView.configureWith(spaceController) } } - private fun enableDragAndDrop() { + private fun enableDragAndDropForNewSpaceController() { + EpoxyTouchHelper.initDragging(newSpaceController) + .withRecyclerView(views.groupListView) + .forVerticalList() + .withTarget(NewSpaceSummaryItem::class.java) + .andCallbacks(object : EpoxyTouchHelper.DragCallbacks() { + var toPositionM: Int? = null + var fromPositionM: Int? = null + var initialElevation: Float? = null + + override fun onDragStarted(model: NewSpaceSummaryItem?, itemView: View?, adapterPosition: Int) { + toPositionM = null + fromPositionM = null + model?.matrixItem?.id?.let { + viewModel.handle(SpaceListAction.OnStartDragging(it, model.expanded)) + } + itemView?.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) + initialElevation = itemView?.elevation + itemView?.elevation = 6f + } + + override fun onDragReleased(model: NewSpaceSummaryItem?, itemView: View?) { + if (toPositionM == null || fromPositionM == null) return + val movedSpaceId = model?.matrixItem?.id ?: return + viewModel.handle(SpaceListAction.MoveSpace(movedSpaceId, toPositionM!! - fromPositionM!!)) + } + + override fun clearView(model: NewSpaceSummaryItem?, itemView: View?) { + itemView?.elevation = initialElevation ?: 0f + } + + override fun onModelMoved(fromPosition: Int, toPosition: Int, modelBeingMoved: NewSpaceSummaryItem?, itemView: View?) { + if (fromPositionM == null) { + fromPositionM = fromPosition + } + if (toPositionM != toPosition) { + toPositionM = toPosition + itemView?.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) + } + } + + override fun isDragEnabledForModel(model: NewSpaceSummaryItem?): Boolean { + return model?.canDrag == true + } + }) + } + + private fun enableDragAndDropForSpaceController() { EpoxyTouchHelper.initDragging(spaceController) .withRecyclerView(views.groupListView) .forVerticalList() From 90f2b93763801391da2e32bd8b0c45dbd998723c Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 5 Aug 2022 12:39:52 +0200 Subject: [PATCH 019/191] Appends to comment in SpaceListFragment and refactors SpaceListBottomSheet class name --- .../features/home/room/list/home/HomeRoomListFragment.kt | 8 ++++---- .../{SpacesBottomSheet.kt => SpaceListBottomSheet.kt} | 2 +- .../im/vector/app/features/spaces/SpaceListFragment.kt | 3 +++ 3 files changed, 8 insertions(+), 5 deletions(-) rename vector/src/main/java/im/vector/app/features/spaces/{SpacesBottomSheet.kt => SpaceListBottomSheet.kt} (96%) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt index a329d52ad6..da228572e9 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt @@ -46,7 +46,7 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import im.vector.app.features.home.room.list.actions.RoomListSharedAction import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel -import im.vector.app.features.spaces.SpacesBottomSheet +import im.vector.app.features.spaces.SpaceListBottomSheet import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -67,7 +67,7 @@ class HomeRoomListFragment @Inject constructor( private var concatAdapter = ConcatAdapter() private var modelBuildListener: OnModelBuildFinishedListener? = null - private val spacesBottomSheet = SpacesBottomSheet() + private val spaceListBottomSheet = SpaceListBottomSheet() private lateinit var stateRestorer: LayoutManagerStateRestorer @@ -109,7 +109,7 @@ class HomeRoomListFragment @Inject constructor( private fun handleSharedAction(action: RoomListSharedAction) { when (action) { - RoomListSharedAction.CloseBottomSheet -> spacesBottomSheet.dismiss() + RoomListSharedAction.CloseBottomSheet -> spaceListBottomSheet.dismiss() } } @@ -168,7 +168,7 @@ class HomeRoomListFragment @Inject constructor( views.newLayoutOpenSpacesButton.setOnClickListener { // Click action for open spaces modal goes here - spacesBottomSheet.show(requireActivity().supportFragmentManager, SpacesBottomSheet.TAG) + spaceListBottomSheet.show(requireActivity().supportFragmentManager, SpaceListBottomSheet.TAG) } // Hide FABs when list is scrolling diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpacesBottomSheet.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListBottomSheet.kt similarity index 96% rename from vector/src/main/java/im/vector/app/features/spaces/SpacesBottomSheet.kt rename to vector/src/main/java/im/vector/app/features/spaces/SpaceListBottomSheet.kt index 757e39b85a..910f8c5379 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpacesBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListBottomSheet.kt @@ -25,7 +25,7 @@ import im.vector.app.R import im.vector.app.core.extensions.replaceChildFragment import im.vector.app.databinding.FragmentSpacesBottomSheetBinding -class SpacesBottomSheet : BottomSheetDialogFragment() { +class SpaceListBottomSheet : BottomSheetDialogFragment() { private lateinit var binding: FragmentSpacesBottomSheetBinding diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt index c408884bc0..70bf7c3839 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt @@ -43,6 +43,9 @@ import javax.inject.Inject /** * This Fragment is displayed in the navigation drawer [im.vector.app.features.home.HomeDrawerFragment] and * is displaying the space hierarchy, with some actions on Spaces. + * + * In the New App Layout this fragment will instead be displayed in a Bottom Sheet [SpaceListBottomSheet] + * and will only display spaces that are direct children of the currently selected space (or root spaces if none) */ class SpaceListFragment @Inject constructor( private val spaceController: SpaceSummaryController, From 0567fa3e53b222e3d24cefcaf7e75af7fd2c3db0 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 5 Aug 2022 15:45:53 +0200 Subject: [PATCH 020/191] Changes header text of bottom sheet to Change Space --- .../java/im/vector/app/features/spaces/SpaceListViewModel.kt | 2 +- vector/src/main/res/layout/item_new_space_list_header.xml | 2 +- vector/src/main/res/values/strings.xml | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt index 6aab2521f2..9048026771 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListViewModel.kt @@ -194,7 +194,7 @@ class SpaceListViewModel @AssistedInject constructor( val moved = removeAt(index) add(index + action.delta, moved) }, - spaceOrderLocalEchos = updatedLocalEchos + spaceOrderLocalEchos = updatedLocalEchos, ) } session.coroutineScope.launch { diff --git a/vector/src/main/res/layout/item_new_space_list_header.xml b/vector/src/main/res/layout/item_new_space_list_header.xml index 103d1a1b83..15dceb9b7f 100644 --- a/vector/src/main/res/layout/item_new_space_list_header.xml +++ b/vector/src/main/res/layout/item_new_space_list_header.xml @@ -7,7 +7,7 @@ android:background="@drawable/bg_space_item" android:orientation="vertical" android:padding="16dp" - android:text="@string/all_chats" + android:text="@string/change_space" android:textAllCaps="true" android:textColor="?vctr_content_tertiary" android:textSize="14sp" diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index e3f250151b..859e4daffc 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -137,6 +137,7 @@ All Chats + Change Space From e6508e8a5a7fca71d9f1d10c52a158cacd407657 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 5 Aug 2022 16:08:05 +0200 Subject: [PATCH 021/191] Cleans up epoxy class for NewSpaceSummaryItem and adds ellipsize to header --- .../spaces/NewSpaceSummaryController.kt | 4 ---- .../features/spaces/NewSpaceSummaryItem.kt | 22 ++++++------------- .../app/features/spaces/SpaceListFragment.kt | 6 +---- .../res/layout/item_new_space_list_header.xml | 2 ++ 4 files changed, 10 insertions(+), 24 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt index 781d6942bc..7c4435bf59 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryController.kt @@ -108,8 +108,6 @@ class NewSpaceSummaryController @Inject constructor( id(subSpaceSummary.roomId) matrixItem(subSpaceSummary.toMatrixItem()) selected(false) - canDrag(true) - onMore { host.callback?.onSpaceSettings(subSpaceSummary) } listener { host.callback?.onSpaceSelected(subSpaceSummary) } countState( UnreadCounterBadgeView.State( @@ -135,8 +133,6 @@ class NewSpaceSummaryController @Inject constructor( avatarRenderer(host.avatarRenderer) id(roomSummary.roomId) matrixItem(roomSummary.toMatrixItem()) - canDrag(true) - onMore { host.callback?.onSpaceSettings(roomSummary) } listener { host.callback?.onSpaceSelected(roomSummary) } countState(UnreadCounterBadgeView.State(roomSummary.notificationCount, roomSummary.highlightCount > 0)) } diff --git a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryItem.kt b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryItem.kt index eecb02b320..778b9c933e 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryItem.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/NewSpaceSummaryItem.kt @@ -37,35 +37,27 @@ abstract class NewSpaceSummaryItem : VectorEpoxyModel(R.id.root) - val avatarImageView by bind(R.id.avatar) - val groupNameView by bind(R.id.name) - val counterBadgeView by bind(R.id.unread_counter) + val avatar by bind(R.id.avatar) + val name by bind(R.id.name) + val unreadCounter by bind(R.id.unread_counter) } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt index 70bf7c3839..7b034356b4 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceListFragment.kt @@ -96,7 +96,7 @@ class SpaceListFragment @Inject constructor( toPositionM = null fromPositionM = null model?.matrixItem?.id?.let { - viewModel.handle(SpaceListAction.OnStartDragging(it, model.expanded)) + viewModel.handle(SpaceListAction.OnStartDragging(it, false)) } itemView?.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) initialElevation = itemView?.elevation @@ -122,10 +122,6 @@ class SpaceListFragment @Inject constructor( itemView?.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) } } - - override fun isDragEnabledForModel(model: NewSpaceSummaryItem?): Boolean { - return model?.canDrag == true - } }) } diff --git a/vector/src/main/res/layout/item_new_space_list_header.xml b/vector/src/main/res/layout/item_new_space_list_header.xml index 15dceb9b7f..2c52304249 100644 --- a/vector/src/main/res/layout/item_new_space_list_header.xml +++ b/vector/src/main/res/layout/item_new_space_list_header.xml @@ -5,8 +5,10 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/bg_space_item" + android:ellipsize="middle" android:orientation="vertical" android:padding="16dp" + android:singleLine="true" android:text="@string/change_space" android:textAllCaps="true" android:textColor="?vctr_content_tertiary" From 756570793f0c6d32da42bba9a58fd47d0f4c51e2 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Fri, 5 Aug 2022 17:12:47 +0200 Subject: [PATCH 022/191] Adds changelog file --- changelog.d/6749.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6749.feature diff --git a/changelog.d/6749.feature b/changelog.d/6749.feature new file mode 100644 index 0000000000..d7fac1efc1 --- /dev/null +++ b/changelog.d/6749.feature @@ -0,0 +1 @@ +Adds space list bottom sheet for new app layout From e02cf61f2ff410b4accd1481ea1e0b564fb05ee9 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 8 Aug 2022 16:57:51 +0100 Subject: [PATCH 023/191] decoupling debug receiver from the variants by introducing vector layer interface --- .../app/features/debug/di/DebugModule.kt | 32 ++++++++++++++++ ...ebugReceiver.kt => VectorDebugReceiver.kt} | 12 +++++- .../vector/app/core/platform/DebugReceiver.kt | 24 ++++++++++++ .../app/core/platform/VectorBaseActivity.kt | 21 +++------- .../java/im/vector/app/core/di/DebugModule.kt | 38 +++++++++++++++++++ 5 files changed, 110 insertions(+), 17 deletions(-) create mode 100644 vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt rename vector/src/debug/java/im/vector/app/receivers/{DebugReceiver.kt => VectorDebugReceiver.kt} (88%) create mode 100644 vector/src/main/java/im/vector/app/core/platform/DebugReceiver.kt create mode 100644 vector/src/release/java/im/vector/app/core/di/DebugModule.kt diff --git a/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt b/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt new file mode 100644 index 0000000000..d68d6c743f --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 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 dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import im.vector.app.core.platform.DebugReceiver +import im.vector.app.receivers.VectorDebugReceiver + +@InstallIn(SingletonComponent::class) +@Module +abstract class DebugModule { + + @Binds + abstract fun bindsDebugReceiver(receiver: VectorDebugReceiver): DebugReceiver +} diff --git a/vector/src/debug/java/im/vector/app/receivers/DebugReceiver.kt b/vector/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt similarity index 88% rename from vector/src/debug/java/im/vector/app/receivers/DebugReceiver.kt rename to vector/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt index 9ec475d6d3..9b547a433e 100644 --- a/vector/src/debug/java/im/vector/app/receivers/DebugReceiver.kt +++ b/vector/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt @@ -23,13 +23,23 @@ import android.content.IntentFilter import android.content.SharedPreferences import androidx.core.content.edit import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.platform.DebugReceiver import im.vector.app.core.utils.lsFiles import timber.log.Timber +import javax.inject.Inject /** * Receiver to handle some command from ADB */ -class DebugReceiver : BroadcastReceiver() { +class VectorDebugReceiver @Inject constructor() : BroadcastReceiver(), DebugReceiver { + + override fun register(context: Context) { + context.registerReceiver(this, getIntentFilter(context)) + } + + override fun unregister(context: Context) { + context.unregisterReceiver(this) + } override fun onReceive(context: Context, intent: Intent) { Timber.v("Received debug action: ${intent.action}") diff --git a/vector/src/main/java/im/vector/app/core/platform/DebugReceiver.kt b/vector/src/main/java/im/vector/app/core/platform/DebugReceiver.kt new file mode 100644 index 0000000000..aeb99f312d --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/platform/DebugReceiver.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022 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.core.platform + +import android.content.Context + +interface DebugReceiver { + fun register(context: Context) + fun unregister(context: Context) +} diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index 8a09b6bd46..e5c7ab9228 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -91,7 +91,7 @@ import im.vector.app.features.settings.FontScalePreferencesImpl import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.themes.ActivityOtherThemes import im.vector.app.features.themes.ThemeUtils -import im.vector.app.receivers.DebugReceiver +import im.vector.app.receivers.VectorDebugReceiver import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.extensions.orFalse @@ -160,6 +160,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver @Inject lateinit var rageShake: RageShake @Inject lateinit var buildMeta: BuildMeta @Inject lateinit var fontScalePreferences: FontScalePreferences + // For debug only + @Inject lateinit var debugReceiver: VectorDebugReceiver @Inject lateinit var vectorFeatures: VectorFeatures @@ -176,9 +178,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver private var savedInstanceState: Bundle? = null - // For debug only - private var debugReceiver: DebugReceiver? = null - private val restorables = ArrayList() override fun attachBaseContext(base: Context) { @@ -418,13 +417,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver if (this !is BugReportActivity && vectorPreferences.useRageshake()) { rageShake.start() } - DebugReceiver - .getIntentFilter(this) - .takeIf { buildMeta.isDebug } - ?.let { - debugReceiver = DebugReceiver() - registerReceiver(debugReceiver, it) - } + debugReceiver.register(this) } private val postResumeScheduledActions = mutableListOf<() -> Unit>() @@ -454,11 +447,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver Timber.i("onPause Activity ${javaClass.simpleName}") rageShake.stop() - - debugReceiver?.let { - unregisterReceiver(debugReceiver) - debugReceiver = null - } + debugReceiver.unregister(this) } override fun onWindowFocusChanged(hasFocus: Boolean) { diff --git a/vector/src/release/java/im/vector/app/core/di/DebugModule.kt b/vector/src/release/java/im/vector/app/core/di/DebugModule.kt new file mode 100644 index 0000000000..2899b14b7b --- /dev/null +++ b/vector/src/release/java/im/vector/app/core/di/DebugModule.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 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 dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import im.vector.app.core.platform.DebugReceiver + +@InstallIn(SingletonComponent::class) +@Module +object DebugModule { + @Provides + fun providesDebugReceiver() = object: DebugReceiver { + override fun register(context: Context) { + // no op + } + + override fun unregister(context: Context) { + // no op + } + } +} From 19c8b2a630e0e15d1f828bec0e2a3a69e9b9b2d9 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 8 Aug 2022 17:02:08 +0100 Subject: [PATCH 024/191] moving debug menu access to only the debug sourceset and providing an injectable interface to decouple from the direct access --- vector/src/debug/AndroidManifest.xml | 1 + .../vector/app/features/debug/di/DebugModule.kt | 15 +++++++++++++++ vector/src/main/AndroidManifest.xml | 1 - .../app/features/navigation/DebugNavigator.kt} | 11 ++++++----- .../app/features/navigation/DefaultNavigator.kt | 7 ++++--- .../java/im/vector/app/core/di/DebugModule.kt | 11 ++++++++++- 6 files changed, 36 insertions(+), 10 deletions(-) rename vector/src/{release/java/im/vector/app/features/debug/DebugMenuActivity.kt => main/java/im/vector/app/features/navigation/DebugNavigator.kt} (74%) diff --git a/vector/src/debug/AndroidManifest.xml b/vector/src/debug/AndroidManifest.xml index 84fa2584b9..4ec47d4920 100644 --- a/vector/src/debug/AndroidManifest.xml +++ b/vector/src/debug/AndroidManifest.xml @@ -9,6 +9,7 @@ + - diff --git a/vector/src/release/java/im/vector/app/features/debug/DebugMenuActivity.kt b/vector/src/main/java/im/vector/app/features/navigation/DebugNavigator.kt similarity index 74% rename from vector/src/release/java/im/vector/app/features/debug/DebugMenuActivity.kt rename to vector/src/main/java/im/vector/app/features/navigation/DebugNavigator.kt index c5db033a18..26e8a3e5c6 100644 --- a/vector/src/release/java/im/vector/app/features/debug/DebugMenuActivity.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DebugNavigator.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019 New Vector Ltd + * Copyright (c) 2022 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. @@ -14,9 +14,10 @@ * limitations under the License. */ -package im.vector.app.features.debug +package im.vector.app.features.navigation -import androidx.appcompat.app.AppCompatActivity +import android.content.Context -// This activity is not accessible -class DebugMenuActivity : AppCompatActivity() +interface DebugNavigator { + fun openDebugMenu(context: Context) +} diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index 38db642287..e9f1619ed5 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -51,7 +51,6 @@ import im.vector.app.features.crypto.recover.BootstrapBottomSheet import im.vector.app.features.crypto.recover.SetupMode import im.vector.app.features.crypto.verification.SupportedVerificationMethodsProvider import im.vector.app.features.crypto.verification.VerificationBottomSheet -import im.vector.app.features.debug.DebugMenuActivity import im.vector.app.features.devtools.RoomDevToolActivity import im.vector.app.features.home.room.detail.RoomDetailActivity import im.vector.app.features.home.room.detail.arguments.TimelineArgs @@ -123,7 +122,8 @@ class DefaultNavigator @Inject constructor( private val spaceStateHandler: SpaceStateHandler, private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider, private val features: VectorFeatures, - private val analyticsTracker: AnalyticsTracker + private val analyticsTracker: AnalyticsTracker, + private val debugNavigator: DebugNavigator, ) : Navigator { override fun openLogin(context: Context, loginConfig: LoginConfig?, flags: Int) { @@ -367,7 +367,7 @@ class DefaultNavigator @Inject constructor( } override fun openDebug(context: Context) { - context.startActivity(Intent(context, DebugMenuActivity::class.java)) + debugNavigator.openDebugMenu(context) } override fun openKeysBackupSetup(context: Context, showManualExport: Boolean) { @@ -615,3 +615,4 @@ class DefaultNavigator @Inject constructor( context.startActivity(this) } } + diff --git a/vector/src/release/java/im/vector/app/core/di/DebugModule.kt b/vector/src/release/java/im/vector/app/core/di/DebugModule.kt index 2899b14b7b..c5af1e06c8 100644 --- a/vector/src/release/java/im/vector/app/core/di/DebugModule.kt +++ b/vector/src/release/java/im/vector/app/core/di/DebugModule.kt @@ -21,12 +21,21 @@ import dagger.Module import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import im.vector.app.core.platform.DebugReceiver +import im.vector.app.features.navigation.DebugNavigator @InstallIn(SingletonComponent::class) @Module object DebugModule { + @Provides - fun providesDebugReceiver() = object: DebugReceiver { + fun providesDebugNavigator() = object : DebugNavigator { + override fun openDebugMenu(context: Context) { + // no op + } + } + + @Provides + fun providesDebugReceiver() = object : DebugReceiver { override fun register(context: Context) { // no op } From 8156a646a118d951af376286b1836f22ab36901b Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 8 Aug 2022 17:06:57 +0100 Subject: [PATCH 025/191] moving debug interfaces to debug package --- .../debug/java/im/vector/app/features/debug/di/DebugModule.kt | 4 ++-- .../debug/java/im/vector/app/receivers/VectorDebugReceiver.kt | 2 +- .../app/{features/navigation => core/debug}/DebugNavigator.kt | 2 +- .../im/vector/app/core/{platform => debug}/DebugReceiver.kt | 2 +- .../im/vector/app/features/navigation/DefaultNavigator.kt | 1 + vector/src/release/java/im/vector/app/core/di/DebugModule.kt | 4 ++-- 6 files changed, 8 insertions(+), 7 deletions(-) rename vector/src/main/java/im/vector/app/{features/navigation => core/debug}/DebugNavigator.kt (94%) rename vector/src/main/java/im/vector/app/core/{platform => debug}/DebugReceiver.kt (95%) diff --git a/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt b/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt index f5f10bf9c9..fbac319ee9 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt @@ -23,9 +23,9 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import im.vector.app.core.platform.DebugReceiver +import im.vector.app.core.debug.DebugReceiver import im.vector.app.features.debug.DebugMenuActivity -import im.vector.app.features.navigation.DebugNavigator +import im.vector.app.core.debug.DebugNavigator import im.vector.app.receivers.VectorDebugReceiver @InstallIn(SingletonComponent::class) diff --git a/vector/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt b/vector/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt index 9b547a433e..827fc540f7 100644 --- a/vector/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt +++ b/vector/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt @@ -23,7 +23,7 @@ import android.content.IntentFilter import android.content.SharedPreferences import androidx.core.content.edit import im.vector.app.core.di.DefaultSharedPreferences -import im.vector.app.core.platform.DebugReceiver +import im.vector.app.core.debug.DebugReceiver import im.vector.app.core.utils.lsFiles import timber.log.Timber import javax.inject.Inject diff --git a/vector/src/main/java/im/vector/app/features/navigation/DebugNavigator.kt b/vector/src/main/java/im/vector/app/core/debug/DebugNavigator.kt similarity index 94% rename from vector/src/main/java/im/vector/app/features/navigation/DebugNavigator.kt rename to vector/src/main/java/im/vector/app/core/debug/DebugNavigator.kt index 26e8a3e5c6..16c8dac55c 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DebugNavigator.kt +++ b/vector/src/main/java/im/vector/app/core/debug/DebugNavigator.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.features.navigation +package im.vector.app.core.debug import android.content.Context diff --git a/vector/src/main/java/im/vector/app/core/platform/DebugReceiver.kt b/vector/src/main/java/im/vector/app/core/debug/DebugReceiver.kt similarity index 95% rename from vector/src/main/java/im/vector/app/core/platform/DebugReceiver.kt rename to vector/src/main/java/im/vector/app/core/debug/DebugReceiver.kt index aeb99f312d..7cccba3d37 100644 --- a/vector/src/main/java/im/vector/app/core/platform/DebugReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/debug/DebugReceiver.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.core.platform +package im.vector.app.core.debug import android.content.Context diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index e9f1619ed5..872f102a0d 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -51,6 +51,7 @@ import im.vector.app.features.crypto.recover.BootstrapBottomSheet import im.vector.app.features.crypto.recover.SetupMode import im.vector.app.features.crypto.verification.SupportedVerificationMethodsProvider import im.vector.app.features.crypto.verification.VerificationBottomSheet +import im.vector.app.core.debug.DebugNavigator import im.vector.app.features.devtools.RoomDevToolActivity import im.vector.app.features.home.room.detail.RoomDetailActivity import im.vector.app.features.home.room.detail.arguments.TimelineArgs diff --git a/vector/src/release/java/im/vector/app/core/di/DebugModule.kt b/vector/src/release/java/im/vector/app/core/di/DebugModule.kt index c5af1e06c8..c340c36aed 100644 --- a/vector/src/release/java/im/vector/app/core/di/DebugModule.kt +++ b/vector/src/release/java/im/vector/app/core/di/DebugModule.kt @@ -20,8 +20,8 @@ import dagger.Binds import dagger.Module import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import im.vector.app.core.platform.DebugReceiver -import im.vector.app.features.navigation.DebugNavigator +import im.vector.app.core.debug.DebugNavigator +import im.vector.app.core.debug.DebugReceiver @InstallIn(SingletonComponent::class) @Module From 02286b96b05b8d2529848035753b352355c5f762 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 8 Aug 2022 17:13:43 +0100 Subject: [PATCH 026/191] decoupling the flipper proxy from the vector module --- .../app/features/debug/di/DebugModule.kt | 6 +++++ ...{FlipperProxy.kt => VectorFlipperProxy.kt} | 13 ++++------ .../java/im/vector/app/di/FlavorModule.kt | 8 ++++++ .../java/im/vector/app/di/FlavorModule.kt | 16 +++++++++--- ...ightlyProxy.kt => FirebaseNightlyProxy.kt} | 8 +++--- .../java/im/vector/app/VectorApplication.kt | 2 +- .../im/vector/app/core/debug/FlipperProxy.kt | 25 +++++++++++++++++++ .../im/vector/app/core/di/SingletonModule.kt | 4 +-- .../app/core/platform/VectorBaseActivity.kt | 5 ++-- .../vector/app/features/home/HomeActivity.kt | 1 - .../vector/app/features/home}/NightlyProxy.kt | 8 +++--- .../java/im/vector/app/core/di/DebugModule.kt | 17 +++++++++++-- 12 files changed, 85 insertions(+), 28 deletions(-) rename vector/src/debug/java/im/vector/app/flipper/{FlipperProxy.kt => VectorFlipperProxy.kt} (91%) rename vector/src/gplay/java/im/vector/app/nightly/{NightlyProxy.kt => FirebaseNightlyProxy.kt} (95%) create mode 100644 vector/src/main/java/im/vector/app/core/debug/FlipperProxy.kt rename vector/src/{fdroid/java/im/vector/app/nightly => main/java/im/vector/app/features/home}/NightlyProxy.kt (82%) diff --git a/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt b/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt index fbac319ee9..56df9fa0bc 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt @@ -26,6 +26,8 @@ import dagger.hilt.components.SingletonComponent import im.vector.app.core.debug.DebugReceiver import im.vector.app.features.debug.DebugMenuActivity import im.vector.app.core.debug.DebugNavigator +import im.vector.app.core.debug.FlipperProxy +import im.vector.app.flipper.VectorFlipperProxy import im.vector.app.receivers.VectorDebugReceiver @InstallIn(SingletonComponent::class) @@ -44,4 +46,8 @@ abstract class DebugModule { @Binds abstract fun bindsDebugReceiver(receiver: VectorDebugReceiver): DebugReceiver + + @Binds + abstract fun bindsFlipperProxy(flipperProxy: VectorFlipperProxy): FlipperProxy + } diff --git a/vector/src/debug/java/im/vector/app/flipper/FlipperProxy.kt b/vector/src/debug/java/im/vector/app/flipper/VectorFlipperProxy.kt similarity index 91% rename from vector/src/debug/java/im/vector/app/flipper/FlipperProxy.kt rename to vector/src/debug/java/im/vector/app/flipper/VectorFlipperProxy.kt index 76be7e1b46..2e4336c942 100644 --- a/vector/src/debug/java/im/vector/app/flipper/FlipperProxy.kt +++ b/vector/src/debug/java/im/vector/app/flipper/VectorFlipperProxy.kt @@ -29,19 +29,19 @@ import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPl import com.facebook.soloader.SoLoader import com.kgurgul.flipper.RealmDatabaseDriver import com.kgurgul.flipper.RealmDatabaseProvider +import im.vector.app.core.debug.FlipperProxy import io.realm.RealmConfiguration -import okhttp3.Interceptor import org.matrix.android.sdk.api.Matrix import javax.inject.Inject import javax.inject.Singleton @Singleton -class FlipperProxy @Inject constructor( +class VectorFlipperProxy @Inject constructor( private val context: Context, -) { +) : FlipperProxy { private val networkFlipperPlugin = NetworkFlipperPlugin() - fun init(matrix: Matrix) { + override fun init(matrix: Matrix) { SoLoader.init(context, false) if (FlipperUtils.shouldEnableFlipper(context)) { @@ -65,8 +65,5 @@ class FlipperProxy @Inject constructor( } } - @Suppress("RedundantNullableReturnType") - fun getNetworkInterceptor(): Interceptor? { - return FlipperOkhttpInterceptor(networkFlipperPlugin) - } + override fun networkInterceptor() = FlipperOkhttpInterceptor(networkFlipperPlugin) } diff --git a/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt b/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt index 1a3348f4c6..fcad54c3d2 100644 --- a/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt +++ b/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt @@ -23,6 +23,7 @@ import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import im.vector.app.core.services.GuardServiceStarter import im.vector.app.fdroid.service.FDroidGuardServiceStarter +import im.vector.app.features.home.NightlyProxy import im.vector.app.features.settings.VectorPreferences @InstallIn(SingletonComponent::class) @@ -33,4 +34,11 @@ object FlavorModule { fun provideGuardServiceStarter(preferences: VectorPreferences, appContext: Context): GuardServiceStarter { return FDroidGuardServiceStarter(preferences, appContext) } + + @Provides + fun provideNightlyProxy() = object : NightlyProxy { + override fun onHomeResumed() { + // no op + } + } } diff --git a/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt b/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt index 901320be4c..256c908a02 100644 --- a/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt +++ b/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt @@ -16,18 +16,26 @@ package im.vector.app.di +import dagger.Binds import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import im.vector.app.core.services.GuardServiceStarter +import im.vector.app.features.home.NightlyProxy +import im.vector.app.nightly.FirebaseNightlyProxy @InstallIn(SingletonComponent::class) @Module -object FlavorModule { +abstract class FlavorModule { - @Provides - fun provideGuardServiceStarter(): GuardServiceStarter { - return object : GuardServiceStarter {} + companion object { + @Provides + fun provideGuardServiceStarter(): GuardServiceStarter { + return object : GuardServiceStarter {} + } } + + @Binds + abstract fun bindsNightlyProxy(nightlyProxy: FirebaseNightlyProxy): NightlyProxy } diff --git a/vector/src/gplay/java/im/vector/app/nightly/NightlyProxy.kt b/vector/src/gplay/java/im/vector/app/nightly/FirebaseNightlyProxy.kt similarity index 95% rename from vector/src/gplay/java/im/vector/app/nightly/NightlyProxy.kt rename to vector/src/gplay/java/im/vector/app/nightly/FirebaseNightlyProxy.kt index 7c6685f5ce..59a1e3eb17 100644 --- a/vector/src/gplay/java/im/vector/app/nightly/NightlyProxy.kt +++ b/vector/src/gplay/java/im/vector/app/nightly/FirebaseNightlyProxy.kt @@ -23,15 +23,17 @@ import com.google.firebase.appdistribution.FirebaseAppDistributionException import im.vector.app.BuildConfig import im.vector.app.core.di.DefaultPreferences import im.vector.app.core.time.Clock +import im.vector.app.features.home.NightlyProxy import timber.log.Timber import javax.inject.Inject -class NightlyProxy @Inject constructor( +class FirebaseNightlyProxy @Inject constructor( private val clock: Clock, @DefaultPreferences private val sharedPreferences: SharedPreferences, -) { - fun onHomeResumed() { +) : NightlyProxy { + + override fun onHomeResumed() { if (!canDisplayPopup()) return val firebaseAppDistribution = FirebaseAppDistribution.getInstance() firebaseAppDistribution.updateIfNewReleaseAvailable() diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index b1bd0fc308..f31b5d915e 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -41,6 +41,7 @@ import com.vanniktech.emoji.EmojiManager import com.vanniktech.emoji.google.GoogleEmojiProvider import dagger.hilt.android.HiltAndroidApp import im.vector.app.config.Config +import im.vector.app.core.debug.FlipperProxy import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.resources.BuildMeta import im.vector.app.features.analytics.VectorAnalytics @@ -59,7 +60,6 @@ import im.vector.app.features.settings.VectorLocale import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.version.VersionProvider -import im.vector.app.flipper.FlipperProxy import im.vector.app.push.fcm.FcmHelper import org.jitsi.meet.sdk.log.JitsiMeetDefaultLogHandler import org.matrix.android.sdk.api.Matrix diff --git a/vector/src/main/java/im/vector/app/core/debug/FlipperProxy.kt b/vector/src/main/java/im/vector/app/core/debug/FlipperProxy.kt new file mode 100644 index 0000000000..a05da239f5 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/debug/FlipperProxy.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 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.core.debug + +import okhttp3.Interceptor +import org.matrix.android.sdk.api.Matrix + +interface FlipperProxy { + fun init(matrix: Matrix) + fun networkInterceptor(): Interceptor? +} diff --git a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt index 6959f17586..a060ebe731 100644 --- a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt @@ -34,6 +34,7 @@ import im.vector.app.EmojiSpanify import im.vector.app.SpaceStateHandler import im.vector.app.SpaceStateHandlerImpl import im.vector.app.config.Config +import im.vector.app.core.debug.FlipperProxy import im.vector.app.core.dispatchers.CoroutineDispatchers import im.vector.app.core.error.DefaultErrorFormatter import im.vector.app.core.error.ErrorFormatter @@ -57,7 +58,6 @@ import im.vector.app.features.settings.FontScalePreferencesImpl import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.ui.SharedPreferencesUiStateRepository import im.vector.app.features.ui.UiStateRepository -import im.vector.app.flipper.FlipperProxy import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers @@ -144,7 +144,7 @@ object VectorStaticModule { roomDisplayNameFallbackProvider = vectorRoomDisplayNameFallbackProvider, threadMessagesEnabledDefault = vectorPreferences.areThreadMessagesEnabled(), networkInterceptors = listOfNotNull( - flipperProxy.getNetworkInterceptor(), + flipperProxy.networkInterceptor(), ) ) } diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index e5c7ab9228..24a65e1071 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -55,6 +55,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.EntryPointAccessors import im.vector.app.R +import im.vector.app.core.debug.DebugReceiver import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ActivityEntryPoint import im.vector.app.core.dialogs.DialogLocker @@ -91,7 +92,6 @@ import im.vector.app.features.settings.FontScalePreferencesImpl import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.themes.ActivityOtherThemes import im.vector.app.features.themes.ThemeUtils -import im.vector.app.receivers.VectorDebugReceiver import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.extensions.orFalse @@ -160,8 +160,9 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver @Inject lateinit var rageShake: RageShake @Inject lateinit var buildMeta: BuildMeta @Inject lateinit var fontScalePreferences: FontScalePreferences + // For debug only - @Inject lateinit var debugReceiver: VectorDebugReceiver + @Inject lateinit var debugReceiver: DebugReceiver @Inject lateinit var vectorFeatures: VectorFeatures diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 12cdaecdf9..4dd6f8cfba 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -79,7 +79,6 @@ import im.vector.app.features.spaces.invite.SpaceInviteBottomSheet import im.vector.app.features.spaces.share.ShareSpaceBottomSheet import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.workers.signout.ServerBackupStatusViewModel -import im.vector.app.nightly.NightlyProxy import im.vector.app.push.fcm.FcmHelper import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach diff --git a/vector/src/fdroid/java/im/vector/app/nightly/NightlyProxy.kt b/vector/src/main/java/im/vector/app/features/home/NightlyProxy.kt similarity index 82% rename from vector/src/fdroid/java/im/vector/app/nightly/NightlyProxy.kt rename to vector/src/main/java/im/vector/app/features/home/NightlyProxy.kt index eecf3a24f2..b25add2ac9 100644 --- a/vector/src/fdroid/java/im/vector/app/nightly/NightlyProxy.kt +++ b/vector/src/main/java/im/vector/app/features/home/NightlyProxy.kt @@ -14,10 +14,8 @@ * limitations under the License. */ -package im.vector.app.nightly +package im.vector.app.features.home -import javax.inject.Inject - -class NightlyProxy @Inject constructor() { - fun onHomeResumed() = Unit +interface NightlyProxy { + fun onHomeResumed() } diff --git a/vector/src/release/java/im/vector/app/core/di/DebugModule.kt b/vector/src/release/java/im/vector/app/core/di/DebugModule.kt index c340c36aed..bedbe97864 100644 --- a/vector/src/release/java/im/vector/app/core/di/DebugModule.kt +++ b/vector/src/release/java/im/vector/app/core/di/DebugModule.kt @@ -14,14 +14,18 @@ * limitations under the License. */ -package im.vector.app.features.debug.di +package im.vector.app.core.di -import dagger.Binds +import android.content.Context import dagger.Module +import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import im.vector.app.core.debug.DebugNavigator import im.vector.app.core.debug.DebugReceiver +import im.vector.app.core.debug.FlipperProxy +import okhttp3.Interceptor +import org.matrix.android.sdk.api.Matrix @InstallIn(SingletonComponent::class) @Module @@ -44,4 +48,13 @@ object DebugModule { // no op } } + + @Provides + fun providesFlipperProxy() = object : FlipperProxy { + override fun init(matrix: Matrix) { + // no op + } + + override fun networkInterceptor(): Interceptor? = null + } } From f605e0c4791318e3f8b103004b7cd4fa1fa4c223 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 8 Aug 2022 17:51:08 +0100 Subject: [PATCH 027/191] decoupling the notification test factory from the vector module --- .../vector/app/di/NotificationTestModule.kt | 31 +++++++++++++++++++ ...ficationTroubleshootTestManagerFactory.kt} | 7 +++-- .../vector/app/di/NotificationTestModule.kt | 31 +++++++++++++++++++ ...ficationTroubleshootTestManagerFactory.kt} | 7 +++-- ...ificationTroubleshootTestManagerFactory.kt | 24 ++++++++++++++ ...ttingsNotificationsTroubleshootFragment.kt | 2 +- 6 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 vector/src/fdroid/java/im/vector/app/di/NotificationTestModule.kt rename vector/src/fdroid/java/im/vector/app/push/fcm/{NotificationTroubleshootTestManagerFactory.kt => FdroidNotificationTroubleshootTestManagerFactory.kt} (93%) create mode 100644 vector/src/gplay/java/im/vector/app/di/NotificationTestModule.kt rename vector/src/gplay/java/im/vector/app/push/fcm/{NotificationTroubleshootTestManagerFactory.kt => GoogleNotificationTroubleshootTestManagerFactory.kt} (93%) create mode 100644 vector/src/main/java/im/vector/app/features/push/NotificationTroubleshootTestManagerFactory.kt diff --git a/vector/src/fdroid/java/im/vector/app/di/NotificationTestModule.kt b/vector/src/fdroid/java/im/vector/app/di/NotificationTestModule.kt new file mode 100644 index 0000000000..a171126168 --- /dev/null +++ b/vector/src/fdroid/java/im/vector/app/di/NotificationTestModule.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 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.di + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ActivityComponent +import im.vector.app.features.push.NotificationTroubleshootTestManagerFactory +import im.vector.app.push.fcm.FdroidNotificationTroubleshootTestManagerFactory + +@InstallIn(ActivityComponent::class) +@Module +abstract class NotificationTestModule { + @Binds + abstract fun bindsNotificationTestFactory(factory: FdroidNotificationTroubleshootTestManagerFactory): NotificationTroubleshootTestManagerFactory +} diff --git a/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/fdroid/java/im/vector/app/push/fcm/FdroidNotificationTroubleshootTestManagerFactory.kt similarity index 93% rename from vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt rename to vector/src/fdroid/java/im/vector/app/push/fcm/FdroidNotificationTroubleshootTestManagerFactory.kt index 5873b4308f..86843f0e6f 100644 --- a/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/fdroid/java/im/vector/app/push/fcm/FdroidNotificationTroubleshootTestManagerFactory.kt @@ -21,6 +21,7 @@ import im.vector.app.fdroid.features.settings.troubleshoot.TestAutoStartBoot import im.vector.app.fdroid.features.settings.troubleshoot.TestBackgroundRestrictions import im.vector.app.fdroid.features.settings.troubleshoot.TestBatteryOptimization import im.vector.app.features.VectorFeatures +import im.vector.app.features.push.NotificationTroubleshootTestManagerFactory import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager import im.vector.app.features.settings.troubleshoot.TestAccountSettings import im.vector.app.features.settings.troubleshoot.TestAvailableUnifiedPushDistributors @@ -35,7 +36,7 @@ import im.vector.app.features.settings.troubleshoot.TestUnifiedPushEndpoint import im.vector.app.features.settings.troubleshoot.TestUnifiedPushGateway import javax.inject.Inject -class NotificationTroubleshootTestManagerFactory @Inject constructor( +class FdroidNotificationTroubleshootTestManagerFactory @Inject constructor( private val unifiedPushHelper: UnifiedPushHelper, private val testSystemSettings: TestSystemSettings, private val testAccountSettings: TestAccountSettings, @@ -52,9 +53,9 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor( private val testBatteryOptimization: TestBatteryOptimization, private val testNotification: TestNotification, private val vectorFeatures: VectorFeatures, -) { +): NotificationTroubleshootTestManagerFactory { - fun create(fragment: Fragment): NotificationTroubleshootTestManager { + override fun create(fragment: Fragment): NotificationTroubleshootTestManager { val mgr = NotificationTroubleshootTestManager(fragment) mgr.addTest(testSystemSettings) mgr.addTest(testAccountSettings) diff --git a/vector/src/gplay/java/im/vector/app/di/NotificationTestModule.kt b/vector/src/gplay/java/im/vector/app/di/NotificationTestModule.kt new file mode 100644 index 0000000000..f3dfbccfc1 --- /dev/null +++ b/vector/src/gplay/java/im/vector/app/di/NotificationTestModule.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 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.di + +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.android.components.ActivityComponent +import im.vector.app.features.push.NotificationTroubleshootTestManagerFactory +import im.vector.app.push.fcm.GoogleNotificationTroubleshootTestManagerFactory + +@InstallIn(ActivityComponent::class) +@Module +abstract class NotificationTestModule { + @Binds + abstract fun bindsNotificationTestFactory(factory: GoogleNotificationTroubleshootTestManagerFactory): NotificationTroubleshootTestManagerFactory +} diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/gplay/java/im/vector/app/push/fcm/GoogleNotificationTroubleshootTestManagerFactory.kt similarity index 93% rename from vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt rename to vector/src/gplay/java/im/vector/app/push/fcm/GoogleNotificationTroubleshootTestManagerFactory.kt index b3425c778b..154e127fb6 100644 --- a/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/GoogleNotificationTroubleshootTestManagerFactory.kt @@ -18,6 +18,7 @@ package im.vector.app.push.fcm import androidx.fragment.app.Fragment import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.features.VectorFeatures +import im.vector.app.features.push.NotificationTroubleshootTestManagerFactory import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager import im.vector.app.features.settings.troubleshoot.TestAccountSettings import im.vector.app.features.settings.troubleshoot.TestAvailableUnifiedPushDistributors @@ -35,7 +36,7 @@ import im.vector.app.gplay.features.settings.troubleshoot.TestPlayServices import im.vector.app.gplay.features.settings.troubleshoot.TestTokenRegistration import javax.inject.Inject -class NotificationTroubleshootTestManagerFactory @Inject constructor( +class GoogleNotificationTroubleshootTestManagerFactory @Inject constructor( private val unifiedPushHelper: UnifiedPushHelper, private val testSystemSettings: TestSystemSettings, private val testAccountSettings: TestAccountSettings, @@ -52,9 +53,9 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor( private val testPushFromPushGateway: TestPushFromPushGateway, private val testNotification: TestNotification, private val vectorFeatures: VectorFeatures, -) { +) : NotificationTroubleshootTestManagerFactory { - fun create(fragment: Fragment): NotificationTroubleshootTestManager { + override fun create(fragment: Fragment): NotificationTroubleshootTestManager { val mgr = NotificationTroubleshootTestManager(fragment) mgr.addTest(testSystemSettings) mgr.addTest(testAccountSettings) diff --git a/vector/src/main/java/im/vector/app/features/push/NotificationTroubleshootTestManagerFactory.kt b/vector/src/main/java/im/vector/app/features/push/NotificationTroubleshootTestManagerFactory.kt new file mode 100644 index 0000000000..6a3ce04c1a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/push/NotificationTroubleshootTestManagerFactory.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2022 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.push + +import androidx.fragment.app.Fragment +import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager + +interface NotificationTroubleshootTestManagerFactory { + fun create(fragment: Fragment): NotificationTroubleshootTestManager +} diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationsTroubleshootFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationsTroubleshootFragment.kt index 8a3407b428..e75824195e 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationsTroubleshootFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationsTroubleshootFragment.kt @@ -35,11 +35,11 @@ import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentSettingsNotificationsTroubleshootBinding import im.vector.app.features.notifications.NotificationActionIds +import im.vector.app.features.push.NotificationTroubleshootTestManagerFactory import im.vector.app.features.rageshake.BugReporter import im.vector.app.features.settings.VectorSettingsFragmentInteractionListener import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager import im.vector.app.features.settings.troubleshoot.TroubleshootTest -import im.vector.app.push.fcm.NotificationTroubleshootTestManagerFactory import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull import javax.inject.Inject From 0c61595ace023f26d22aa85baf6a7fb8c3bdcd78 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Mon, 8 Aug 2022 18:05:04 +0100 Subject: [PATCH 028/191] decoupling the fcm helper from the vector module --- .../java/im/vector/app/di/FlavorModule.kt | 26 ++++++---- .../fcm/{FcmHelper.kt => FdroidFcmHelper.kt} | 17 ++++--- .../java/im/vector/app/di/FlavorModule.kt | 5 ++ .../troubleshoot/TestFirebaseToken.kt | 2 +- .../troubleshoot/TestTokenRegistration.kt | 2 +- .../fcm/{FcmHelper.kt => GoogleFcmHelper.kt} | 17 ++++--- .../java/im/vector/app/VectorApplication.kt | 2 +- .../im/vector/app/core/pushers/FcmHelper.kt | 50 +++++++++++++++++++ .../app/core/pushers/UnifiedPushHelper.kt | 1 - .../vector/app/features/home/HomeActivity.kt | 2 +- .../TestAvailableUnifiedPushDistributors.kt | 2 +- 11 files changed, 95 insertions(+), 31 deletions(-) rename vector/src/fdroid/java/im/vector/app/push/fcm/{FcmHelper.kt => FdroidFcmHelper.kt} (78%) rename vector/src/gplay/java/im/vector/app/push/fcm/{FcmHelper.kt => GoogleFcmHelper.kt} (87%) create mode 100644 vector/src/main/java/im/vector/app/core/pushers/FcmHelper.kt diff --git a/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt b/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt index fcad54c3d2..5a7a527c3f 100644 --- a/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt +++ b/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt @@ -17,28 +17,36 @@ package im.vector.app.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.core.pushers.FcmHelper import im.vector.app.core.services.GuardServiceStarter import im.vector.app.fdroid.service.FDroidGuardServiceStarter import im.vector.app.features.home.NightlyProxy import im.vector.app.features.settings.VectorPreferences +import im.vector.app.push.fcm.FdroidFcmHelper @InstallIn(SingletonComponent::class) @Module -object FlavorModule { +abstract class FlavorModule { - @Provides - fun provideGuardServiceStarter(preferences: VectorPreferences, appContext: Context): GuardServiceStarter { - return FDroidGuardServiceStarter(preferences, appContext) - } + companion object { + @Provides + fun provideGuardServiceStarter(preferences: VectorPreferences, appContext: Context): GuardServiceStarter { + return FDroidGuardServiceStarter(preferences, appContext) + } - @Provides - fun provideNightlyProxy() = object : NightlyProxy { - override fun onHomeResumed() { - // no op + @Provides + fun provideNightlyProxy() = object : NightlyProxy { + override fun onHomeResumed() { + // no op + } } } + + @Binds + abstract fun bindsFcmHelper(fcmHelper: FdroidFcmHelper): FcmHelper } diff --git a/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt b/vector/src/fdroid/java/im/vector/app/push/fcm/FdroidFcmHelper.kt similarity index 78% rename from vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt rename to vector/src/fdroid/java/im/vector/app/push/fcm/FdroidFcmHelper.kt index 24ff00a353..8d41ce1e00 100755 --- a/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt +++ b/vector/src/fdroid/java/im/vector/app/push/fcm/FdroidFcmHelper.kt @@ -20,6 +20,7 @@ package im.vector.app.push.fcm import android.app.Activity import android.content.Context import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.pushers.FcmHelper import im.vector.app.core.pushers.PushersManager import im.vector.app.fdroid.BackgroundSyncStarter import im.vector.app.fdroid.receiver.AlarmSyncBroadcastReceiver @@ -28,19 +29,19 @@ import javax.inject.Inject /** * This class has an alter ego in the gplay variant. */ -class FcmHelper @Inject constructor( +class FdroidFcmHelper @Inject constructor( private val context: Context, private val backgroundSyncStarter: BackgroundSyncStarter, -) { +) : FcmHelper { - fun isFirebaseAvailable(): Boolean = false + override fun isFirebaseAvailable(): Boolean = false /** * Retrieves the FCM registration token. * * @return the FCM token or null if not received from FCM */ - fun getFcmToken(): String? { + override fun getFcmToken(): String? { return null } @@ -49,7 +50,7 @@ class FcmHelper @Inject constructor( * * @param token the token to store */ - fun storeFcmToken(token: String?) { + override fun storeFcmToken(token: String?) { // No op } @@ -58,17 +59,17 @@ class FcmHelper @Inject constructor( * * @param activity the first launch Activity */ - fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) { + override fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) { // No op } - fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) { + override fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) { // try to stop all regardless of background mode activeSessionHolder.getSafeActiveSession()?.syncService()?.stopAnyBackgroundSync() AlarmSyncBroadcastReceiver.cancelAlarm(context) } - fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) { + override fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) { backgroundSyncStarter.start(activeSessionHolder) } } diff --git a/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt b/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt index 256c908a02..442f5f2eed 100644 --- a/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt +++ b/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt @@ -21,9 +21,11 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import im.vector.app.core.pushers.FcmHelper import im.vector.app.core.services.GuardServiceStarter import im.vector.app.features.home.NightlyProxy import im.vector.app.nightly.FirebaseNightlyProxy +import im.vector.app.push.fcm.GoogleFcmHelper @InstallIn(SingletonComponent::class) @Module @@ -38,4 +40,7 @@ abstract class FlavorModule { @Binds abstract fun bindsNightlyProxy(nightlyProxy: FirebaseNightlyProxy): NightlyProxy + + @Binds + abstract fun bindsFcmHelper(fcmHelper: GoogleFcmHelper): FcmHelper } diff --git a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestFirebaseToken.kt b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestFirebaseToken.kt index e7e3157f6b..d6180a9fe8 100644 --- a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestFirebaseToken.kt +++ b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestFirebaseToken.kt @@ -20,10 +20,10 @@ import androidx.activity.result.ActivityResultLauncher import androidx.fragment.app.FragmentActivity import com.google.firebase.messaging.FirebaseMessaging import im.vector.app.R +import im.vector.app.core.pushers.FcmHelper import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.startAddGoogleAccountIntent import im.vector.app.features.settings.troubleshoot.TroubleshootTest -import im.vector.app.push.fcm.FcmHelper import timber.log.Timber import javax.inject.Inject diff --git a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestTokenRegistration.kt b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestTokenRegistration.kt index 8c21404d20..840bde77b1 100644 --- a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestTokenRegistration.kt +++ b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestTokenRegistration.kt @@ -23,10 +23,10 @@ import androidx.work.WorkInfo import androidx.work.WorkManager import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.pushers.FcmHelper import im.vector.app.core.pushers.PushersManager import im.vector.app.core.resources.StringProvider import im.vector.app.features.settings.troubleshoot.TroubleshootTest -import im.vector.app.push.fcm.FcmHelper import org.matrix.android.sdk.api.session.pushers.PusherState import javax.inject.Inject diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt b/vector/src/gplay/java/im/vector/app/push/fcm/GoogleFcmHelper.kt similarity index 87% rename from vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt rename to vector/src/gplay/java/im/vector/app/push/fcm/GoogleFcmHelper.kt index a4eb9efc73..636f4f3189 100755 --- a/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/GoogleFcmHelper.kt @@ -25,6 +25,7 @@ import com.google.firebase.messaging.FirebaseMessaging import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.pushers.FcmHelper import im.vector.app.core.pushers.PushersManager import timber.log.Timber import javax.inject.Inject @@ -33,23 +34,23 @@ import javax.inject.Inject * This class store the FCM token in SharedPrefs and ensure this token is retrieved. * It has an alter ego in the fdroid variant. */ -class FcmHelper @Inject constructor( +class GoogleFcmHelper @Inject constructor( context: Context, -) { +) : FcmHelper { companion object { private const val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN" } private val sharedPrefs = DefaultSharedPreferences.getInstance(context) - fun isFirebaseAvailable(): Boolean = true + override fun isFirebaseAvailable(): Boolean = true /** * Retrieves the FCM registration token. * * @return the FCM token or null if not received from FCM */ - fun getFcmToken(): String? { + override fun getFcmToken(): String? { return sharedPrefs.getString(PREFS_KEY_FCM_TOKEN, null) } @@ -59,7 +60,7 @@ class FcmHelper @Inject constructor( * * @param token the token to store */ - fun storeFcmToken(token: String?) { + override fun storeFcmToken(token: String?) { sharedPrefs.edit { putString(PREFS_KEY_FCM_TOKEN, token) } @@ -70,7 +71,7 @@ class FcmHelper @Inject constructor( * * @param activity the first launch Activity */ - fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) { + override fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) { // if (TextUtils.isEmpty(getFcmToken(activity))) { // 'app should always check the device for a compatible Google Play services APK before accessing Google Play services features' if (checkPlayServices(activity)) { @@ -106,12 +107,12 @@ class FcmHelper @Inject constructor( } @Suppress("UNUSED_PARAMETER") - fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) { + override fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) { // No op } @Suppress("UNUSED_PARAMETER") - fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) { + override fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) { // No op } } diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index f31b5d915e..53222ab962 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -43,6 +43,7 @@ import dagger.hilt.android.HiltAndroidApp import im.vector.app.config.Config import im.vector.app.core.debug.FlipperProxy import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.pushers.FcmHelper import im.vector.app.core.resources.BuildMeta import im.vector.app.features.analytics.VectorAnalytics import im.vector.app.features.call.webrtc.WebRtcCallManager @@ -60,7 +61,6 @@ import im.vector.app.features.settings.VectorLocale import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.version.VersionProvider -import im.vector.app.push.fcm.FcmHelper import org.jitsi.meet.sdk.log.JitsiMeetDefaultLogHandler import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.auth.AuthenticationService diff --git a/vector/src/main/java/im/vector/app/core/pushers/FcmHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/FcmHelper.kt new file mode 100644 index 0000000000..601722a036 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/pushers/FcmHelper.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 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.core.pushers + +import android.app.Activity +import im.vector.app.core.di.ActiveSessionHolder + +interface FcmHelper { + fun isFirebaseAvailable(): Boolean + + /** + * Retrieves the FCM registration token. + * + * @return the FCM token or null if not received from FCM + */ + fun getFcmToken(): String? + + /** + * Store FCM token to the SharedPrefs + * TODO Store in realm + * + * @param token the token to store + */ + fun storeFcmToken(token: String?) + + /** + * onNewToken may not be called on application upgrade, so ensure my shared pref is set + * + * @param activity the first launch Activity + */ + fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) + + fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) + + fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) +} diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 724d3c7aa6..1f44ab3686 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -28,7 +28,6 @@ import im.vector.app.core.utils.getApplicationLabel import im.vector.app.features.VectorFeatures import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorPreferences -import im.vector.app.push.fcm.FcmHelper import kotlinx.coroutines.launch import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.cache.CacheStrategy diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 4dd6f8cfba..fe57b9f735 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -44,6 +44,7 @@ import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.extensions.validateBackPressed import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorMenuProvider +import im.vector.app.core.pushers.FcmHelper import im.vector.app.core.pushers.PushersManager import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.utils.startSharePlainTextIntent @@ -79,7 +80,6 @@ import im.vector.app.features.spaces.invite.SpaceInviteBottomSheet import im.vector.app.features.spaces.share.ShareSpaceBottomSheet import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.workers.signout.ServerBackupStatusViewModel -import im.vector.app.push.fcm.FcmHelper import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt index acc0142924..89e7d8c204 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt @@ -19,9 +19,9 @@ package im.vector.app.features.settings.troubleshoot import android.content.Intent import androidx.activity.result.ActivityResultLauncher import im.vector.app.R +import im.vector.app.core.pushers.FcmHelper import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.resources.StringProvider -import im.vector.app.push.fcm.FcmHelper import javax.inject.Inject class TestAvailableUnifiedPushDistributors @Inject constructor( From 9892c66d2753e81f6ed4d8c90c9fd69881a89980 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Tue, 9 Aug 2022 10:54:28 +0200 Subject: [PATCH 029/191] Fixes lint errors --- .../java/im/vector/app/features/home/NewHomeDetailFragment.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index c0f6c673f4..cfd4b1f0bf 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -44,7 +44,6 @@ import im.vector.app.features.call.SharedKnownCallsViewModel import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.dialpad.DialPadFragment import im.vector.app.features.call.webrtc.WebRtcCallManager -import im.vector.app.features.home.room.list.RoomListFragment import im.vector.app.features.home.room.list.RoomListParams import im.vector.app.features.home.room.list.home.HomeRoomListFragment import im.vector.app.features.popup.PopupAlertManager From ed3b73a98990dbb6a80a147f90c5a157b0282ebe Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 9 Aug 2022 10:32:43 +0100 Subject: [PATCH 030/191] decouples the flavor code / OSS licenses activity launching --- .../fdroid/java/im/vector/app/di/FlavorModule.kt | 10 ++++++++++ .../app/{FlavorCode.kt => GoogleFlavorLegals.kt} | 14 ++++++++++++-- .../gplay/java/im/vector/app/di/FlavorModule.kt | 6 ++++++ .../app/features/settings/legals/FlavourLegals.kt} | 10 ++++++---- .../features/settings/legals/LegalsController.kt | 5 +++-- .../app/features/settings/legals/LegalsFragment.kt | 7 +++---- 6 files changed, 40 insertions(+), 12 deletions(-) rename vector/src/gplay/java/im/vector/app/{FlavorCode.kt => GoogleFlavorLegals.kt} (60%) rename vector/src/{fdroid/java/im/vector/app/FlavorCode.kt => main/java/im/vector/app/features/settings/legals/FlavourLegals.kt} (74%) diff --git a/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt b/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt index 5a7a527c3f..1936fbda8c 100644 --- a/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt +++ b/vector/src/fdroid/java/im/vector/app/di/FlavorModule.kt @@ -27,6 +27,7 @@ import im.vector.app.core.services.GuardServiceStarter import im.vector.app.fdroid.service.FDroidGuardServiceStarter import im.vector.app.features.home.NightlyProxy import im.vector.app.features.settings.VectorPreferences +import im.vector.app.features.settings.legals.FlavourLegals import im.vector.app.push.fcm.FdroidFcmHelper @InstallIn(SingletonComponent::class) @@ -45,6 +46,15 @@ abstract class FlavorModule { // no op } } + + @Provides + fun providesFlavorLegals() = object : FlavourLegals { + override fun hasThirdPartyNotices() = false + + override fun navigateToThirdPartyNotices(context: Context) { + // no op + } + } } @Binds diff --git a/vector/src/gplay/java/im/vector/app/FlavorCode.kt b/vector/src/gplay/java/im/vector/app/GoogleFlavorLegals.kt similarity index 60% rename from vector/src/gplay/java/im/vector/app/FlavorCode.kt rename to vector/src/gplay/java/im/vector/app/GoogleFlavorLegals.kt index 040296d755..32849b3741 100644 --- a/vector/src/gplay/java/im/vector/app/FlavorCode.kt +++ b/vector/src/gplay/java/im/vector/app/GoogleFlavorLegals.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 New Vector Ltd + * Copyright (c) 2022 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. @@ -19,5 +19,15 @@ package im.vector.app import android.content.Context import android.content.Intent import com.google.android.gms.oss.licenses.OssLicensesMenuActivity +import im.vector.app.features.settings.legals.FlavourLegals +import javax.inject.Inject -fun openOssLicensesMenuActivity(context: Context) = context.startActivity(Intent(context, OssLicensesMenuActivity::class.java)) +class GoogleFlavorLegals @Inject constructor() : FlavourLegals { + + override fun hasThirdPartyNotices() = true + + override fun navigateToThirdPartyNotices(context: Context) { + // See https://developers.google.com/android/guides/opensource + context.startActivity(Intent(context, OssLicensesMenuActivity::class.java)) + } +} diff --git a/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt b/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt index 442f5f2eed..c97d1bff04 100644 --- a/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt +++ b/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt @@ -21,9 +21,11 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import im.vector.app.GoogleFlavorLegals import im.vector.app.core.pushers.FcmHelper import im.vector.app.core.services.GuardServiceStarter import im.vector.app.features.home.NightlyProxy +import im.vector.app.features.settings.legals.FlavourLegals import im.vector.app.nightly.FirebaseNightlyProxy import im.vector.app.push.fcm.GoogleFcmHelper @@ -43,4 +45,8 @@ abstract class FlavorModule { @Binds abstract fun bindsFcmHelper(fcmHelper: GoogleFcmHelper): FcmHelper + + @Binds + abstract fun bindsFlavorLegals(legals: GoogleFlavorLegals): FlavourLegals } + diff --git a/vector/src/fdroid/java/im/vector/app/FlavorCode.kt b/vector/src/main/java/im/vector/app/features/settings/legals/FlavourLegals.kt similarity index 74% rename from vector/src/fdroid/java/im/vector/app/FlavorCode.kt rename to vector/src/main/java/im/vector/app/features/settings/legals/FlavourLegals.kt index 7d8ef22b44..a33ad23f7e 100644 --- a/vector/src/fdroid/java/im/vector/app/FlavorCode.kt +++ b/vector/src/main/java/im/vector/app/features/settings/legals/FlavourLegals.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 New Vector Ltd + * Copyright (c) 2022 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. @@ -14,9 +14,11 @@ * limitations under the License. */ -package im.vector.app +package im.vector.app.features.settings.legals import android.content.Context -// No op -fun openOssLicensesMenuActivity(@Suppress("UNUSED_PARAMETER") context: Context) = Unit +interface FlavourLegals { + fun hasThirdPartyNotices(): Boolean + fun navigateToThirdPartyNotices(context: Context) +} diff --git a/vector/src/main/java/im/vector/app/features/settings/legals/LegalsController.kt b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsController.kt index f88b73f36c..c64b2e51d3 100644 --- a/vector/src/main/java/im/vector/app/features/settings/legals/LegalsController.kt +++ b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsController.kt @@ -38,7 +38,8 @@ class LegalsController @Inject constructor( private val stringProvider: StringProvider, private val resources: Resources, private val elementLegals: ElementLegals, - private val errorFormatter: ErrorFormatter + private val errorFormatter: ErrorFormatter, + private val flavourLegals: FlavourLegals, ) : TypedEpoxyController() { var listener: Listener? = null @@ -134,7 +135,7 @@ class LegalsController @Inject constructor( clickListener { host.listener?.openThirdPartyNotice() } } // Only on Gplay - if (resources.getBoolean(R.bool.isGplay)) { + if (flavourLegals.hasThirdPartyNotices()) { discoveryPolicyItem { id("eltpn2") name(host.stringProvider.getString(R.string.settings_other_third_party_notices)) diff --git a/vector/src/main/java/im/vector/app/features/settings/legals/LegalsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsFragment.kt index 9a4090ad1b..7bdcb9b5c9 100644 --- a/vector/src/main/java/im/vector/app/features/settings/legals/LegalsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsFragment.kt @@ -33,11 +33,11 @@ import im.vector.app.databinding.FragmentGenericRecyclerBinding import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.discovery.ServerPolicy import im.vector.app.features.settings.VectorSettingsUrls -import im.vector.app.openOssLicensesMenuActivity import javax.inject.Inject class LegalsFragment @Inject constructor( - private val controller: LegalsController + private val controller: LegalsController, + private val flavourLegals: FlavourLegals, ) : VectorBaseFragment(), LegalsController.Listener { @@ -100,8 +100,7 @@ class LegalsFragment @Inject constructor( override fun openThirdPartyNoticeGplay() { if (firstThrottler.canHandle() is FirstThrottler.CanHandlerResult.Yes) { - // See https://developers.google.com/android/guides/opensource - openOssLicensesMenuActivity(requireActivity()) + flavourLegals.navigateToThirdPartyNotices(requireContext()) } } } From 045398d06feddff81be334cddf8c834a86383d68 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 9 Aug 2022 10:42:44 +0100 Subject: [PATCH 031/191] fixing import ordering and duplicated documentation --- .../app/features/debug/di/DebugModule.kt | 5 ++--- .../app/receivers/VectorDebugReceiver.kt | 2 +- .../im/vector/app/push/fcm/FdroidFcmHelper.kt | 15 --------------- ...ificationTroubleshootTestManagerFactory.kt | 2 +- .../java/im/vector/app/di/FlavorModule.kt | 1 - .../im/vector/app/push/fcm/GoogleFcmHelper.kt | 19 +------------------ .../im/vector/app/core/pushers/FcmHelper.kt | 13 +++++++------ .../features/navigation/DefaultNavigator.kt | 3 +-- 8 files changed, 13 insertions(+), 47 deletions(-) diff --git a/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt b/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt index 56df9fa0bc..b15f6dce62 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/di/DebugModule.kt @@ -23,10 +23,10 @@ import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent -import im.vector.app.core.debug.DebugReceiver -import im.vector.app.features.debug.DebugMenuActivity import im.vector.app.core.debug.DebugNavigator +import im.vector.app.core.debug.DebugReceiver import im.vector.app.core.debug.FlipperProxy +import im.vector.app.features.debug.DebugMenuActivity import im.vector.app.flipper.VectorFlipperProxy import im.vector.app.receivers.VectorDebugReceiver @@ -49,5 +49,4 @@ abstract class DebugModule { @Binds abstract fun bindsFlipperProxy(flipperProxy: VectorFlipperProxy): FlipperProxy - } diff --git a/vector/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt b/vector/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt index 827fc540f7..550dc055d9 100644 --- a/vector/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt +++ b/vector/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt @@ -22,8 +22,8 @@ import android.content.Intent import android.content.IntentFilter import android.content.SharedPreferences import androidx.core.content.edit -import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.core.debug.DebugReceiver +import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.core.utils.lsFiles import timber.log.Timber import javax.inject.Inject diff --git a/vector/src/fdroid/java/im/vector/app/push/fcm/FdroidFcmHelper.kt b/vector/src/fdroid/java/im/vector/app/push/fcm/FdroidFcmHelper.kt index 8d41ce1e00..5b83769116 100755 --- a/vector/src/fdroid/java/im/vector/app/push/fcm/FdroidFcmHelper.kt +++ b/vector/src/fdroid/java/im/vector/app/push/fcm/FdroidFcmHelper.kt @@ -36,29 +36,14 @@ class FdroidFcmHelper @Inject constructor( override fun isFirebaseAvailable(): Boolean = false - /** - * Retrieves the FCM registration token. - * - * @return the FCM token or null if not received from FCM - */ override fun getFcmToken(): String? { return null } - /** - * Store FCM token to the SharedPrefs - * - * @param token the token to store - */ override fun storeFcmToken(token: String?) { // No op } - /** - * onNewToken may not be called on application upgrade, so ensure my shared pref is set - * - * @param activity the first launch Activity - */ override fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) { // No op } diff --git a/vector/src/fdroid/java/im/vector/app/push/fcm/FdroidNotificationTroubleshootTestManagerFactory.kt b/vector/src/fdroid/java/im/vector/app/push/fcm/FdroidNotificationTroubleshootTestManagerFactory.kt index 86843f0e6f..d99afa59f7 100644 --- a/vector/src/fdroid/java/im/vector/app/push/fcm/FdroidNotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/fdroid/java/im/vector/app/push/fcm/FdroidNotificationTroubleshootTestManagerFactory.kt @@ -53,7 +53,7 @@ class FdroidNotificationTroubleshootTestManagerFactory @Inject constructor( private val testBatteryOptimization: TestBatteryOptimization, private val testNotification: TestNotification, private val vectorFeatures: VectorFeatures, -): NotificationTroubleshootTestManagerFactory { +) : NotificationTroubleshootTestManagerFactory { override fun create(fragment: Fragment): NotificationTroubleshootTestManager { val mgr = NotificationTroubleshootTestManager(fragment) diff --git a/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt b/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt index c97d1bff04..393ea1e62a 100644 --- a/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt +++ b/vector/src/gplay/java/im/vector/app/di/FlavorModule.kt @@ -49,4 +49,3 @@ abstract class FlavorModule { @Binds abstract fun bindsFlavorLegals(legals: GoogleFlavorLegals): FlavourLegals } - diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/GoogleFcmHelper.kt b/vector/src/gplay/java/im/vector/app/push/fcm/GoogleFcmHelper.kt index 636f4f3189..d64847c124 100755 --- a/vector/src/gplay/java/im/vector/app/push/fcm/GoogleFcmHelper.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/GoogleFcmHelper.kt @@ -45,32 +45,17 @@ class GoogleFcmHelper @Inject constructor( override fun isFirebaseAvailable(): Boolean = true - /** - * Retrieves the FCM registration token. - * - * @return the FCM token or null if not received from FCM - */ override fun getFcmToken(): String? { return sharedPrefs.getString(PREFS_KEY_FCM_TOKEN, null) } - /** - * Store FCM token to the SharedPrefs - * TODO Store in realm - * - * @param token the token to store - */ override fun storeFcmToken(token: String?) { + // TODO Store in realm sharedPrefs.edit { putString(PREFS_KEY_FCM_TOKEN, token) } } - /** - * onNewToken may not be called on application upgrade, so ensure my shared pref is set - * - * @param activity the first launch Activity - */ override fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) { // if (TextUtils.isEmpty(getFcmToken(activity))) { // 'app should always check the device for a compatible Google Play services APK before accessing Google Play services features' @@ -106,12 +91,10 @@ class GoogleFcmHelper @Inject constructor( return resultCode == ConnectionResult.SUCCESS } - @Suppress("UNUSED_PARAMETER") override fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) { // No op } - @Suppress("UNUSED_PARAMETER") override fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) { // No op } diff --git a/vector/src/main/java/im/vector/app/core/pushers/FcmHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/FcmHelper.kt index 601722a036..7b2c5e3959 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/FcmHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/FcmHelper.kt @@ -25,22 +25,23 @@ interface FcmHelper { /** * Retrieves the FCM registration token. * - * @return the FCM token or null if not received from FCM + * @return the FCM token or null if not received from FCM. */ fun getFcmToken(): String? /** - * Store FCM token to the SharedPrefs - * TODO Store in realm + * Store FCM token to the SharedPrefs. * - * @param token the token to store + * @param token the token to store. */ fun storeFcmToken(token: String?) /** - * onNewToken may not be called on application upgrade, so ensure my shared pref is set + * onNewToken may not be called on application upgrade, so ensure my shared pref is set. * - * @param activity the first launch Activity + * @param activity the first launch Activity. + * @param pushersManager the instance to register the pusher on. + * @param registerPusher whether the pusher should be registered. */ fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index 872f102a0d..e724084501 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -34,6 +34,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import im.vector.app.R import im.vector.app.SpaceStateHandler import im.vector.app.config.OnboardingVariant +import im.vector.app.core.debug.DebugNavigator import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.error.fatalError import im.vector.app.features.VectorFeatures @@ -51,7 +52,6 @@ import im.vector.app.features.crypto.recover.BootstrapBottomSheet import im.vector.app.features.crypto.recover.SetupMode import im.vector.app.features.crypto.verification.SupportedVerificationMethodsProvider import im.vector.app.features.crypto.verification.VerificationBottomSheet -import im.vector.app.core.debug.DebugNavigator import im.vector.app.features.devtools.RoomDevToolActivity import im.vector.app.features.home.room.detail.RoomDetailActivity import im.vector.app.features.home.room.detail.arguments.TimelineArgs @@ -616,4 +616,3 @@ class DefaultNavigator @Inject constructor( context.startActivity(this) } } - From 319ec6fbf492fb47265170331445a98c20dc9b8d Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 9 Aug 2022 11:25:55 +0100 Subject: [PATCH 032/191] removing now unused gplay resource --- vector/build.gradle | 2 -- 1 file changed, 2 deletions(-) diff --git a/vector/build.gradle b/vector/build.gradle index 0edaf5424e..1244a84bfd 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -307,7 +307,6 @@ android { isDefault = true versionName "${versionMajor}.${versionMinor}.${versionPatch}${getGplayVersionSuffix()}" - resValue "bool", "isGplay", "true" buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"G\"" buildConfigField "String", "FLAVOR_DESCRIPTION", "\"GooglePlay\"" } @@ -317,7 +316,6 @@ android { versionName "${versionMajor}.${versionMinor}.${versionPatch}${getFdroidVersionSuffix()}" - resValue "bool", "isGplay", "false" buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"F\"" buildConfigField "String", "FLAVOR_DESCRIPTION", "\"FDroid\"" } From 65b7a317286e73f0c035dfefa5c54ce378752a64 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Tue, 9 Aug 2022 14:23:56 +0200 Subject: [PATCH 033/191] Fixes toMvRxBundle import --- .../java/im/vector/app/features/home/NewHomeDetailFragment.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index cfd4b1f0bf..bfdf385356 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -31,6 +31,7 @@ import com.google.android.material.badge.BadgeDrawable import im.vector.app.R import im.vector.app.SpaceStateHandler import im.vector.app.core.extensions.commitTransaction +import im.vector.app.core.extensions.toMvRxBundle import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment From af04221ad9e0d1eaa0bb6f4546d3b43cf65ff47e Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Tue, 9 Aug 2022 14:30:36 +0200 Subject: [PATCH 034/191] Improves content descriptions --- vector/src/main/res/layout/fragment_room_list.xml | 4 ++-- vector/src/main/res/values/strings.xml | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/vector/src/main/res/layout/fragment_room_list.xml b/vector/src/main/res/layout/fragment_room_list.xml index 631602bb14..17d93eb98a 100644 --- a/vector/src/main/res/layout/fragment_room_list.xml +++ b/vector/src/main/res/layout/fragment_room_list.xml @@ -67,7 +67,7 @@ android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:accessibilityTraversalAfter="@id/newLayoutCreateChatButton" - android:contentDescription="@string/a11y_create_room" + android:contentDescription="@string/a11y_open_spaces" android:src="@drawable/ic_open_spaces" android:visibility="gone" app:backgroundTint="?attr/vctr_toolbar_background" @@ -88,7 +88,7 @@ android:layout_marginEnd="16dp" android:layout_marginBottom="16dp" android:accessibilityTraversalBefore="@id/roomListView" - android:contentDescription="@string/a11y_create_room" + android:contentDescription="@string/a11y_create_message" android:src="@drawable/ic_new_chat" android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index bd4f032d0e..9fc9756897 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1812,7 +1812,8 @@ Close the create room menu… Create a new direct conversation Create a new conversation or room - Create a new room + Create a new room + Open spaces list Close keys backup banner Jump to bottom From d7949307a41f5cceacdb2e1e6f8190a15d9ae1cd Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 9 Aug 2022 14:01:00 +0100 Subject: [PATCH 035/191] adding changelog entry --- changelog.d/6783.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6783.misc diff --git a/changelog.d/6783.misc b/changelog.d/6783.misc new file mode 100644 index 0000000000..d1095c1203 --- /dev/null +++ b/changelog.d/6783.misc @@ -0,0 +1 @@ +Decouples the variant logic from the vector module From a2768ccab7b99c3a44cdd745033d63b52fe91f12 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 9 Aug 2022 16:22:21 +0100 Subject: [PATCH 036/191] ignoring the gl locale from the play store upload step as it's unsupported --- tools/release/pushPlayStoreMetaData.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/release/pushPlayStoreMetaData.sh b/tools/release/pushPlayStoreMetaData.sh index 2d8fd9b36a..5c2f69cb7b 100755 --- a/tools/release/pushPlayStoreMetaData.sh +++ b/tools/release/pushPlayStoreMetaData.sh @@ -28,6 +28,7 @@ mv ./fastlane/metadata/android/fy ./fastlane_tmp mv ./fastlane/metadata/android/ga ./fastlane_tmp mv ./fastlane/metadata/android/kab ./fastlane_tmp mv ./fastlane/metadata/android/nb ./fastlane_tmp +mv ./fastlane/metadata/android/gl ./fastlane_tmp # Fastlane / PlayStore require longDescription and shortDescription file to be set, so copy the default # one for languages where they are missing From 9505d196e4d0f191b229042d92b55bc780f21174 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Wed, 10 Aug 2022 08:10:33 +0200 Subject: [PATCH 037/191] Changes space title in toolbar --- .../java/im/vector/app/features/home/NewHomeDetailFragment.kt | 3 +-- vector/src/main/res/layout/fragment_new_home_detail.xml | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index bfdf385356..4766cd5006 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -270,8 +270,7 @@ class NewHomeDetailFragment @Inject constructor( } private fun onSpaceChange(spaceSummary: RoomSummary?) { - // Reimplement in next PR - println(spaceSummary) + views.collapsingToolbar.title = (spaceSummary?.displayName ?: getString(R.string.all_chats)) } private fun setupKeysBackupBanner() { diff --git a/vector/src/main/res/layout/fragment_new_home_detail.xml b/vector/src/main/res/layout/fragment_new_home_detail.xml index b0e7bf7634..8066ab1bd9 100644 --- a/vector/src/main/res/layout/fragment_new_home_detail.xml +++ b/vector/src/main/res/layout/fragment_new_home_detail.xml @@ -49,6 +49,7 @@ app:layout_constraintTop_toBottomOf="@id/syncStateView"> + tools:title="@string/all_chats"> Date: Wed, 10 Aug 2022 08:24:03 +0200 Subject: [PATCH 038/191] Removes params passed into HomeRoomListFragment and fixes lint error --- .../im/vector/app/features/home/NewHomeDetailFragment.kt | 5 +---- .../app/features/home/room/list/home/HomeRoomListFragment.kt | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index bfdf385356..c2b61d694a 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -31,7 +31,6 @@ import com.google.android.material.badge.BadgeDrawable import im.vector.app.R import im.vector.app.SpaceStateHandler import im.vector.app.core.extensions.commitTransaction -import im.vector.app.core.extensions.toMvRxBundle import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment @@ -45,7 +44,6 @@ import im.vector.app.features.call.SharedKnownCallsViewModel import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.dialpad.DialPadFragment import im.vector.app.features.call.webrtc.WebRtcCallManager -import im.vector.app.features.home.room.list.RoomListParams import im.vector.app.features.home.room.list.home.HomeRoomListFragment import im.vector.app.features.popup.PopupAlertManager import im.vector.app.features.popup.VerificationVectorAlert @@ -339,8 +337,7 @@ class NewHomeDetailFragment @Inject constructor( if (fragmentToShow == null) { when (tab) { is HomeTab.RoomList -> { - val params = RoomListParams(tab.displayMode) - add(R.id.roomListContainer, HomeRoomListFragment::class.java, params.toMvRxBundle(), fragmentTag) + add(R.id.roomListContainer, HomeRoomListFragment::class.java, null, fragmentTag) } is HomeTab.DialPad -> { add(R.id.roomListContainer, createDialPadFragment(), fragmentTag) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt index bb8fee632c..d0ef6fc0c2 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt @@ -205,7 +205,6 @@ class HomeRoomListFragment @Inject constructor( } } - private fun promptLeaveRoom(roomId: String) { val isPublicRoom = roomListViewModel.isPublicRoom(roomId) val message = buildString { From 358ec5a722e5fe0b6889a65e9f9d6d9bf918301e Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Wed, 10 Aug 2022 08:25:51 +0200 Subject: [PATCH 039/191] Fixes post merge errors --- .../app/features/home/room/list/home/HomeRoomListFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt index b29e151350..3c0c8f6b7e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt @@ -47,8 +47,8 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import im.vector.app.features.home.room.list.actions.RoomListSharedAction import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel -import im.vector.app.features.spaces.SpaceListBottomSheet import im.vector.app.features.home.room.list.home.recent.RecentRoomCarouselController +import im.vector.app.features.spaces.SpaceListBottomSheet import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.room.model.RoomSummary From fb0b38bb4936c19c45f5ed7fb67ce48ecfdb9894 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Tue, 9 Aug 2022 17:18:56 +0200 Subject: [PATCH 040/191] Adding new feature flag for new device management --- .../app/features/debug/features/DebugFeaturesStateFactory.kt | 5 +++++ .../app/features/debug/features/DebugVectorFeatures.kt | 4 ++++ .../src/main/java/im/vector/app/features/VectorFeatures.kt | 2 ++ 3 files changed, 11 insertions(+) diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt index d7e402c4dc..c127e3aed6 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt @@ -90,6 +90,11 @@ class DebugFeaturesStateFactory @Inject constructor( key = DebugFeatureKeys.newAppLayoutEnabled, factory = VectorFeatures::isNewAppLayoutEnabled ), + createBooleanFeature( + label = "Enable New Device Management", + key = DebugFeatureKeys.newDeviceManagementEnabled, + factory = VectorFeatures::isNewDeviceManagementEnabled + ), ) ) } 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 index 031ff11d59..003b9b8084 100644 --- 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 @@ -79,6 +79,9 @@ class DebugVectorFeatures( override fun isNewAppLayoutEnabled(): Boolean = read(DebugFeatureKeys.newAppLayoutEnabled) ?: vectorFeatures.isNewAppLayoutEnabled() + override fun isNewDeviceManagementEnabled(): Boolean = read(DebugFeatureKeys.newDeviceManagementEnabled) + ?: vectorFeatures.isNewDeviceManagementEnabled() + fun override(value: T?, key: Preferences.Key) = updatePreferences { if (value == null) { it.remove(key) @@ -139,4 +142,5 @@ object DebugFeatureKeys { val forceUsageOfOpusEncoder = booleanPreferencesKey("force-usage-of-opus-encoder") val startDmOnFirstMsg = booleanPreferencesKey("start-dm-on-first-msg") val newAppLayoutEnabled = booleanPreferencesKey("new-app-layout-enabled") + val newDeviceManagementEnabled = booleanPreferencesKey("new-device-management-enabled") } 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 290d21879d..e60b225689 100644 --- a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt +++ b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt @@ -34,6 +34,7 @@ interface VectorFeatures { fun forceUsageOfOpusEncoder(): Boolean fun shouldStartDmOnFirstMessage(): Boolean fun isNewAppLayoutEnabled(): Boolean + fun isNewDeviceManagementEnabled(): Boolean } class DefaultVectorFeatures : VectorFeatures { @@ -50,4 +51,5 @@ class DefaultVectorFeatures : VectorFeatures { override fun forceUsageOfOpusEncoder(): Boolean = false override fun shouldStartDmOnFirstMessage(): Boolean = false override fun isNewAppLayoutEnabled(): Boolean = false + override fun isNewDeviceManagementEnabled(): Boolean = false } From db1d0daec077a60f57c1a2670a7d632f6bb680a5 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 10 Aug 2022 09:50:02 +0200 Subject: [PATCH 041/191] Adding a new setting entry behind feature flag --- .../vector/app/features/settings/VectorPreferences.kt | 1 + .../settings/VectorSettingsSecurityPrivacyFragment.kt | 10 ++++++++++ .../main/res/xml/vector_settings_security_privacy.xml | 7 ++++++- 3 files changed, 17 insertions(+), 1 deletion(-) 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 ac14bfc3c7..0134fc581b 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 @@ -74,6 +74,7 @@ class VectorPreferences @Inject constructor( const val SETTINGS_ENCRYPTION_IMPORT_E2E_ROOM_KEYS_PREFERENCE_KEY = "SETTINGS_ENCRYPTION_IMPORT_E2E_ROOM_KEYS_PREFERENCE_KEY" const val SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY = "SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY" const val SETTINGS_SHOW_DEVICES_LIST_PREFERENCE_KEY = "SETTINGS_SHOW_DEVICES_LIST_PREFERENCE_KEY" + const val SETTINGS_SHOW_DEVICES_V2_LIST_PREFERENCE_KEY = "SETTINGS_SHOW_DEVICES_V2_LIST_PREFERENCE_KEY" const val SETTINGS_ALLOW_INTEGRATIONS_KEY = "SETTINGS_ALLOW_INTEGRATIONS_KEY" const val SETTINGS_INTEGRATION_MANAGER_UI_URL_KEY = "SETTINGS_INTEGRATION_MANAGER_UI_URL_KEY" const val SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY = "SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY" diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt index ac8a47b81e..023bb9e03f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -50,6 +50,7 @@ import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.openFileSelection import im.vector.app.core.utils.toast import im.vector.app.databinding.DialogImportE2eKeysBinding +import im.vector.app.features.VectorFeatures import im.vector.app.features.analytics.AnalyticsConfig import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewActions @@ -86,6 +87,7 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( private val rawService: RawService, private val navigator: Navigator, private val analyticsConfig: AnalyticsConfig, + private val vectorFeatures: VectorFeatures, ) : VectorSettingsBaseFragment() { override var titleRes = R.string.settings_security_and_privacy @@ -135,6 +137,10 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( findPreference(VectorPreferences.SETTINGS_SHOW_DEVICES_LIST_PREFERENCE_KEY)!! } + private val showDevicesV2ListPref by lazy { + findPreference(VectorPreferences.SETTINGS_SHOW_DEVICES_V2_LIST_PREFERENCE_KEY)!! + } + // encrypt to unverified devices private val sendToUnverifiedDevicesPref by lazy { findPreference(VectorPreferences.SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY)!! @@ -546,6 +552,10 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( showDeviceListPref.isEnabled = devices.isNotEmpty() showDeviceListPref.summary = resources.getQuantityString(R.plurals.settings_active_sessions_count, devices.size, devices.size) + showDevicesV2ListPref.isVisible = vectorFeatures.isNewDeviceManagementEnabled() + showDevicesV2ListPref.title = showDeviceListPref.title.toString() + " (V2, WIP)" + showDevicesV2ListPref.summary = resources.getQuantityString(R.plurals.settings_active_sessions_count, devices.size, devices.size) + val userId = session.myUserId val deviceId = session.sessionParams.deviceId diff --git a/vector/src/main/res/xml/vector_settings_security_privacy.xml b/vector/src/main/res/xml/vector_settings_security_privacy.xml index d4dfed2fcf..d3493fd984 100644 --- a/vector/src/main/res/xml/vector_settings_security_privacy.xml +++ b/vector/src/main/res/xml/vector_settings_security_privacy.xml @@ -62,6 +62,11 @@ android:title="@string/settings_active_sessions_show_all" app:fragment="im.vector.app.features.settings.devices.VectorSettingsDevicesFragment" /> + + - \ No newline at end of file + From 1ebc2a9a8c0485a7d91a72a2e0d69097bc680165 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 10 Aug 2022 10:18:37 +0200 Subject: [PATCH 042/191] New empty devices list screen --- .../v2/VectorSettingsDevicesFragment.kt | 49 +++++++++++++++++++ .../res/layout/fragment_settings_devices.xml | 5 ++ vector/src/main/res/values/strings.xml | 1 + .../xml/vector_settings_security_privacy.xml | 2 +- 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt create mode 100644 vector/src/main/res/layout/fragment_settings_devices.xml diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt new file mode 100644 index 0000000000..0d5dedacc9 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2022 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.settings.devices.v2 + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.R +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentSettingsDevicesBinding +import javax.inject.Inject + +/** + * Display the list of the user's devices and sessions. + */ +@AndroidEntryPoint +class VectorSettingsDevicesFragment @Inject constructor() : VectorBaseFragment() { + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSettingsDevicesBinding { + return FragmentSettingsDevicesBinding.inflate(inflater, container, false) + } + + override fun onAttach(context: Context) { + super.onAttach(context) + initToolbar() + } + + private fun initToolbar() { + (activity as? AppCompatActivity) + ?.supportActionBar + ?.setTitle(R.string.settings_sessions_list) + } +} diff --git a/vector/src/main/res/layout/fragment_settings_devices.xml b/vector/src/main/res/layout/fragment_settings_devices.xml new file mode 100644 index 0000000000..2a77219ad0 --- /dev/null +++ b/vector/src/main/res/layout/fragment_settings_devices.xml @@ -0,0 +1,5 @@ + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 9fc9756897..7c01eed715 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -2336,6 +2336,7 @@ Show All Sessions Manage Sessions Sign out of this session + Sessions Server name Server version diff --git a/vector/src/main/res/xml/vector_settings_security_privacy.xml b/vector/src/main/res/xml/vector_settings_security_privacy.xml index d3493fd984..b5b21bc017 100644 --- a/vector/src/main/res/xml/vector_settings_security_privacy.xml +++ b/vector/src/main/res/xml/vector_settings_security_privacy.xml @@ -65,7 +65,7 @@ + app:fragment="im.vector.app.features.settings.devices.v2.VectorSettingsDevicesFragment" /> From ed00685514d734afd80b833cc0f0d89f4695b9ad Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 10 Aug 2022 10:39:27 +0200 Subject: [PATCH 043/191] Adding changelog entry --- changelog.d/6798.wip | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6798.wip diff --git a/changelog.d/6798.wip b/changelog.d/6798.wip new file mode 100644 index 0000000000..a16270666b --- /dev/null +++ b/changelog.d/6798.wip @@ -0,0 +1 @@ +[Devices management] Add a feature flag and empty screen for future new layout From b9fa4ddfc8dbdfad7afb50cba4eb8d3e08fa60b6 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 10 Aug 2022 10:53:34 +0200 Subject: [PATCH 044/191] Renaming v2 setting key --- .../vector/app/features/settings/VectorPreferences.kt | 2 +- .../settings/VectorSettingsSecurityPrivacyFragment.kt | 10 +++++----- .../main/res/xml/vector_settings_security_privacy.xml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) 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 0134fc581b..857d2ce7fb 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 @@ -74,7 +74,7 @@ class VectorPreferences @Inject constructor( const val SETTINGS_ENCRYPTION_IMPORT_E2E_ROOM_KEYS_PREFERENCE_KEY = "SETTINGS_ENCRYPTION_IMPORT_E2E_ROOM_KEYS_PREFERENCE_KEY" const val SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY = "SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY" const val SETTINGS_SHOW_DEVICES_LIST_PREFERENCE_KEY = "SETTINGS_SHOW_DEVICES_LIST_PREFERENCE_KEY" - const val SETTINGS_SHOW_DEVICES_V2_LIST_PREFERENCE_KEY = "SETTINGS_SHOW_DEVICES_V2_LIST_PREFERENCE_KEY" + const val SETTINGS_SHOW_DEVICES_LIST_V2_PREFERENCE_KEY = "SETTINGS_SHOW_DEVICES_LIST_V2_PREFERENCE_KEY" const val SETTINGS_ALLOW_INTEGRATIONS_KEY = "SETTINGS_ALLOW_INTEGRATIONS_KEY" const val SETTINGS_INTEGRATION_MANAGER_UI_URL_KEY = "SETTINGS_INTEGRATION_MANAGER_UI_URL_KEY" const val SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY = "SETTINGS_SECURE_MESSAGE_RECOVERY_PREFERENCE_KEY" diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt index 023bb9e03f..24ad4e55ab 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -137,8 +137,8 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( findPreference(VectorPreferences.SETTINGS_SHOW_DEVICES_LIST_PREFERENCE_KEY)!! } - private val showDevicesV2ListPref by lazy { - findPreference(VectorPreferences.SETTINGS_SHOW_DEVICES_V2_LIST_PREFERENCE_KEY)!! + private val showDevicesListV2Pref by lazy { + findPreference(VectorPreferences.SETTINGS_SHOW_DEVICES_LIST_V2_PREFERENCE_KEY)!! } // encrypt to unverified devices @@ -552,9 +552,9 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( showDeviceListPref.isEnabled = devices.isNotEmpty() showDeviceListPref.summary = resources.getQuantityString(R.plurals.settings_active_sessions_count, devices.size, devices.size) - showDevicesV2ListPref.isVisible = vectorFeatures.isNewDeviceManagementEnabled() - showDevicesV2ListPref.title = showDeviceListPref.title.toString() + " (V2, WIP)" - showDevicesV2ListPref.summary = resources.getQuantityString(R.plurals.settings_active_sessions_count, devices.size, devices.size) + showDevicesListV2Pref.isVisible = vectorFeatures.isNewDeviceManagementEnabled() + showDevicesListV2Pref.title = showDeviceListPref.title.toString() + " (V2, WIP)" + showDevicesListV2Pref.summary = resources.getQuantityString(R.plurals.settings_active_sessions_count, devices.size, devices.size) val userId = session.myUserId val deviceId = session.sessionParams.deviceId diff --git a/vector/src/main/res/xml/vector_settings_security_privacy.xml b/vector/src/main/res/xml/vector_settings_security_privacy.xml index b5b21bc017..c246a40f71 100644 --- a/vector/src/main/res/xml/vector_settings_security_privacy.xml +++ b/vector/src/main/res/xml/vector_settings_security_privacy.xml @@ -63,7 +63,7 @@ app:fragment="im.vector.app.features.settings.devices.VectorSettingsDevicesFragment" /> From c0c0f90b042f3da543de0df600a76effcd583034 Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Wed, 10 Aug 2022 11:26:25 +0200 Subject: [PATCH 045/191] Adds NewChatBottomSheet --- .../room/list/home/HomeRoomListFragment.kt | 4 +- .../home/room/list/home/NewChatBottomSheet.kt | 38 +++++++++++++++++++ .../layout/fragment_new_chat_bottom_sheet.xml | 27 +++++++++++++ vector/src/main/res/values/strings.xml | 2 + 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 vector/src/main/java/im/vector/app/features/home/room/list/home/NewChatBottomSheet.kt create mode 100644 vector/src/main/res/layout/fragment_new_chat_bottom_sheet.xml diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt index 43a6f25841..0c9cb3136e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListFragment.kt @@ -68,6 +68,8 @@ class HomeRoomListFragment @Inject constructor( private lateinit var stateRestorer: LayoutManagerStateRestorer + private val newChatBottomSheet = NewChatBottomSheet() + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentRoomListBinding { return FragmentRoomListBinding.inflate(inflater, container, false) } @@ -117,7 +119,7 @@ class HomeRoomListFragment @Inject constructor( showFABs() views.newLayoutCreateChatButton.setOnClickListener { - // Click action for create chat modal goes here (Issue #6717) + newChatBottomSheet.show(requireActivity().supportFragmentManager, NewChatBottomSheet.TAG) } views.newLayoutOpenSpacesButton.setOnClickListener { diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/NewChatBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/NewChatBottomSheet.kt new file mode 100644 index 0000000000..836346e40e --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/NewChatBottomSheet.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 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.home.room.list.home + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import im.vector.app.databinding.FragmentNewChatBottomSheetBinding + +class NewChatBottomSheet : BottomSheetDialogFragment() { + + private lateinit var binding: FragmentNewChatBottomSheetBinding + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + binding = FragmentNewChatBottomSheetBinding.inflate(inflater, container, false) + return binding.root + } + + companion object { + const val TAG = "NewChatBottomSheet" + } +} diff --git a/vector/src/main/res/layout/fragment_new_chat_bottom_sheet.xml b/vector/src/main/res/layout/fragment_new_chat_bottom_sheet.xml new file mode 100644 index 0000000000..8cfd4b3f31 --- /dev/null +++ b/vector/src/main/res/layout/fragment_new_chat_bottom_sheet.xml @@ -0,0 +1,27 @@ + + + + + + + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 9fc9756897..9ea90a07d4 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -137,6 +137,8 @@ All Chats + Start chat + Create room From fd37b31c4482868ee7d23f8f25c622258b79f03c Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Wed, 10 Aug 2022 11:28:14 +0200 Subject: [PATCH 046/191] Changes changelog file extension --- changelog.d/{6749.feature => 6749.wip} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog.d/{6749.feature => 6749.wip} (100%) diff --git a/changelog.d/6749.feature b/changelog.d/6749.wip similarity index 100% rename from changelog.d/6749.feature rename to changelog.d/6749.wip From 527bcf2e6fee6ecb64e86749c8166ddeac04844a Mon Sep 17 00:00:00 2001 From: ericdecanini Date: Wed, 10 Aug 2022 11:30:15 +0200 Subject: [PATCH 047/191] Adds changelog file --- changelog.d/6795.wip | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6795.wip diff --git a/changelog.d/6795.wip b/changelog.d/6795.wip new file mode 100644 index 0000000000..da525a2c67 --- /dev/null +++ b/changelog.d/6795.wip @@ -0,0 +1 @@ +Makes toolbar switch title based on space in New App Layout From defd848363c35b9394f3cf503bf17a01d173cd7d Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 10 Aug 2022 12:30:38 +0100 Subject: [PATCH 048/191] updating version for next release cycle --- matrix-sdk-android/build.gradle | 2 +- vector/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 45a962f12c..e6b526585b 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -60,7 +60,7 @@ android { // that the app's state is completely cleared between tests. testInstrumentationRunnerArguments clearPackageData: 'true' - buildConfigField "String", "SDK_VERSION", "\"1.4.32\"" + buildConfigField "String", "SDK_VERSION", "\"1.4.34\"" buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\"" buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\"" diff --git a/vector/build.gradle b/vector/build.gradle index e5bd835a8f..cb7ee67a6a 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -37,7 +37,7 @@ ext.versionMinor = 4 // Note: even values are reserved for regular release, odd values for hotfix release. // When creating a hotfix, you should decrease the value, since the current value // is the value for the next regular release. -ext.versionPatch = 32 +ext.versionPatch = 34 static def getGitTimestamp() { def cmd = 'git show -s --format=%ct' From aecf460c96b3a56603c6410ccd6f522c521ae998 Mon Sep 17 00:00:00 2001 From: Jorge Martin Espinosa Date: Wed, 10 Aug 2022 14:00:36 +0200 Subject: [PATCH 049/191] Improve tests for lockscreen (#6796) * Improve tests * Address review comments. * Refactor pin code tests and code to improve testability. * Fix lint issues --- .../pin/lockscreen/ui/LockScreenViewModel.kt | 19 +- .../pin/lockscreen/ui/LockScreenViewState.kt | 4 +- .../fragment/LockScreenViewModelTests.kt | 218 +++++++++++------- .../java/im/vector/app/test/Extensions.kt | 5 + .../im/vector/app/test/FlowTestObserver.kt | 10 +- 5 files changed, 155 insertions(+), 101 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/LockScreenViewModel.kt b/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/LockScreenViewModel.kt index d40f67ea35..33ea590f1d 100644 --- a/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/LockScreenViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/LockScreenViewModel.kt @@ -64,8 +64,6 @@ class LockScreenViewModel @AssistedInject constructor( private val biometricHelper = biometricHelperFactory.create(initialState.lockScreenConfiguration) - private var firstEnteredCode: String? = null - // BiometricPrompt will automatically disable system auth after too many failed auth attempts private var isSystemAuthTemporarilyDisabledByBiometricPrompt = false @@ -108,18 +106,17 @@ class LockScreenViewModel @AssistedInject constructor( val state = awaitState() when (state.lockScreenConfiguration.mode) { LockScreenMode.CREATE -> { - if (firstEnteredCode == null && state.lockScreenConfiguration.needsNewCodeValidation) { - firstEnteredCode = code - _viewEvents.post(LockScreenViewEvent.ClearPinCode(false)) - emit(PinCodeState.FirstCodeEntered) + val enteredPinCode = (state.pinCodeState as? PinCodeState.FirstCodeEntered)?.pinCode + if (enteredPinCode == null && state.lockScreenConfiguration.needsNewCodeValidation) { + _viewEvents.post(LockScreenViewEvent.ClearPinCode(confirmationFailed = false)) + emit(PinCodeState.FirstCodeEntered(code)) } else { - if (!state.lockScreenConfiguration.needsNewCodeValidation || code == firstEnteredCode) { + if (!state.lockScreenConfiguration.needsNewCodeValidation || code == enteredPinCode) { pinCodeHelper.createPinCode(code) _viewEvents.post(LockScreenViewEvent.CodeCreationComplete) emit(null) } else { - firstEnteredCode = null - _viewEvents.post(LockScreenViewEvent.ClearPinCode(true)) + _viewEvents.post(LockScreenViewEvent.ClearPinCode(confirmationFailed = true)) emit(PinCodeState.Idle) } } @@ -137,7 +134,9 @@ class LockScreenViewModel @AssistedInject constructor( }.catch { error -> _viewEvents.post(LockScreenViewEvent.AuthError(AuthMethod.PIN_CODE, error)) }.onEach { newPinState -> - newPinState?.let { setState { copy(pinCodeState = it) } } + if (newPinState != null) { + setState { copy(pinCodeState = newPinState) } + } }.launchIn(viewModelScope) @SuppressLint("NewApi") diff --git a/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/LockScreenViewState.kt b/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/LockScreenViewState.kt index f689e1faf1..c6c6359f4f 100644 --- a/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/LockScreenViewState.kt +++ b/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/LockScreenViewState.kt @@ -27,11 +27,11 @@ data class LockScreenViewState( val isBiometricKeyInvalidated: Boolean, ) : MavericksState { constructor(lockScreenConfiguration: LockScreenConfiguration) : this( - lockScreenConfiguration, false, false, PinCodeState.Idle, false + lockScreenConfiguration, false, false, PinCodeState.Idle, false, ) } sealed class PinCodeState { object Idle : PinCodeState() - object FirstCodeEntered : PinCodeState() + data class FirstCodeEntered(val pinCode: String) : PinCodeState() } diff --git a/vector/src/test/java/im/vector/app/features/pin/lockscreen/fragment/LockScreenViewModelTests.kt b/vector/src/test/java/im/vector/app/features/pin/lockscreen/fragment/LockScreenViewModelTests.kt index 18dfdf9145..6037d9933e 100644 --- a/vector/src/test/java/im/vector/app/features/pin/lockscreen/fragment/LockScreenViewModelTests.kt +++ b/vector/src/test/java/im/vector/app/features/pin/lockscreen/fragment/LockScreenViewModelTests.kt @@ -19,9 +19,11 @@ package im.vector.app.features.pin.lockscreen.fragment import android.app.KeyguardManager import android.os.Build import android.security.keystore.KeyPermanentlyInvalidatedException +import androidx.biometric.BiometricPrompt import androidx.fragment.app.FragmentActivity import com.airbnb.mvrx.test.MvRxTestRule import com.airbnb.mvrx.withState +import im.vector.app.features.pin.lockscreen.biometrics.BiometricAuthError import im.vector.app.features.pin.lockscreen.biometrics.BiometricHelper import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguration import im.vector.app.features.pin.lockscreen.configuration.LockScreenMode @@ -42,10 +44,8 @@ import io.mockk.every import io.mockk.mockk import io.mockk.verify import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest -import org.amshove.kluent.shouldBeEqualTo -import org.amshove.kluent.shouldBeFalse +import org.amshove.kluent.shouldBeTrue import org.amshove.kluent.shouldNotBeEqualTo import org.junit.Before import org.junit.Rule @@ -76,138 +76,141 @@ class LockScreenViewModelTests { @Test fun `init migrates old keys to new ones if needed`() { + // given val initialState = createViewState() + // when LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) - + // then coVerify { keysMigrator.migrateIfNeeded() } } @Test fun `init updates the initial state with biometric info`() = runTest { + // given every { biometricHelper.isSystemAuthEnabledAndValid } returns true val initialState = createViewState() + // when val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) - advanceUntilIdle() - val newState = viewModel.awaitState() + // then + val newState = viewModel.awaitState() // Can't use viewModel.test() here since we want to record events emitted on init newState shouldNotBeEqualTo initialState } @Test fun `Updating the initial state with biometric info waits until device is unlocked on Android 12+`() = runTest { + // given val initialState = createViewState() versionProvider.value = Build.VERSION_CODES.S + // when LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) - advanceUntilIdle() + // then verify { keyguardManager.isDeviceLocked } } @Test fun `when ViewModel is instantiated initialState is updated with biometric info`() { + // given + givenShowBiometricPromptAutomatically() val initialState = createViewState() - // This should set canUseBiometricAuth to true - every { biometricHelper.isSystemAuthEnabledAndValid } returns true + // when val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) - val newState = withState(viewModel) { it } - initialState shouldNotBeEqualTo newState + // then + withState(viewModel) { newState -> + initialState shouldNotBeEqualTo newState + } } @Test - fun `when onPinCodeEntered is called in VERIFY mode, the code is verified and the result is emitted as a ViewEvent`() = runTest { + fun `when onPinCodeEntered is called in VERIFY mode and verification is successful, code is verified and result is emitted as a ViewEvent`() = runTest { + // given val initialState = createViewState() val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) coEvery { pinCodeHelper.verifyPinCode(any()) } returns true - - val events = viewModel.test().viewEvents - events.assertNoValues() - - val stateBefore = viewModel.awaitState() - + val test = viewModel.test() + // when viewModel.handle(LockScreenAction.PinCodeEntered("1234")) + // then coVerify { pinCodeHelper.verifyPinCode(any()) } - events.assertValues(LockScreenViewEvent.AuthSuccessful(AuthMethod.PIN_CODE)) + test.assertEvents(LockScreenViewEvent.AuthSuccessful(AuthMethod.PIN_CODE)) + test.assertStates(initialState) + } + @Test + fun `when onPinCodeEntered is called in VERIFY mode and verification fails, the error result is emitted as a ViewEvent`() = runTest { + // given + val initialState = createViewState() + val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) coEvery { pinCodeHelper.verifyPinCode(any()) } returns false + val test = viewModel.test() + // when viewModel.handle(LockScreenAction.PinCodeEntered("1234")) - events.assertValues(LockScreenViewEvent.AuthSuccessful(AuthMethod.PIN_CODE), LockScreenViewEvent.AuthFailure(AuthMethod.PIN_CODE)) - - val stateAfter = viewModel.awaitState() - stateBefore shouldBeEqualTo stateAfter + // then + coVerify { pinCodeHelper.verifyPinCode(any()) } + test.assertEvents(LockScreenViewEvent.AuthFailure(AuthMethod.PIN_CODE)) + test.assertStates(initialState) } @Test fun `when onPinCodeEntered is called in CREATE mode with no confirmation needed it creates the pin code`() = runTest { + // given val configuration = createDefaultConfiguration(mode = LockScreenMode.CREATE, needsNewCodeValidation = false) val initialState = createViewState(lockScreenConfiguration = configuration) val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) - - val events = viewModel.test().viewEvents - events.assertNoValues() - + val test = viewModel.test() + // when viewModel.handle(LockScreenAction.PinCodeEntered("1234")) + // then coVerify { pinCodeHelper.createPinCode(any()) } - - events.assertValues(LockScreenViewEvent.CodeCreationComplete) + test.assertEvents(LockScreenViewEvent.CodeCreationComplete) } @Test fun `when onPinCodeEntered is called twice in CREATE mode with confirmation needed it verifies and creates the pin code`() = runTest { + // given + val pinCode = "1234" val configuration = createDefaultConfiguration(mode = LockScreenMode.CREATE, needsNewCodeValidation = true) - val initialState = createViewState(lockScreenConfiguration = configuration) + val initialState = createViewState(lockScreenConfiguration = configuration, pinCodeState = PinCodeState.FirstCodeEntered(pinCode)) val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) - - val events = viewModel.test().viewEvents - events.assertNoValues() - - viewModel.handle(LockScreenAction.PinCodeEntered("1234")) - - events.assertValues(LockScreenViewEvent.ClearPinCode(false)) - val pinCodeState = viewModel.awaitState().pinCodeState - pinCodeState shouldBeEqualTo PinCodeState.FirstCodeEntered - - viewModel.handle(LockScreenAction.PinCodeEntered("1234")) - events.assertValues(LockScreenViewEvent.ClearPinCode(false), LockScreenViewEvent.CodeCreationComplete) + val test = viewModel.test() + // when + viewModel.handle(LockScreenAction.PinCodeEntered(pinCode)) + // then + test.assertEvents(LockScreenViewEvent.CodeCreationComplete) + .assertLatestState { (it.pinCodeState as? PinCodeState.FirstCodeEntered)?.pinCode == pinCode } } @Test fun `when onPinCodeEntered is called in CREATE mode with incorrect confirmation it clears the pin code`() = runTest { + // given val configuration = createDefaultConfiguration(mode = LockScreenMode.CREATE, needsNewCodeValidation = true) - val initialState = createViewState(lockScreenConfiguration = configuration) + val initialState = createViewState(lockScreenConfiguration = configuration, pinCodeState = PinCodeState.FirstCodeEntered("1234")) val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) - - val events = viewModel.test().viewEvents - events.assertNoValues() - - viewModel.handle(LockScreenAction.PinCodeEntered("1234")) - - events.assertValues(LockScreenViewEvent.ClearPinCode(false)) - val pinCodeState = viewModel.awaitState().pinCodeState - pinCodeState shouldBeEqualTo PinCodeState.FirstCodeEntered - + val test = viewModel.test() + // when viewModel.handle(LockScreenAction.PinCodeEntered("4321")) - events.assertValues(LockScreenViewEvent.ClearPinCode(false), LockScreenViewEvent.ClearPinCode(true)) - val newPinCodeState = viewModel.awaitState().pinCodeState - newPinCodeState shouldBeEqualTo PinCodeState.Idle + // then + test.assertEvents(LockScreenViewEvent.ClearPinCode(true)) + .assertLatestState(initialState.copy(pinCodeState = PinCodeState.Idle)) } @Test fun `onPinCodeEntered handles exceptions`() = runTest { + // given val initialState = createViewState() val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) val exception = IllegalStateException("Something went wrong") coEvery { pinCodeHelper.verifyPinCode(any()) } throws exception - - val events = viewModel.test().viewEvents - events.assertNoValues() - + val test = viewModel.test() + // when viewModel.handle(LockScreenAction.PinCodeEntered("1234")) - - events.assertValues(LockScreenViewEvent.AuthError(AuthMethod.PIN_CODE, exception)) + // then + test.assertEvents(LockScreenViewEvent.AuthError(AuthMethod.PIN_CODE, exception)) } @Test fun `when showBiometricPrompt catches a KeyPermanentlyInvalidatedException it disables biometric authentication`() = runTest { + // given versionProvider.value = Build.VERSION_CODES.M - every { biometricHelper.isSystemKeyValid } returns false val exception = KeyPermanentlyInvalidatedException() coEvery { biometricHelper.authenticate(any()) } throws exception @@ -218,49 +221,81 @@ class LockScreenViewModelTests { lockScreenConfiguration = configuration ) val viewModel = LockScreenViewModel(initialState, pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) - - val events = viewModel.test().viewEvents - events.assertNoValues() - + val test = viewModel.test() + // when viewModel.handle(LockScreenAction.ShowBiometricPrompt(mockk())) - - events.assertValues(LockScreenViewEvent.ShowBiometricKeyInvalidatedMessage) + // then + test.assertEvents(LockScreenViewEvent.ShowBiometricKeyInvalidatedMessage) + // Biometric key is invalidated so biometric auth is disabled + .assertLatestState { !it.canUseBiometricAuth } verify { biometricHelper.disableAuthentication() } - - // System key was deleted, biometric auth should be disabled - every { biometricHelper.isSystemAuthEnabledAndValid } returns false - val newState = viewModel.awaitState() - newState.canUseBiometricAuth.shouldBeFalse() } @Test fun `when showBiometricPrompt receives an event it propagates it as a ViewEvent`() = runTest { + // given val viewModel = LockScreenViewModel(createViewState(), pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) coEvery { biometricHelper.authenticate(any()) } returns flowOf(false, true) - - val events = viewModel.test().viewEvents - events.assertNoValues() - + val test = viewModel.test() + // when viewModel.handle(LockScreenAction.ShowBiometricPrompt(mockk())) - - events.assertValues(LockScreenViewEvent.AuthFailure(AuthMethod.BIOMETRICS), LockScreenViewEvent.AuthSuccessful(AuthMethod.BIOMETRICS)) + // then + test.assertEvents(LockScreenViewEvent.AuthFailure(AuthMethod.BIOMETRICS), LockScreenViewEvent.AuthSuccessful(AuthMethod.BIOMETRICS)) } @Test fun `showBiometricPrompt handles exceptions`() = runTest { + // given val viewModel = LockScreenViewModel(createViewState(), pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) val exception = IllegalStateException("Something went wrong") coEvery { biometricHelper.authenticate(any()) } throws exception - - val events = viewModel.test().viewEvents - events.assertNoValues() - + val test = viewModel.test() + // when viewModel.handle(LockScreenAction.ShowBiometricPrompt(mockk())) - - events.assertValues(LockScreenViewEvent.AuthError(AuthMethod.BIOMETRICS, exception)) + // then + test.assertEvents(LockScreenViewEvent.AuthError(AuthMethod.BIOMETRICS, exception)) } - private fun createViewState( + @Test + fun `when showBiometricPrompt handles isAuthDisabledError, canUseBiometricAuth becomes false`() = runTest { + // given + val viewModel = LockScreenViewModel(createViewState(), pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) + val exception = BiometricAuthError(BiometricPrompt.ERROR_LOCKOUT_PERMANENT, "Permanent lockout") + coEvery { biometricHelper.authenticate(any()) } throws exception + val test = viewModel.test() + // when + viewModel.handle(LockScreenAction.ShowBiometricPrompt(mockk())) + // then + exception.isAuthDisabledError.shouldBeTrue() + test.assertEvents(LockScreenViewEvent.AuthError(AuthMethod.BIOMETRICS, exception)) + .assertLatestState { !it.canUseBiometricAuth } + } + + @Test + fun `when OnUIReady action is received and showBiometricPromptAutomatically is true it shows prompt`() = runTest { + // given + givenShowBiometricPromptAutomatically() + val viewModel = LockScreenViewModel(createViewState(), pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) + val test = viewModel.test() + // when + viewModel.handle(LockScreenAction.OnUIReady) + // then + test.assertEvents(LockScreenViewEvent.ShowBiometricPromptAutomatically) + } + + @Test + fun `when OnUIReady action is received and isBiometricKeyInvalidated is true it shows prompt`() = runTest { + // given + givenBiometricKeyIsInvalidated() + val viewModel = LockScreenViewModel(createViewState(), pinCodeHelper, biometricHelperFactory, keysMigrator, versionProvider, keyguardManager) + val test = viewModel.test() + // when + viewModel.handle(LockScreenAction.OnUIReady) + // then + test.assertEvents(LockScreenViewEvent.ShowBiometricKeyInvalidatedMessage) + } + + private fun createViewState( lockScreenConfiguration: LockScreenConfiguration = createDefaultConfiguration(), canUseBiometricAuth: Boolean = false, showBiometricPromptAutomatically: Boolean = false, @@ -286,4 +321,13 @@ class LockScreenViewModelTests { isDeviceCredentialUnlockEnabled, needsNewCodeValidation ).let(otherChanges) + + private fun givenBiometricKeyIsInvalidated() { + every { biometricHelper.hasSystemKey } returns true + every { biometricHelper.isSystemKeyValid } returns false + } + + private fun givenShowBiometricPromptAutomatically() { + every { biometricHelper.isSystemAuthEnabledAndValid } returns true + } } diff --git a/vector/src/test/java/im/vector/app/test/Extensions.kt b/vector/src/test/java/im/vector/app/test/Extensions.kt index 5ac17cc5ff..2fbab3b71b 100644 --- a/vector/src/test/java/im/vector/app/test/Extensions.kt +++ b/vector/src/test/java/im/vector/app/test/Extensions.kt @@ -91,6 +91,11 @@ class ViewModelTest( return this } + fun assertLatestState(predicate: (S) -> Boolean): ViewModelTest { + states.assertLatestValue(predicate) + return this + } + fun finish() { states.finish() viewEvents.finish() diff --git a/vector/src/test/java/im/vector/app/test/FlowTestObserver.kt b/vector/src/test/java/im/vector/app/test/FlowTestObserver.kt index db828be232..ce8d27cd2a 100644 --- a/vector/src/test/java/im/vector/app/test/FlowTestObserver.kt +++ b/vector/src/test/java/im/vector/app/test/FlowTestObserver.kt @@ -47,8 +47,14 @@ class FlowTestObserver( return this } - fun assertLatestValue(value: T) { - assertTrue(values.last() == value) + fun assertLatestValue(predicate: (T) -> Boolean): FlowTestObserver { + assertTrue(predicate(values.last())) + return this + } + + fun assertLatestValue(value: T): FlowTestObserver { + assertEquals(value, values.last()) + return this } fun assertValues(values: List): FlowTestObserver { From 31a350eea70ede920002e310c2506a14e5648da4 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 27 Jul 2022 16:36:16 +0200 Subject: [PATCH 050/191] Enabling leakcanary on debug builds --- dependencies_groups.gradle | 2 ++ vector/build.gradle | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle index f60a77a92d..1c0135ae0f 100644 --- a/dependencies_groups.gradle +++ b/dependencies_groups.gradle @@ -106,7 +106,9 @@ ext.groups = [ 'com.pinterest.ktlint', 'com.posthog.android', 'com.squareup', + 'com.squareup.curtains', 'com.squareup.duktape', + 'com.squareup.leakcanary', 'com.squareup.moshi', 'com.squareup.okhttp3', 'com.squareup.okio', diff --git a/vector/build.gradle b/vector/build.gradle index 1244a84bfd..ee08ad7ae5 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -573,7 +573,7 @@ dependencies { debugImplementation "com.kgurgul.flipper:flipper-realm-android:2.2.0" // Activate when you want to check for leaks, from time to time. - //debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3' + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1' androidTestImplementation libs.androidx.testCore androidTestImplementation libs.androidx.testRunner From 36c69a46fdb9d3f9880b3890b779125d045eca04 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 8 Aug 2022 17:52:58 +0200 Subject: [PATCH 051/191] Adding way to enable leak canary at runtime --- .../vector/app/leakcanary/LeakCanaryProxy.kt | 26 ++++++++++++++++++ .../java/im/vector/app/VectorApplication.kt | 9 +++++++ .../im/vector/app/core/di/FragmentModule.kt | 6 +++++ .../features/settings/VectorPreferences.kt | 6 +++++ .../VectorSettingsAdvancedSettingsFragment.kt | 19 ++++++++++++- vector/src/main/res/values/strings.xml | 3 +++ .../xml/vector_settings_advanced_settings.xml | 9 ++++++- .../vector/app/leakcanary/LeakCanaryProxy.kt | 27 +++++++++++++++++++ 8 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 vector/src/debug/java/im/vector/app/leakcanary/LeakCanaryProxy.kt create mode 100644 vector/src/release/java/im/vector/app/leakcanary/LeakCanaryProxy.kt diff --git a/vector/src/debug/java/im/vector/app/leakcanary/LeakCanaryProxy.kt b/vector/src/debug/java/im/vector/app/leakcanary/LeakCanaryProxy.kt new file mode 100644 index 0000000000..3154c2c04b --- /dev/null +++ b/vector/src/debug/java/im/vector/app/leakcanary/LeakCanaryProxy.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2022 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.leakcanary + +import leakcanary.LeakCanary +import javax.inject.Inject + +class LeakCanaryProxy @Inject constructor() { + fun enable(enable: Boolean) { + LeakCanary.config = LeakCanary.config.copy(dumpHeap = enable) + } +} diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index 53222ab962..bbff8f35c8 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -61,6 +61,8 @@ import im.vector.app.features.settings.VectorLocale import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.version.VersionProvider +import im.vector.app.leakcanary.LeakCanaryProxy +import im.vector.app.push.fcm.FcmHelper import org.jitsi.meet.sdk.log.JitsiMeetDefaultLogHandler import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.auth.AuthenticationService @@ -102,6 +104,7 @@ class VectorApplication : @Inject lateinit var matrix: Matrix @Inject lateinit var fcmHelper: FcmHelper @Inject lateinit var buildMeta: BuildMeta + @Inject lateinit var leakCanaryProxy: LeakCanaryProxy // font thread handler private var fontThreadHandler: Handler? = null @@ -196,6 +199,8 @@ class VectorApplication : // Initialize Mapbox before inflating mapViews Mapbox.getInstance(this) + + initMemoryLeakAnalysis() } private fun enableStrictModeIfNeeded() { @@ -251,4 +256,8 @@ class VectorApplication : handlerThread.start() return Handler(handlerThread.looper) } + + private fun initMemoryLeakAnalysis() { + leakCanaryProxy.enable(vectorPreferences.isMemoryLeakAnalysisEnabled()) + } } diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt index e86b350534..36b1d994c1 100644 --- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt @@ -150,6 +150,7 @@ import im.vector.app.features.roomprofile.settings.joinrule.advanced.RoomJoinRul import im.vector.app.features.roomprofile.uploads.RoomUploadsFragment import im.vector.app.features.roomprofile.uploads.files.RoomUploadsFilesFragment import im.vector.app.features.roomprofile.uploads.media.RoomUploadsMediaFragment +import im.vector.app.features.settings.VectorSettingsAdvancedSettingsFragment import im.vector.app.features.settings.VectorSettingsGeneralFragment import im.vector.app.features.settings.VectorSettingsHelpAboutFragment import im.vector.app.features.settings.VectorSettingsLabsFragment @@ -624,6 +625,11 @@ interface FragmentModule { @FragmentKey(VectorSettingsSecurityPrivacyFragment::class) fun bindVectorSettingsSecurityPrivacyFragment(fragment: VectorSettingsSecurityPrivacyFragment): Fragment + @Binds + @IntoMap + @FragmentKey(VectorSettingsAdvancedSettingsFragment::class) + fun bindVectorSettingsAdvancedSettingsFragment(fragment: VectorSettingsAdvancedSettingsFragment): Fragment + @Binds @IntoMap @FragmentKey(VectorSettingsHelpAboutFragment::class) 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 ac14bfc3c7..287b2c64ee 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 @@ -168,6 +168,7 @@ class VectorPreferences @Inject constructor( private const val SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY = "SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY" private const val SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY = "SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY" private const val SETTINGS_DEVELOPER_MODE_SHOW_INFO_ON_SCREEN_KEY = "SETTINGS_DEVELOPER_MODE_SHOW_INFO_ON_SCREEN_KEY" + const val SETTINGS_ENABLE_MEMORY_LEAK_ANALYSIS_KEY = "SETTINGS_ENABLE_MEMORY_LEAK_ANALYSIS_KEY" const val SETTINGS_LABS_MSC3061_SHARE_KEYS_HISTORY = "SETTINGS_LABS_MSC3061_SHARE_KEYS_HISTORY" @@ -268,6 +269,7 @@ class VectorPreferences @Inject constructor( SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY, SETTINGS_LABS_ALLOW_EXTENDED_LOGS, SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY, + SETTINGS_ENABLE_MEMORY_LEAK_ANALYSIS_KEY, SETTINGS_USE_RAGE_SHAKE_KEY, SETTINGS_SECURITY_USE_FLAG_SECURE, @@ -368,6 +370,10 @@ class VectorPreferences @Inject constructor( return buildMeta.isDebug || (developerMode() && defaultPrefs.getBoolean(SETTINGS_DEVELOPER_MODE_FAIL_FAST_PREFERENCE_KEY, false)) } + fun isMemoryLeakAnalysisEnabled(): Boolean { + return buildMeta.isDebug && developerMode() && defaultPrefs.getBoolean(SETTINGS_ENABLE_MEMORY_LEAK_ANALYSIS_KEY, false) + } + fun didAskUserToEnableSessionPush(): Boolean { return defaultPrefs.getBoolean(DID_ASK_TO_ENABLE_SESSION_PUSH, false) } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt index b616ce1e1f..1bb7718390 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsAdvancedSettingsFragment.kt @@ -19,14 +19,19 @@ package im.vector.app.features.settings import android.os.Bundle import androidx.preference.Preference import androidx.preference.SeekBarPreference +import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.preference.VectorPreferenceCategory import im.vector.app.core.preference.VectorSwitchPreference import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.rageshake.RageShake +import im.vector.app.leakcanary.LeakCanaryProxy +import javax.inject.Inject -class VectorSettingsAdvancedSettingsFragment : VectorSettingsBaseFragment() { +class VectorSettingsAdvancedSettingsFragment @Inject constructor( + private val leakCanaryProxy: LeakCanaryProxy, +) : VectorSettingsBaseFragment() { override var titleRes = R.string.settings_advanced_settings override val preferenceXmlRes = R.xml.vector_settings_advanced_settings @@ -82,5 +87,17 @@ class VectorSettingsAdvancedSettingsFragment : VectorSettingsBaseFragment() { } else { findPreference("SETTINGS_RAGE_SHAKE_CATEGORY_KEY")!!.isVisible = false } + + bindMemoryLeakSetting() + } + + private fun bindMemoryLeakSetting() { + findPreference(VectorPreferences.SETTINGS_ENABLE_MEMORY_LEAK_ANALYSIS_KEY)?.let { pref -> + pref.isVisible = BuildConfig.DEBUG + pref.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + leakCanaryProxy.enable(newValue as? Boolean ?: false) + true + } + } } } diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index d1b2d237d9..1b21642e04 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -2185,6 +2185,9 @@ ${app_name} may crash more often when an unexpected error occurs + Enable memory leak analysis + App performances may be impacted when enabled. + Show debug info on screen Show some useful info to help debugging the application diff --git a/vector/src/main/res/xml/vector_settings_advanced_settings.xml b/vector/src/main/res/xml/vector_settings_advanced_settings.xml index 2fb3fae310..c076fc2238 100644 --- a/vector/src/main/res/xml/vector_settings_advanced_settings.xml +++ b/vector/src/main/res/xml/vector_settings_advanced_settings.xml @@ -44,6 +44,13 @@ android:summary="@string/settings_developer_mode_fail_fast_summary" android:title="@string/settings_developer_mode_fail_fast_title" /> + + - \ No newline at end of file + diff --git a/vector/src/release/java/im/vector/app/leakcanary/LeakCanaryProxy.kt b/vector/src/release/java/im/vector/app/leakcanary/LeakCanaryProxy.kt new file mode 100644 index 0000000000..28c9f1c9d5 --- /dev/null +++ b/vector/src/release/java/im/vector/app/leakcanary/LeakCanaryProxy.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 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.leakcanary + +import javax.inject.Inject + +/** + * No op version. + */ +@Suppress("UNUSED_PARAMETER") +class LeakCanaryProxy @Inject constructor() { + fun enable(enable: Boolean) {} +} From 12405527e14b010123aa98977be515410ce583c5 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Tue, 9 Aug 2022 16:16:55 +0200 Subject: [PATCH 052/191] Adding changelog entry --- changelog.d/6786.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6786.misc diff --git a/changelog.d/6786.misc b/changelog.d/6786.misc new file mode 100644 index 0000000000..a916336ae4 --- /dev/null +++ b/changelog.d/6786.misc @@ -0,0 +1 @@ +Add a developer setting to enable LeakCanary at runtime From 250ee1faa1c4a7a9a0ff5aa866aa0f50570faac5 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 10 Aug 2022 14:19:03 +0200 Subject: [PATCH 053/191] Moving the new setting inside debug screen --- vector/src/debug/AndroidManifest.xml | 1 + .../app/features/debug/DebugMenuActivity.kt | 6 ++ .../debug/di/MavericksViewModelDebugModule.kt | 7 ++ .../debug/leak/DebugMemoryLeaksActivity.kt | 37 ++++++++++ .../debug/leak/DebugMemoryLeaksFragment.kt | 54 +++++++++++++++ .../debug/leak/DebugMemoryLeaksViewActions.kt | 23 +++++++ .../debug/leak/DebugMemoryLeaksViewModel.kt | 67 +++++++++++++++++++ .../debug/leak/DebugMemoryLeaksViewState.kt | 23 +++++++ .../debug/res/layout/activity_debug_menu.xml | 12 +++- .../layout/fragment_debug_memory_leaks.xml | 32 +++++++++ .../im/vector/app/core/di/FragmentModule.kt | 6 -- .../features/settings/VectorPreferences.kt | 9 ++- .../VectorSettingsAdvancedSettingsFragment.kt | 18 +---- vector/src/main/res/values/strings.xml | 3 - .../xml/vector_settings_advanced_settings.xml | 7 -- 15 files changed, 270 insertions(+), 35 deletions(-) create mode 100644 vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksActivity.kt create mode 100644 vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksFragment.kt create mode 100644 vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewActions.kt create mode 100644 vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewModel.kt create mode 100644 vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewState.kt create mode 100644 vector/src/debug/res/layout/fragment_debug_memory_leaks.xml diff --git a/vector/src/debug/AndroidManifest.xml b/vector/src/debug/AndroidManifest.xml index 4ec47d4920..94fdb1b389 100644 --- a/vector/src/debug/AndroidManifest.xml +++ b/vector/src/debug/AndroidManifest.xml @@ -10,6 +10,7 @@ + () { views.debugAnalytics.setOnClickListener { startActivity(Intent(this, DebugAnalyticsActivity::class.java)) } + views.debugMemoryLeaks.setOnClickListener { openMemoryLeaksSettings() } views.debugTestTextViewLink.setOnClickListener { testTextViewLink() } views.debugOpenButtonStylesLight.setOnClickListener { startActivity(Intent(this, DebugVectorButtonStylesLightActivity::class.java)) @@ -130,6 +132,10 @@ class DebugMenuActivity : VectorBaseActivity() { startActivity(Intent(this, DebugPrivateSettingsActivity::class.java)) } + private fun openMemoryLeaksSettings() { + startActivity(Intent(this, DebugMemoryLeaksActivity::class.java)) + } + private fun renderQrCode(text: String) { views.debugQrCode.setData(text) } diff --git a/vector/src/debug/java/im/vector/app/features/debug/di/MavericksViewModelDebugModule.kt b/vector/src/debug/java/im/vector/app/features/debug/di/MavericksViewModelDebugModule.kt index 6ef7fe441a..8512bb8c6d 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/di/MavericksViewModelDebugModule.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/di/MavericksViewModelDebugModule.kt @@ -24,6 +24,7 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.MavericksViewModelComponent import im.vector.app.core.di.MavericksViewModelKey import im.vector.app.features.debug.analytics.DebugAnalyticsViewModel +import im.vector.app.features.debug.leak.DebugMemoryLeaksViewModel import im.vector.app.features.debug.settings.DebugPrivateSettingsViewModel @InstallIn(MavericksViewModelComponent::class) @@ -39,4 +40,10 @@ interface MavericksViewModelDebugModule { @IntoMap @MavericksViewModelKey(DebugPrivateSettingsViewModel::class) fun debugPrivateSettingsViewModelFactory(factory: DebugPrivateSettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + + @Binds + @IntoMap + @MavericksViewModelKey(DebugMemoryLeaksViewModel::class) + fun debugMemoryLeaksViewModelFactory(factory: DebugMemoryLeaksViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + } diff --git a/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksActivity.kt new file mode 100644 index 0000000000..226c65e3ed --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksActivity.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 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.leak + +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.extensions.addFragment +import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivitySimpleBinding + +@AndroidEntryPoint +class DebugMemoryLeaksActivity : VectorBaseActivity() { + + override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) + + override fun initUiAndData() { + if (isFirstCreation()) { + addFragment( + views.simpleFragmentContainer, + DebugMemoryLeaksFragment::class.java + ) + } + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksFragment.kt b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksFragment.kt new file mode 100644 index 0000000000..d3e70e26e6 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksFragment.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 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.leak + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.epoxy.onClick +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentDebugMemoryLeaksBinding + +@AndroidEntryPoint +class DebugMemoryLeaksFragment : VectorBaseFragment() { + + private val viewModel: DebugMemoryLeaksViewModel by fragmentViewModel() + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentDebugMemoryLeaksBinding { + return FragmentDebugMemoryLeaksBinding.inflate(inflater, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setViewListeners() + } + + private fun setViewListeners() { + views.enableMemoryLeakAnalysis.onClick { + viewModel.handle(DebugMemoryLeaksViewActions.EnableMemoryLeaksAnalysis(views.enableMemoryLeakAnalysis.isChecked)) + } + } + + override fun invalidate() = withState(viewModel) { viewState -> + views.enableMemoryLeakAnalysis.isChecked = viewState.isMemoryLeaksAnalysisEnabled + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewActions.kt b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewActions.kt new file mode 100644 index 0000000000..e1447ae345 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewActions.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 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.leak + +import im.vector.app.core.platform.VectorViewModelAction + +sealed interface DebugMemoryLeaksViewActions : VectorViewModelAction { + data class EnableMemoryLeaksAnalysis(val isEnabled: Boolean) : DebugMemoryLeaksViewActions +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewModel.kt b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewModel.kt new file mode 100644 index 0000000000..617a6b2ecb --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewModel.kt @@ -0,0 +1,67 @@ +/* + * 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.leak + +import com.airbnb.mvrx.MavericksViewModelFactory +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import im.vector.app.core.di.MavericksAssistedViewModelFactory +import im.vector.app.core.di.hiltMavericksViewModelFactory +import im.vector.app.core.platform.EmptyViewEvents +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.settings.VectorPreferences +import im.vector.app.leakcanary.LeakCanaryProxy +import kotlinx.coroutines.launch + +class DebugMemoryLeaksViewModel @AssistedInject constructor( + @Assisted initialState: DebugMemoryLeaksViewState, + private val vectorPreferences: VectorPreferences, + private val leakCanaryProxy: LeakCanaryProxy, +) : VectorViewModel(initialState) { + + @AssistedFactory + interface Factory : MavericksAssistedViewModelFactory { + override fun create(initialState: DebugMemoryLeaksViewState): DebugMemoryLeaksViewModel + } + + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + + init { + viewModelScope.launch { + refreshStateFromPreferences() + } + } + + override fun handle(action: DebugMemoryLeaksViewActions) { + when (action) { + is DebugMemoryLeaksViewActions.EnableMemoryLeaksAnalysis -> handleEnableMemoryLeaksAnalysis(action) + } + } + + private fun handleEnableMemoryLeaksAnalysis(action: DebugMemoryLeaksViewActions.EnableMemoryLeaksAnalysis) { + viewModelScope.launch { + vectorPreferences.enableMemoryLeakAnalysis(action.isEnabled) + leakCanaryProxy.enable(action.isEnabled) + refreshStateFromPreferences() + } + } + + private fun refreshStateFromPreferences() { + setState { copy(isMemoryLeaksAnalysisEnabled = vectorPreferences.isMemoryLeakAnalysisEnabled()) } + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewState.kt b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewState.kt new file mode 100644 index 0000000000..4e9fe4b402 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksViewState.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 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.leak + +import com.airbnb.mvrx.MavericksState + +data class DebugMemoryLeaksViewState( + val isMemoryLeaksAnalysisEnabled: Boolean = false +) : MavericksState diff --git a/vector/src/debug/res/layout/activity_debug_menu.xml b/vector/src/debug/res/layout/activity_debug_menu.xml index 8b38c17b35..b5efe0302c 100644 --- a/vector/src/debug/res/layout/activity_debug_menu.xml +++ b/vector/src/debug/res/layout/activity_debug_menu.xml @@ -1,5 +1,6 @@ + android:layout_height="wrap_content" + app:layout_anchor="@+id/scrollView2" + app:layout_anchorGravity="center"> +