diff --git a/changelog.d/6646.misc b/changelog.d/6646.misc
new file mode 100644
index 0000000000..0f2e3f0881
--- /dev/null
+++ b/changelog.d/6646.misc
@@ -0,0 +1 @@
+[App Layout] Obsolete settings are not shown when App Layout flag is enabled
diff --git a/changelog.d/6876.feature b/changelog.d/6876.feature
new file mode 100644
index 0000000000..12a2b78a1e
--- /dev/null
+++ b/changelog.d/6876.feature
@@ -0,0 +1 @@
+[App Layout] - Invites now show empty screen after you reject last invite
diff --git a/docs/nightly_build.md b/docs/nightly_build.md
index 7750e0466a..77cc676c7f 100644
--- a/docs/nightly_build.md
+++ b/docs/nightly_build.md
@@ -47,7 +47,7 @@ git checkout develop
mv towncrier.toml towncrier.toml.bak
sed 's/CHANGES\.md/CHANGES_NIGHTLY\.md/' towncrier.toml.bak > towncrier.toml
rm towncrier.toml.bak
-yes n | towncrier --version nightly
+yes n | towncrier build --version nightly
./gradlew assembleGplayNightly appDistributionUploadGplayNightly $CI_GRADLE_ARG_PROPERTIES
```
diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml
index cc63ceb2a9..520843add9 100644
--- a/library/ui-strings/src/main/res/values/strings.xml
+++ b/library/ui-strings/src/main/res/values/strings.xml
@@ -454,6 +454,9 @@
Invites
+ Nothing new.
+ This is where your new requests and invites will be.
+
Conversations
Matrix contacts only
@@ -3259,4 +3262,15 @@
Nothing to report.
This is where your unread messages will show up, when you have some.
+ Welcome to a new view!
+
+ To simplify your ${app_name}, tabs are now optional. Manage them using the top-right menu.
+ Access Spaces
+
+ Access your Spaces (bottom-right) faster and easier than ever before.
+ Give Feedback
+
+ Tap top right to see the option to feedback.
+ Try it out
+
diff --git a/library/ui-styles/src/main/res/values-h720dp/dimens.xml b/library/ui-styles/src/main/res/values-h720dp/dimens.xml
index 1a7791720d..2a7b12cf2f 100644
--- a/library/ui-styles/src/main/res/values-h720dp/dimens.xml
+++ b/library/ui-styles/src/main/res/values-h720dp/dimens.xml
@@ -2,4 +2,8 @@
- 0.05
- 0.40
-
\ No newline at end of file
+
+ 16dp
+ 40dp
+ 46dp
+
diff --git a/library/ui-styles/src/main/res/values/dimens.xml b/library/ui-styles/src/main/res/values/dimens.xml
index 53f1044a12..758dd6e978 100644
--- a/library/ui-styles/src/main/res/values/dimens.xml
+++ b/library/ui-styles/src/main/res/values/dimens.xml
@@ -74,4 +74,9 @@
112dp
+
+
+ 8dp
+ 16dp
+ 28dp
diff --git a/vector/build.gradle b/vector/build.gradle
index 4f8db05e73..65adc7089c 100644
--- a/vector/build.gradle
+++ b/vector/build.gradle
@@ -257,7 +257,7 @@ dependencies {
// UnifiedPush
implementation 'com.github.UnifiedPush:android-connector:2.0.1'
// UnifiedPush gplay flavor only
- gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.2') {
+ gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.3') {
exclude group: 'com.google.firebase', module: 'firebase-core'
exclude group: 'com.google.firebase', module: 'firebase-analytics'
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml
index e87bbad77a..c4022576c3 100644
--- a/vector/src/main/AndroidManifest.xml
+++ b/vector/src/main/AndroidManifest.xml
@@ -338,6 +338,7 @@
+
diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
index b21b4778e3..a40aeaaa15 100644
--- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt
@@ -53,6 +53,7 @@ import im.vector.app.features.home.room.detail.upgrade.MigrateRoomViewModel
import im.vector.app.features.home.room.list.RoomListViewModel
import im.vector.app.features.home.room.list.home.HomeRoomListViewModel
import im.vector.app.features.home.room.list.home.invites.InvitesViewModel
+import im.vector.app.features.home.room.list.home.release.ReleaseNotesViewModel
import im.vector.app.features.homeserver.HomeServerCapabilitiesViewModel
import im.vector.app.features.invite.InviteUsersToRoomViewModel
import im.vector.app.features.location.LocationSharingViewModel
@@ -624,4 +625,9 @@ interface MavericksViewModelModule {
@IntoMap
@MavericksViewModelKey(InvitesViewModel::class)
fun invitesViewModel(factory: InvitesViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
+
+ @Binds
+ @IntoMap
+ @MavericksViewModelKey(ReleaseNotesViewModel::class)
+ fun releaseNotesViewModel(factory: ReleaseNotesViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
}
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 7665f95a40..6880b85df4 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
@@ -60,6 +60,7 @@ import im.vector.app.features.disclaimer.showDisclaimerDialog
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.home.room.list.home.layout.HomeLayoutSettingBottomDialogFragment
+import im.vector.app.features.home.room.list.home.release.ReleaseNotesActivity
import im.vector.app.features.matrixto.MatrixToBottomSheet
import im.vector.app.features.matrixto.OriginOfMatrixTo
import im.vector.app.features.navigation.Navigator
@@ -268,6 +269,7 @@ class HomeActivity :
}
is HomeActivityViewEvents.OnCrossSignedInvalidated -> handleCrossSigningInvalidated(it)
HomeActivityViewEvents.ShowAnalyticsOptIn -> handleShowAnalyticsOptIn()
+ HomeActivityViewEvents.ShowReleaseNotes -> handleShowReleaseNotes()
HomeActivityViewEvents.NotifyUserForThreadsMigration -> handleNotifyUserForThreadsMigration()
is HomeActivityViewEvents.MigrateThreads -> migrateThreadsIfNeeded(it.checkSession)
}
@@ -282,6 +284,10 @@ class HomeActivity :
homeActivityViewModel.handle(HomeActivityViewActions.ViewStarted)
}
+ private fun handleShowReleaseNotes() {
+ startActivity(Intent(this, ReleaseNotesActivity::class.java))
+ }
+
private fun showSpaceSettings(spaceId: String) {
// open bottom sheet
SpaceSettingsMenuBottomSheet
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewEvents.kt
index 170550d5b4..e0b9e8ceb5 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewEvents.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewEvents.kt
@@ -31,6 +31,7 @@ sealed interface HomeActivityViewEvents : VectorViewEvents {
data class OnCrossSignedInvalidated(val userItem: MatrixItem.UserItem) : HomeActivityViewEvents
object PromptToEnableSessionPush : HomeActivityViewEvents
object ShowAnalyticsOptIn : HomeActivityViewEvents
+ object ShowReleaseNotes : HomeActivityViewEvents
object NotifyUserForThreadsMigration : HomeActivityViewEvents
data class MigrateThreads(val checkSession: Boolean) : HomeActivityViewEvents
object StartRecoverySetupFlow : HomeActivityViewEvents
diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
index cfe76706a5..dd54285fb5 100644
--- a/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/HomeActivityViewModel.kt
@@ -26,11 +26,13 @@ import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.VectorViewModel
+import im.vector.app.features.VectorFeatures
import im.vector.app.features.analytics.AnalyticsConfig
import im.vector.app.features.analytics.AnalyticsTracker
import im.vector.app.features.analytics.extensions.toAnalyticsType
import im.vector.app.features.analytics.plan.Signup
import im.vector.app.features.analytics.store.AnalyticsStore
+import im.vector.app.features.home.room.list.home.release.ReleaseNotesPreferencesStore
import im.vector.app.features.login.ReAuthHelper
import im.vector.app.features.onboarding.AuthenticationDescription
import im.vector.app.features.raw.wellknown.ElementWellKnown
@@ -82,6 +84,8 @@ class HomeActivityViewModel @AssistedInject constructor(
private val vectorPreferences: VectorPreferences,
private val analyticsTracker: AnalyticsTracker,
private val analyticsConfig: AnalyticsConfig,
+ private val releaseNotesPreferencesStore: ReleaseNotesPreferencesStore,
+ private val vectorFeatures: VectorFeatures,
) : VectorViewModel(initialState) {
@AssistedFactory
@@ -110,9 +114,27 @@ class HomeActivityViewModel @AssistedInject constructor(
checkSessionPushIsOn()
observeCrossSigningReset()
observeAnalytics()
+ observeReleaseNotes()
initThreadsMigration()
}
+ private fun observeReleaseNotes() = withState { state ->
+ // we don't want to show release notes for new users or after relogin
+ if (state.authenticationDescription == null && vectorFeatures.isNewAppLayoutEnabled()) {
+ releaseNotesPreferencesStore.appLayoutOnboardingShown.onEach { isAppLayoutOnboardingShown ->
+ if (!isAppLayoutOnboardingShown) {
+ releaseNotesPreferencesStore.setAppLayoutOnboardingShown(true)
+ _viewEvents.post(HomeActivityViewEvents.ShowReleaseNotes)
+ }
+ }.launchIn(viewModelScope)
+ } else {
+ // we assume that users which came from auth flow either have seen updates already (relogin) or don't need them (new user)
+ viewModelScope.launch {
+ releaseNotesPreferencesStore.setAppLayoutOnboardingShown(true)
+ }
+ }
+ }
+
private fun observeAnalytics() {
if (analyticsConfig.isEnabled) {
analyticsStore.didAskUserConsentFlow
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt
index 74b46cec33..f557483289 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesFragment.kt
@@ -20,15 +20,18 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.fragmentViewModel
-import com.airbnb.mvrx.withState
import dagger.hilt.android.AndroidEntryPoint
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.FragmentInvitesBinding
import im.vector.app.features.analytics.plan.ViewRoom
import im.vector.app.features.home.room.list.RoomListListener
import im.vector.app.features.notifications.NotificationDrawerManager
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
import javax.inject.Inject
@@ -51,6 +54,8 @@ class InvitesFragment : VectorBaseFragment(), RoomListLi
setupToolbar(views.invitesToolbar)
.allowBack()
+ views.invitesStateView.contentView = views.invitesRecycler
+
views.invitesRecycler.configureWith(controller)
controller.listener = this
@@ -62,13 +67,31 @@ class InvitesFragment : VectorBaseFragment(), RoomListLi
when (it) {
is InvitesViewEvents.Failure -> showFailure(it.throwable)
is InvitesViewEvents.OpenRoom -> handleOpenRoom(it.roomSummary, it.shouldCloseInviteView)
- InvitesViewEvents.Close -> handleClose()
}
}
- }
- private fun handleClose() {
- requireActivity().finish()
+ viewModel.invites.onEach {
+ when (it) {
+ is InvitesContentState.Content -> {
+ views.invitesStateView.state = StateView.State.Content
+ controller.submitList(it.content)
+ }
+ is InvitesContentState.Empty -> {
+ views.invitesStateView.state = StateView.State.Empty(
+ title = it.title,
+ image = it.image,
+ message = it.message
+ )
+ }
+ is InvitesContentState.Error -> {
+ when (views.invitesStateView.state) {
+ StateView.State.Content -> showErrorInSnackbar(it.throwable)
+ else -> views.invitesStateView.state = StateView.State.Error(it.throwable.message)
+ }
+ }
+ InvitesContentState.Loading -> views.invitesStateView.state = StateView.State.Loading
+ }
+ }.launchIn(viewLifecycleOwner.lifecycleScope)
}
private fun handleOpenRoom(roomSummary: RoomSummary, shouldCloseInviteView: Boolean) {
@@ -83,14 +106,6 @@ class InvitesFragment : VectorBaseFragment(), RoomListLi
}
}
- override fun invalidate(): Unit = withState(viewModel) { state ->
- super.invalidate()
-
- state.pagedList?.observe(viewLifecycleOwner) { list ->
- controller.submitList(list)
- }
- }
-
override fun onRejectRoomInvitation(room: RoomSummary) {
notificationDrawerManager.updateEvents { it.clearMemberShipNotificationForRoom(room.roomId) }
viewModel.handle(InvitesAction.RejectInvitation(room))
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt
index d68577cf95..21310592a4 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewEvents.kt
@@ -22,5 +22,4 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary
sealed class InvitesViewEvents : VectorViewEvents {
data class Failure(val throwable: Throwable) : InvitesViewEvents()
data class OpenRoom(val roomSummary: RoomSummary, val shouldCloseInviteView: Boolean) : InvitesViewEvents()
- object Close : InvitesViewEvents()
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt
index b0d854be66..b8034d2364 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewModel.kt
@@ -16,14 +16,25 @@
package im.vector.app.features.home.room.list.home.invites
+import androidx.lifecycle.asFlow
import androidx.paging.PagedList
import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
+import im.vector.app.R
import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.VectorViewModel
+import im.vector.app.core.resources.DrawableProvider
+import im.vector.app.core.resources.StringProvider
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.extensions.orFalse
import org.matrix.android.sdk.api.session.Session
@@ -36,6 +47,8 @@ import timber.log.Timber
class InvitesViewModel @AssistedInject constructor(
@Assisted val initialState: InvitesViewState,
private val session: Session,
+ private val stringProvider: StringProvider,
+ private val drawableProvider: DrawableProvider
) : VectorViewModel(initialState) {
private val pagedListConfig = PagedList.Config.Builder()
@@ -52,6 +65,11 @@ class InvitesViewModel @AssistedInject constructor(
companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory()
+ private val _invites = MutableSharedFlow(replay = 1)
+ val invites = _invites.asSharedFlow()
+
+ private var invitesCount = -1
+
init {
observeInvites()
}
@@ -72,8 +90,6 @@ class InvitesViewModel @AssistedInject constructor(
return@withState
}
- val shouldCloseInviteView = state.pagedList?.value?.size == 1
-
viewModelScope.launch {
try {
session.roomService().leaveRoom(roomId)
@@ -81,9 +97,6 @@ class InvitesViewModel @AssistedInject constructor(
// Instead, we wait for the room to be rejected
// Known bug: if the user is invited again (after rejecting the first invitation), the loading will be displayed instead of the buttons.
// If we update the state, the button will be displayed again, so it's not ideal...
- if (shouldCloseInviteView) {
- _viewEvents.post(InvitesViewEvents.Close)
- }
} catch (failure: Throwable) {
// Notify the user
_viewEvents.post(InvitesViewEvents.Failure(failure))
@@ -101,9 +114,7 @@ class InvitesViewModel @AssistedInject constructor(
}
// close invites view when navigate to a room from the last one invite
- val shouldCloseInviteView = state.pagedList?.value?.size == 1
-
- _viewEvents.post(InvitesViewEvents.OpenRoom(action.roomSummary, shouldCloseInviteView))
+ val shouldCloseInviteView = invitesCount == 1
// quick echo
setState {
@@ -117,6 +128,8 @@ class InvitesViewModel @AssistedInject constructor(
}
)
}
+
+ _viewEvents.post(InvitesViewEvents.OpenRoom(action.roomSummary, shouldCloseInviteView))
}
private fun observeInvites() {
@@ -129,8 +142,26 @@ class InvitesViewModel @AssistedInject constructor(
sortOrder = RoomSortOrder.ACTIVITY
)
- setState {
- copy(pagedList = pagedList)
- }
+ pagedList.asFlow()
+ .map {
+ if (it.isEmpty()) {
+ InvitesContentState.Empty(
+ title = stringProvider.getString(R.string.invites_empty_title),
+ image = drawableProvider.getDrawable(R.drawable.ic_invites_empty),
+ message = stringProvider.getString(R.string.invites_empty_message)
+ )
+ } else {
+ invitesCount = it.loadedCount
+ InvitesContentState.Content(it)
+ }
+ }
+ .catch {
+ emit(InvitesContentState.Error(it))
+ }
+ .onStart {
+ emit(InvitesContentState.Loading)
+ }.onEach {
+ _invites.emit(it)
+ }.launchIn(viewModelScope)
}
}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt
index 708db29604..2f82c3fe76 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesViewState.kt
@@ -16,13 +16,24 @@
package im.vector.app.features.home.room.list.home.invites
-import androidx.lifecycle.LiveData
+import android.graphics.drawable.Drawable
import androidx.paging.PagedList
import com.airbnb.mvrx.MavericksState
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
import org.matrix.android.sdk.api.session.room.model.RoomSummary
data class InvitesViewState(
- val pagedList: LiveData>? = null,
val roomMembershipChanges: Map = emptyMap(),
) : MavericksState
+
+sealed interface InvitesContentState {
+ object Loading : InvitesContentState
+ data class Empty(
+ val title: CharSequence,
+ val image: Drawable?,
+ val message: CharSequence
+ ) : InvitesContentState
+
+ data class Content(val content: PagedList) : InvitesContentState
+ data class Error(val throwable: Throwable) : InvitesContentState
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseCarouselData.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseCarouselData.kt
new file mode 100644
index 0000000000..22431b0bf9
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseCarouselData.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.release
+
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+
+class ReleaseCarouselData(
+ val items: List-
+) {
+ data class Item(
+ @StringRes val title: Int,
+ @StringRes val body: Int,
+ @DrawableRes val image: Int,
+ )
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseCarouselItem.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseCarouselItem.kt
new file mode 100644
index 0000000000..49eb0761f7
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseCarouselItem.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.home.room.list.home.release
+
+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.VectorEpoxyHolder
+import im.vector.app.core.epoxy.VectorEpoxyModel
+
+@EpoxyModelClass
+abstract class ReleaseCarouselItem : VectorEpoxyModel(R.layout.item_release_carousel) {
+
+ @EpoxyAttribute
+ lateinit var item: ReleaseCarouselData.Item
+
+ override fun bind(holder: Holder) {
+ super.bind(holder)
+
+ holder.image.setImageResource(item.image)
+ holder.title.setText(item.title)
+ holder.body.setText(item.body)
+ }
+
+ class Holder : VectorEpoxyHolder() {
+ val image by bind(R.id.carousel_item_image)
+ val title by bind(R.id.carousel_item_title)
+ val body by bind(R.id.carousel_item_body)
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesAction.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesAction.kt
new file mode 100644
index 0000000000..7a66d00589
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesAction.kt
@@ -0,0 +1,28 @@
+/*
+ * 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.release
+
+import im.vector.app.core.platform.VectorViewModelAction
+
+sealed class ReleaseNotesAction : VectorViewModelAction {
+ data class NextPressed(
+ val isLastItemSelected: Boolean = false
+ ) : ReleaseNotesAction()
+ data class PageSelected(
+ val selectedPageIndex: Int = 0
+ ) : ReleaseNotesAction()
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesActivity.kt
new file mode 100644
index 0000000000..c5cc55d7bb
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesActivity.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.release
+
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.core.extensions.addFragment
+import im.vector.app.core.platform.ScreenOrientationLocker
+import im.vector.app.core.platform.VectorBaseActivity
+import im.vector.app.databinding.ActivitySimpleBinding
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class ReleaseNotesActivity : VectorBaseActivity() {
+
+ @Inject lateinit var orientationLocker: ScreenOrientationLocker
+
+ override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater)
+
+ override fun getCoordinatorLayout() = views.coordinatorLayout
+
+ override fun initUiAndData() {
+ orientationLocker.lockPhonesToPortrait(this)
+ if (isFirstCreation()) {
+ addFragment(views.simpleFragmentContainer, ReleaseNotesFragment::class.java)
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesCarouselController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesCarouselController.kt
new file mode 100644
index 0000000000..22d2915c47
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesCarouselController.kt
@@ -0,0 +1,31 @@
+/*
+ * 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.home.room.list.home.release
+
+import com.airbnb.epoxy.TypedEpoxyController
+import javax.inject.Inject
+
+class ReleaseNotesCarouselController @Inject constructor() : TypedEpoxyController() {
+ override fun buildModels(data: ReleaseCarouselData) {
+ data.items.forEachIndexed { index, item ->
+ releaseCarouselItem {
+ id(index)
+ item(item)
+ }
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesFragment.kt
new file mode 100644
index 0000000000..6b86897dc8
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesFragment.kt
@@ -0,0 +1,138 @@
+/*
+ * 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.release
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import androidx.viewpager2.widget.ViewPager2
+import com.airbnb.mvrx.fragmentViewModel
+import com.google.android.material.tabs.TabLayoutMediator
+import dagger.hilt.android.AndroidEntryPoint
+import im.vector.app.R
+import im.vector.app.core.epoxy.onClick
+import im.vector.app.core.platform.VectorBaseFragment
+import im.vector.app.databinding.BottomSheetReleaseNotesBinding
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class ReleaseNotesFragment : VectorBaseFragment() {
+
+ @Inject lateinit var carouselController: ReleaseNotesCarouselController
+ private var tabLayoutMediator: TabLayoutMediator? = null
+
+ private val viewModel by fragmentViewModel(ReleaseNotesViewModel::class)
+
+ override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetReleaseNotesBinding {
+ return BottomSheetReleaseNotesBinding.inflate(inflater, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ val carouselAdapter = carouselController.adapter
+ views.releaseNotesCarousel.adapter = carouselAdapter
+
+ tabLayoutMediator = TabLayoutMediator(views.releaseNotesCarouselIndicator, views.releaseNotesCarousel) { _, _ -> }
+ .also { it.attach() }
+
+ val pageCallback = object : ViewPager2.OnPageChangeCallback() {
+ override fun onPageSelected(position: Int) {
+ viewModel.handle(ReleaseNotesAction.PageSelected(position))
+ updateButtonText(position)
+ }
+ }
+
+ viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
+ override fun onCreate(owner: LifecycleOwner) {
+ views.releaseNotesCarousel.registerOnPageChangeCallback(pageCallback)
+ }
+
+ override fun onDestroy(owner: LifecycleOwner) {
+ views.releaseNotesCarousel.unregisterOnPageChangeCallback(pageCallback)
+ }
+ })
+
+ carouselController.setData(createCarouselData())
+
+ views.releaseNotesBtnClose.onClick { close() }
+ views.releaseNotesButtonNext.onClick {
+ val isLastItemSelected = with(views.releaseNotesCarouselIndicator) {
+ selectedTabPosition == tabCount - 1
+ }
+ viewModel.handle(ReleaseNotesAction.NextPressed(isLastItemSelected))
+ }
+
+ viewModel.observeViewEvents {
+ when (it) {
+ is ReleaseNotesViewEvents.SelectPage -> selectPage(it.index)
+ ReleaseNotesViewEvents.Close -> close()
+ }
+ }
+ }
+
+ private fun createCarouselData(): ReleaseCarouselData {
+ return ReleaseCarouselData(
+ listOf(
+ ReleaseCarouselData.Item(
+ R.string.onboarding_new_app_layout_welcome_title,
+ R.string.onboarding_new_app_layout_welcome_message,
+ R.drawable.ill_app_layout_onboarding_rooms
+ ),
+ ReleaseCarouselData.Item(
+ R.string.onboarding_new_app_layout_spaces_title,
+ R.string.onboarding_new_app_layout_spaces_message,
+ R.drawable.ill_app_layout_onboarding_spaces
+ ),
+ ReleaseCarouselData.Item(
+ R.string.onboarding_new_app_layout_feedback_title,
+ R.string.onboarding_new_app_layout_feedback_message,
+ R.drawable.ill_app_layout_onboarding_rooms
+ ),
+ )
+ )
+ }
+
+ private fun close() {
+ requireActivity().finish()
+ }
+
+ private fun selectPage(index: Int) {
+ views.releaseNotesCarouselIndicator.selectTab(views.releaseNotesCarouselIndicator.getTabAt(index))
+ updateButtonText(index)
+ }
+
+ private fun updateButtonText(selectedIndex: Int) {
+ val isLastItem = selectedIndex == views.releaseNotesCarouselIndicator.tabCount - 1
+ if (isLastItem) {
+ views.releaseNotesButtonNext.setText(R.string.onboarding_new_app_layout_button_try)
+ } else {
+ views.releaseNotesButtonNext.setText(R.string.action_next)
+ }
+ }
+
+ override fun onDestroyView() {
+ tabLayoutMediator?.detach()
+ tabLayoutMediator = null
+
+ views.releaseNotesCarousel.adapter = null
+ super.onDestroyView()
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesPreferencesStore.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesPreferencesStore.kt
new file mode 100644
index 0000000000..cefe107905
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesPreferencesStore.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.release
+
+import android.content.Context
+import androidx.datastore.core.DataStore
+import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.core.booleanPreferencesKey
+import androidx.datastore.preferences.core.edit
+import androidx.datastore.preferences.preferencesDataStore
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.map
+import org.matrix.android.sdk.api.extensions.orFalse
+import javax.inject.Inject
+
+private val Context.dataStore: DataStore by preferencesDataStore(name = "release_notes")
+
+class ReleaseNotesPreferencesStore @Inject constructor(
+ private val context: Context
+) {
+
+ private val isAppLayoutOnboardingShown = booleanPreferencesKey("SETTINGS_APP_LAYOUT_ONBOARDING_SHOWN")
+
+ val appLayoutOnboardingShown: Flow = context.dataStore.data
+ .map { preferences -> preferences[isAppLayoutOnboardingShown].orFalse() }
+ .distinctUntilChanged()
+
+ suspend fun setAppLayoutOnboardingShown(isShown: Boolean) {
+ context.dataStore.edit { settings ->
+ settings[isAppLayoutOnboardingShown] = isShown
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesViewEvents.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesViewEvents.kt
new file mode 100644
index 0000000000..7901a8b28f
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesViewEvents.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.home.release
+
+import im.vector.app.core.platform.VectorViewEvents
+
+sealed class ReleaseNotesViewEvents : VectorViewEvents {
+ object Close : ReleaseNotesViewEvents()
+ data class SelectPage(val index: Int) : ReleaseNotesViewEvents()
+}
diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesViewModel.kt
new file mode 100644
index 0000000000..23e2364d0c
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesViewModel.kt
@@ -0,0 +1,63 @@
+/*
+ * 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.release
+
+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.VectorDummyViewState
+import im.vector.app.core.platform.VectorViewModel
+
+class ReleaseNotesViewModel @AssistedInject constructor(
+ @Assisted initialState: VectorDummyViewState,
+) : VectorViewModel(initialState) {
+
+ @AssistedFactory
+ interface Factory : MavericksAssistedViewModelFactory {
+ override fun create(initialState: VectorDummyViewState): ReleaseNotesViewModel
+ }
+
+ companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory()
+
+ private var selectedPageIndex = 0
+
+ init {
+ _viewEvents.post(ReleaseNotesViewEvents.SelectPage(0))
+ }
+
+ override fun handle(action: ReleaseNotesAction) {
+ when (action) {
+ is ReleaseNotesAction.NextPressed -> handleNextPressed(action)
+ is ReleaseNotesAction.PageSelected -> handlePageSelected(action)
+ }
+ }
+
+ private fun handlePageSelected(action: ReleaseNotesAction.PageSelected) {
+ selectedPageIndex = action.selectedPageIndex
+ }
+
+ private fun handleNextPressed(action: ReleaseNotesAction.NextPressed) {
+ if (action.isLastItemSelected) {
+ _viewEvents.post(ReleaseNotesViewEvents.Close)
+ } else {
+ _viewEvents.post(ReleaseNotesViewEvents.SelectPage(++selectedPageIndex))
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt
index 9661feb002..52c445f1fa 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingViewModel.kt
@@ -627,7 +627,7 @@ class OnboardingViewModel @AssistedInject constructor(
_viewEvents.post(OnboardingViewEvents.OnAccountCreated)
}
AuthenticationDescription.Login -> {
- setState { copy(isLoading = false) }
+ setState { copy(isLoading = false, selectedAuthenticationState = SelectedAuthenticationState(authenticationDescription)) }
_viewEvents.post(OnboardingViewEvents.OnAccountSignedIn)
}
}
diff --git a/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt b/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt
index 40ef6d819e..b1327f0caf 100644
--- a/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt
+++ b/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt
@@ -28,6 +28,7 @@ import im.vector.app.core.time.Clock
import im.vector.app.core.utils.isAnimationEnabled
import im.vector.app.features.MainActivity
import im.vector.app.features.analytics.ui.consent.AnalyticsOptInActivity
+import im.vector.app.features.home.room.list.home.release.ReleaseNotesActivity
import im.vector.app.features.pin.PinActivity
import im.vector.app.features.signout.hard.SignedOutActivity
import im.vector.app.features.themes.ThemeUtils
@@ -307,6 +308,7 @@ class PopupAlertManager @Inject constructor(
activity !is PinActivity &&
activity !is SignedOutActivity &&
activity !is AnalyticsOptInActivity &&
+ activity !is ReleaseNotesActivity &&
activity is VectorBaseActivity<*> &&
alert.shouldBeDisplayedIn.invoke(activity)
}
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 483b246595..529a6d9b14 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,11 @@ class VectorPreferences @Inject constructor(
const val SETTINGS_LABS_AUTO_REPORT_UISI = "SETTINGS_LABS_AUTO_REPORT_UISI"
const val SETTINGS_PREF_SPACE_SHOW_ALL_ROOM_IN_HOME = "SETTINGS_PREF_SPACE_SHOW_ALL_ROOM_IN_HOME"
+ /**
+ * This is not preference, but category on preferences screen which contains [SETTINGS_PREF_SPACE_SHOW_ALL_ROOM_IN_HOME].
+ * Needed to show/hide this category, depending on visibility of [SETTINGS_PREF_SPACE_SHOW_ALL_ROOM_IN_HOME]. */
+ const val SETTINGS_PREF_SPACE_CATEGORY = "SETTINGS_PREF_SPACE_CATEGORY"
+
private const val SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY = "SETTINGS_DEVELOPER_MODE_PREFERENCE_KEY"
private const val SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY = "SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"
private const val SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY = "SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY"
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsLabsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsLabsFragment.kt
index f43add508c..7e414fc4ec 100644
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsLabsFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsLabsFragment.kt
@@ -78,6 +78,10 @@ class VectorSettingsLabsFragment :
findPreference(VectorPreferences.SETTINGS_LABS_NEW_APP_LAYOUT_KEY)?.let { pref ->
pref.isVisible = vectorFeatures.isNewAppLayoutEnabled()
}
+
+ findPreference(VectorPreferences.SETTINGS_LABS_UNREAD_NOTIFICATIONS_AS_TAB)?.let { pref ->
+ pref.isVisible = !vectorFeatures.isNewAppLayoutEnabled()
+ }
}
/**
diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt
index 0bd5316b8f..135c25cd8d 100644
--- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt
@@ -31,6 +31,7 @@ import im.vector.app.core.preference.VectorPreference
import im.vector.app.core.preference.VectorSwitchPreference
import im.vector.app.features.MainActivity
import im.vector.app.features.MainActivityArgs
+import im.vector.app.features.VectorFeatures
import im.vector.app.features.analytics.plan.MobileScreen
import im.vector.app.features.settings.font.FontScaleSettingActivity
import im.vector.app.features.themes.ThemeUtils
@@ -44,6 +45,7 @@ class VectorSettingsPreferencesFragment :
@Inject lateinit var vectorPreferences: VectorPreferences
@Inject lateinit var fontScalePreferences: FontScalePreferences
+ @Inject lateinit var vectorFeatures: VectorFeatures
override var titleRes = R.string.settings_preferences
override val preferenceXmlRes = R.xml.vector_settings_preferences
@@ -99,6 +101,10 @@ class VectorSettingsPreferencesFragment :
}
}
+ findPreference(VectorPreferences.SETTINGS_PREF_SPACE_CATEGORY)!!.let { pref ->
+ pref.isVisible = !vectorFeatures.isNewAppLayoutEnabled()
+ }
+
// Url preview
/*
TODO Note: we keep the setting client side for now
diff --git a/vector/src/main/res/drawable-hdpi/ill_app_layout_onboarding_rooms.webp b/vector/src/main/res/drawable-hdpi/ill_app_layout_onboarding_rooms.webp
new file mode 100644
index 0000000000..5ac890e617
Binary files /dev/null and b/vector/src/main/res/drawable-hdpi/ill_app_layout_onboarding_rooms.webp differ
diff --git a/vector/src/main/res/drawable-hdpi/ill_app_layout_onboarding_spaces.webp b/vector/src/main/res/drawable-hdpi/ill_app_layout_onboarding_spaces.webp
new file mode 100644
index 0000000000..35f2a04236
Binary files /dev/null and b/vector/src/main/res/drawable-hdpi/ill_app_layout_onboarding_spaces.webp differ
diff --git a/vector/src/main/res/drawable-mdpi/ill_app_layout_onboarding_rooms.webp b/vector/src/main/res/drawable-mdpi/ill_app_layout_onboarding_rooms.webp
new file mode 100644
index 0000000000..07ece0d947
Binary files /dev/null and b/vector/src/main/res/drawable-mdpi/ill_app_layout_onboarding_rooms.webp differ
diff --git a/vector/src/main/res/drawable-mdpi/ill_app_layout_onboarding_spaces.webp b/vector/src/main/res/drawable-mdpi/ill_app_layout_onboarding_spaces.webp
new file mode 100644
index 0000000000..a77bce20e8
Binary files /dev/null and b/vector/src/main/res/drawable-mdpi/ill_app_layout_onboarding_spaces.webp differ
diff --git a/vector/src/main/res/drawable-xhdpi/ill_app_layout_onboarding_rooms.webp b/vector/src/main/res/drawable-xhdpi/ill_app_layout_onboarding_rooms.webp
new file mode 100644
index 0000000000..e86bd5fe6b
Binary files /dev/null and b/vector/src/main/res/drawable-xhdpi/ill_app_layout_onboarding_rooms.webp differ
diff --git a/vector/src/main/res/drawable-xhdpi/ill_app_layout_onboarding_spaces.webp b/vector/src/main/res/drawable-xhdpi/ill_app_layout_onboarding_spaces.webp
new file mode 100644
index 0000000000..9b5b9fa607
Binary files /dev/null and b/vector/src/main/res/drawable-xhdpi/ill_app_layout_onboarding_spaces.webp differ
diff --git a/vector/src/main/res/drawable-xxhdpi/ill_app_layout_onboarding_rooms.webp b/vector/src/main/res/drawable-xxhdpi/ill_app_layout_onboarding_rooms.webp
new file mode 100644
index 0000000000..f95909eaae
Binary files /dev/null and b/vector/src/main/res/drawable-xxhdpi/ill_app_layout_onboarding_rooms.webp differ
diff --git a/vector/src/main/res/drawable-xxhdpi/ill_app_layout_onboarding_spaces.webp b/vector/src/main/res/drawable-xxhdpi/ill_app_layout_onboarding_spaces.webp
new file mode 100644
index 0000000000..03e31dc9d6
Binary files /dev/null and b/vector/src/main/res/drawable-xxhdpi/ill_app_layout_onboarding_spaces.webp differ
diff --git a/vector/src/main/res/drawable-xxxhdpi/ill_app_layout_onboarding_rooms.webp b/vector/src/main/res/drawable-xxxhdpi/ill_app_layout_onboarding_rooms.webp
new file mode 100644
index 0000000000..cee3cf512c
Binary files /dev/null and b/vector/src/main/res/drawable-xxxhdpi/ill_app_layout_onboarding_rooms.webp differ
diff --git a/vector/src/main/res/drawable-xxxhdpi/ill_app_layout_onboarding_spaces.webp b/vector/src/main/res/drawable-xxxhdpi/ill_app_layout_onboarding_spaces.webp
new file mode 100644
index 0000000000..b4bf421be5
Binary files /dev/null and b/vector/src/main/res/drawable-xxxhdpi/ill_app_layout_onboarding_spaces.webp differ
diff --git a/vector/src/main/res/drawable/ic_invites_empty.xml b/vector/src/main/res/drawable/ic_invites_empty.xml
new file mode 100644
index 0000000000..79908ff380
--- /dev/null
+++ b/vector/src/main/res/drawable/ic_invites_empty.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/vector/src/main/res/layout/activity_home.xml b/vector/src/main/res/layout/activity_home.xml
index 9899c15aa6..698aab2340 100644
--- a/vector/src/main/res/layout/activity_home.xml
+++ b/vector/src/main/res/layout/activity_home.xml
@@ -28,4 +28,4 @@
android:layout_height="match_parent"
android:layout_gravity="start" />
-
\ No newline at end of file
+
diff --git a/vector/src/main/res/layout/bottom_sheet_release_notes.xml b/vector/src/main/res/layout/bottom_sheet_release_notes.xml
new file mode 100644
index 0000000000..1d14c2c4a2
--- /dev/null
+++ b/vector/src/main/res/layout/bottom_sheet_release_notes.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/res/layout/fragment_invites.xml b/vector/src/main/res/layout/fragment_invites.xml
index 74226357c9..070cad5ec8 100644
--- a/vector/src/main/res/layout/fragment_invites.xml
+++ b/vector/src/main/res/layout/fragment_invites.xml
@@ -20,17 +20,24 @@
-
+ app:layout_constraintTop_toBottomOf="@id/appBarLayout">
+
+
+
+
+
diff --git a/vector/src/main/res/layout/item_release_carousel.xml b/vector/src/main/res/layout/item_release_carousel.xml
new file mode 100644
index 0000000000..eeb999b187
--- /dev/null
+++ b/vector/src/main/res/layout/item_release_carousel.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/res/res/drawable-hdpi/app_layout_onboarding_feedback.webp b/vector/src/main/res/res/drawable-hdpi/app_layout_onboarding_feedback.webp
new file mode 100644
index 0000000000..5ac890e617
Binary files /dev/null and b/vector/src/main/res/res/drawable-hdpi/app_layout_onboarding_feedback.webp differ
diff --git a/vector/src/main/res/res/drawable-hdpi/app_layout_onboarding_spaces.webp b/vector/src/main/res/res/drawable-hdpi/app_layout_onboarding_spaces.webp
new file mode 100644
index 0000000000..35f2a04236
Binary files /dev/null and b/vector/src/main/res/res/drawable-hdpi/app_layout_onboarding_spaces.webp differ
diff --git a/vector/src/main/res/res/drawable-hdpi/app_layout_onboarding_welcome.webp b/vector/src/main/res/res/drawable-hdpi/app_layout_onboarding_welcome.webp
new file mode 100644
index 0000000000..5ac890e617
Binary files /dev/null and b/vector/src/main/res/res/drawable-hdpi/app_layout_onboarding_welcome.webp differ
diff --git a/vector/src/main/res/res/drawable-mdpi/app_layout_onboarding_feedback.webp b/vector/src/main/res/res/drawable-mdpi/app_layout_onboarding_feedback.webp
new file mode 100644
index 0000000000..07ece0d947
Binary files /dev/null and b/vector/src/main/res/res/drawable-mdpi/app_layout_onboarding_feedback.webp differ
diff --git a/vector/src/main/res/res/drawable-mdpi/app_layout_onboarding_spaces.webp b/vector/src/main/res/res/drawable-mdpi/app_layout_onboarding_spaces.webp
new file mode 100644
index 0000000000..a77bce20e8
Binary files /dev/null and b/vector/src/main/res/res/drawable-mdpi/app_layout_onboarding_spaces.webp differ
diff --git a/vector/src/main/res/res/drawable-mdpi/app_layout_onboarding_welcome.webp b/vector/src/main/res/res/drawable-mdpi/app_layout_onboarding_welcome.webp
new file mode 100644
index 0000000000..07ece0d947
Binary files /dev/null and b/vector/src/main/res/res/drawable-mdpi/app_layout_onboarding_welcome.webp differ
diff --git a/vector/src/main/res/res/drawable-xhdpi/app_layout_onboarding_feedback.webp b/vector/src/main/res/res/drawable-xhdpi/app_layout_onboarding_feedback.webp
new file mode 100644
index 0000000000..e86bd5fe6b
Binary files /dev/null and b/vector/src/main/res/res/drawable-xhdpi/app_layout_onboarding_feedback.webp differ
diff --git a/vector/src/main/res/res/drawable-xhdpi/app_layout_onboarding_spaces.webp b/vector/src/main/res/res/drawable-xhdpi/app_layout_onboarding_spaces.webp
new file mode 100644
index 0000000000..9b5b9fa607
Binary files /dev/null and b/vector/src/main/res/res/drawable-xhdpi/app_layout_onboarding_spaces.webp differ
diff --git a/vector/src/main/res/res/drawable-xhdpi/app_layout_onboarding_welcome.webp b/vector/src/main/res/res/drawable-xhdpi/app_layout_onboarding_welcome.webp
new file mode 100644
index 0000000000..e86bd5fe6b
Binary files /dev/null and b/vector/src/main/res/res/drawable-xhdpi/app_layout_onboarding_welcome.webp differ
diff --git a/vector/src/main/res/res/drawable-xxhdpi/app_layout_onboarding_feedback.webp b/vector/src/main/res/res/drawable-xxhdpi/app_layout_onboarding_feedback.webp
new file mode 100644
index 0000000000..f95909eaae
Binary files /dev/null and b/vector/src/main/res/res/drawable-xxhdpi/app_layout_onboarding_feedback.webp differ
diff --git a/vector/src/main/res/res/drawable-xxhdpi/app_layout_onboarding_spaces.webp b/vector/src/main/res/res/drawable-xxhdpi/app_layout_onboarding_spaces.webp
new file mode 100644
index 0000000000..03e31dc9d6
Binary files /dev/null and b/vector/src/main/res/res/drawable-xxhdpi/app_layout_onboarding_spaces.webp differ
diff --git a/vector/src/main/res/res/drawable-xxhdpi/app_layout_onboarding_welcome.webp b/vector/src/main/res/res/drawable-xxhdpi/app_layout_onboarding_welcome.webp
new file mode 100644
index 0000000000..f95909eaae
Binary files /dev/null and b/vector/src/main/res/res/drawable-xxhdpi/app_layout_onboarding_welcome.webp differ
diff --git a/vector/src/main/res/res/drawable-xxxhdpi/app_layout_onboarding_feedback.webp b/vector/src/main/res/res/drawable-xxxhdpi/app_layout_onboarding_feedback.webp
new file mode 100644
index 0000000000..cee3cf512c
Binary files /dev/null and b/vector/src/main/res/res/drawable-xxxhdpi/app_layout_onboarding_feedback.webp differ
diff --git a/vector/src/main/res/res/drawable-xxxhdpi/app_layout_onboarding_spaces.webp b/vector/src/main/res/res/drawable-xxxhdpi/app_layout_onboarding_spaces.webp
new file mode 100644
index 0000000000..b4bf421be5
Binary files /dev/null and b/vector/src/main/res/res/drawable-xxxhdpi/app_layout_onboarding_spaces.webp differ
diff --git a/vector/src/main/res/res/drawable-xxxhdpi/app_layout_onboarding_welcome.webp b/vector/src/main/res/res/drawable-xxxhdpi/app_layout_onboarding_welcome.webp
new file mode 100644
index 0000000000..cee3cf512c
Binary files /dev/null and b/vector/src/main/res/res/drawable-xxxhdpi/app_layout_onboarding_welcome.webp differ
diff --git a/vector/src/main/res/xml/vector_settings_preferences.xml b/vector/src/main/res/xml/vector_settings_preferences.xml
index a3b8a3476c..172fa5606c 100644
--- a/vector/src/main/res/xml/vector_settings_preferences.xml
+++ b/vector/src/main/res/xml/vector_settings_preferences.xml
@@ -30,7 +30,9 @@
-
+