Merge pull request #4626 from vector-im/feature/adm/feature-flags

Feature flags base
This commit is contained in:
Benoit Marty 2021-12-03 17:38:25 +01:00 committed by GitHub
commit 1f58913b53
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 214 additions and 97 deletions

1
changelog.d/4626.misc Normal file
View file

@ -0,0 +1 @@
Introducing feature flagging to the login and notification settings flows

View file

@ -160,7 +160,7 @@ Formatter\.formatShortFileSize===1
# android\.text\.TextUtils # android\.text\.TextUtils
### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt ### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt
enum class===108 enum class===110
### Do not import temporary legacy classes ### Do not import temporary legacy classes
import org.matrix.android.sdk.internal.legacy.riot===3 import org.matrix.android.sdk.internal.legacy.riot===3

View file

@ -140,16 +140,8 @@ android {
buildConfigField "String", "BUILD_NUMBER", "\"${buildNumber}\"" buildConfigField "String", "BUILD_NUMBER", "\"${buildNumber}\""
resValue "string", "build_number", "\"${buildNumber}\"" resValue "string", "build_number", "\"${buildNumber}\""
// The two booleans must not have the same value. We need two values for the manifest buildConfigField "im.vector.app.features.VectorFeatures.LoginVersion", "LOGIN_VERSION", "im.vector.app.features.VectorFeatures.LoginVersion.V1"
// LoginFlowV2 is disabled to be merged on develop (changelog: Improve login/register flow (#1410, #2585, #3172)) buildConfigField "im.vector.app.features.VectorFeatures.NotificationSettingsVersion", "NOTIFICATION_SETTINGS_VERSION", "im.vector.app.features.VectorFeatures.NotificationSettingsVersion.V2"
resValue "bool", "useLoginV1", "true"
resValue "bool", "useLoginV2", "false"
// NotificationSettingsV2 is disabled. To be released in conjunction with iOS/Web
def useNotificationSettingsV2 = true
buildConfigField "Boolean", "USE_NOTIFICATION_SETTINGS_V2", "${useNotificationSettingsV2}"
resValue "bool", "useNotificationSettingsV1", "${!useNotificationSettingsV2}"
resValue "bool", "useNotificationSettingsV2", "${useNotificationSettingsV2}"
buildConfigField "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy", "outboundSessionKeySharingStrategy", "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy.WhenTyping" buildConfigField "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy", "outboundSessionKeySharingStrategy", "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy.WhenTyping"

View file

@ -21,22 +21,27 @@ import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
import im.vector.app.BuildConfig import im.vector.app.BuildConfig
import im.vector.app.R import im.vector.app.R
import im.vector.app.espresso.tools.clickOnPreference import im.vector.app.espresso.tools.clickOnPreference
import im.vector.app.features.VectorFeatures
class SettingsNotificationsRobot { class SettingsNotificationsRobot {
fun crawl() { fun crawl() {
if (BuildConfig.USE_NOTIFICATION_SETTINGS_V2) { when (BuildConfig.NOTIFICATION_SETTINGS_VERSION!!) {
clickOn(R.string.settings_notification_default) VectorFeatures.NotificationSettingsVersion.V1 -> {
pressBack() clickOn(R.string.settings_notification_advanced)
clickOn(R.string.settings_notification_mentions_and_keywords) pressBack()
// TODO Test adding a keyword? }
pressBack() VectorFeatures.NotificationSettingsVersion.V2 -> {
clickOn(R.string.settings_notification_other) clickOn(R.string.settings_notification_default)
pressBack() pressBack()
} else { clickOn(R.string.settings_notification_mentions_and_keywords)
clickOn(R.string.settings_notification_advanced) // TODO Test adding a keyword?
pressBack() pressBack()
clickOn(R.string.settings_notification_other)
pressBack()
}
} }
/* /*
clickOn(R.string.settings_noisy_notifications_preferences) clickOn(R.string.settings_noisy_notifications_preferences)
TODO Cannot go back TODO Cannot go back

View file

@ -113,45 +113,33 @@
<activity android:name=".features.home.HomeActivity" /> <activity android:name=".features.home.HomeActivity" />
<!-- exported="true" is required to handle android.intent.action.VIEW for URL redirection--> <activity
android:name=".features.login.SSORedirectRouterActivity"
android:exported="true"
android:theme="@style/Theme.Vector.Black.Transparent">
<!-- Add intent filter to handle redirection URL after SSO login in external browser -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="connect"
android:scheme="element" />
</intent-filter>
</activity>
<activity <activity
android:name=".features.login.LoginActivity" android:name=".features.login.LoginActivity"
android:enabled="@bool/useLoginV1"
android:exported="true"
android:launchMode="singleTask" android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize" />
<!-- Add intent filter to handle redirection URL after SSO login in external browser -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="connect"
android:scheme="element" />
</intent-filter>
</activity>
<!-- exported="true" is required to handle android.intent.action.VIEW for URL redirection-->
<activity <activity
android:name=".features.login2.LoginActivity2" android:name=".features.login2.LoginActivity2"
android:enabled="@bool/useLoginV2"
android:exported="true"
android:launchMode="singleTask" android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize" />
<!-- Add intent filter to handle redirection URL after SSO login in external browser -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="connect"
android:scheme="element" />
</intent-filter>
</activity>
<!-- Add tools:ignore="Instantiatable" for the error reported only by Buildkite :/ --> <!-- Add tools:ignore="Instantiatable" for the error reported only by Buildkite :/ -->
<activity <activity

View file

@ -31,6 +31,8 @@ import im.vector.app.core.error.DefaultErrorFormatter
import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.time.Clock import im.vector.app.core.time.Clock
import im.vector.app.core.time.DefaultClock import im.vector.app.core.time.DefaultClock
import im.vector.app.features.DefaultVectorFeatures
import im.vector.app.features.VectorFeatures
import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.invite.AutoAcceptInvites
import im.vector.app.features.invite.CompileTimeAutoAcceptInvites import im.vector.app.features.invite.CompileTimeAutoAcceptInvites
import im.vector.app.features.navigation.DefaultNavigator import im.vector.app.features.navigation.DefaultNavigator
@ -133,4 +135,9 @@ object VectorStaticModule {
fun providesCoroutineDispatchers(): CoroutineDispatchers { fun providesCoroutineDispatchers(): CoroutineDispatchers {
return CoroutineDispatchers(io = Dispatchers.IO, computation = Dispatchers.Default) return CoroutineDispatchers(io = Dispatchers.IO, computation = Dispatchers.Default)
} }
@Provides
fun providesFeatures(): VectorFeatures {
return DefaultVectorFeatures()
}
} }

View file

@ -41,8 +41,6 @@ import im.vector.app.features.pin.UnlockedActivity
import im.vector.app.features.popup.PopupAlertManager import im.vector.app.features.popup.PopupAlertManager
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.signout.hard.SignedOutActivity import im.vector.app.features.signout.hard.SignedOutActivity
import im.vector.app.features.signout.soft.SoftLogoutActivity
import im.vector.app.features.signout.soft.SoftLogoutActivity2
import im.vector.app.features.themes.ActivityOtherThemes import im.vector.app.features.themes.ActivityOtherThemes
import im.vector.app.features.ui.UiStateRepository import im.vector.app.features.ui.UiStateRepository
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -223,9 +221,11 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
navigator.openLogin(this, null) navigator.openLogin(this, null)
null null
} }
args.isSoftLogout -> args.isSoftLogout -> {
// The homeserver has invalidated the token, with a soft logout // The homeserver has invalidated the token, with a soft logout
getSoftLogoutActivityIntent() navigator.softLogout(this)
null
}
args.isUserLoggedOut -> args.isUserLoggedOut ->
// the homeserver has invalidated the token (password changed, device deleted, other security reasons) // the homeserver has invalidated the token (password changed, device deleted, other security reasons)
SignedOutActivity.newIntent(this) SignedOutActivity.newIntent(this)
@ -236,7 +236,8 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
HomeActivity.newIntent(this) HomeActivity.newIntent(this)
} else { } else {
// The token is still invalid // The token is still invalid
getSoftLogoutActivityIntent() navigator.softLogout(this)
null
} }
else -> { else -> {
// First start, or no active session // First start, or no active session
@ -247,12 +248,4 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
intent?.let { startActivity(it) } intent?.let { startActivity(it) }
finish() finish()
} }
private fun getSoftLogoutActivityIntent(): Intent {
return if (resources.getBoolean(R.bool.useLoginV2)) {
SoftLogoutActivity2.newIntent(this)
} else {
SoftLogoutActivity.newIntent(this)
}
}
} }

View file

@ -0,0 +1,40 @@
/*
* 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
import im.vector.app.BuildConfig
interface VectorFeatures {
fun loginVersion(): LoginVersion
fun notificationSettingsVersion(): NotificationSettingsVersion
enum class LoginVersion {
V1,
V2
}
enum class NotificationSettingsVersion {
V1,
V2
}
}
class DefaultVectorFeatures : VectorFeatures {
override fun loginVersion(): VectorFeatures.LoginVersion = BuildConfig.LOGIN_VERSION
override fun notificationSettingsVersion(): VectorFeatures.NotificationSettingsVersion = BuildConfig.NOTIFICATION_SETTINGS_VERSION
}

View file

@ -17,7 +17,6 @@ package im.vector.app.features.home.room.list.actions
import androidx.annotation.StringRes import androidx.annotation.StringRes
import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.epoxy.TypedEpoxyController
import im.vector.app.BuildConfig
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.epoxy.bottomSheetDividerItem import im.vector.app.core.epoxy.bottomSheetDividerItem
import im.vector.app.core.epoxy.bottomsheet.bottomSheetActionItem import im.vector.app.core.epoxy.bottomsheet.bottomSheetActionItem
@ -25,6 +24,7 @@ import im.vector.app.core.epoxy.bottomsheet.bottomSheetRoomPreviewItem
import im.vector.app.core.epoxy.profiles.notifications.radioButtonItem import im.vector.app.core.epoxy.profiles.notifications.radioButtonItem
import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.features.VectorFeatures
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.roomprofile.notifications.notificationOptions import im.vector.app.features.roomprofile.notifications.notificationOptions
import im.vector.app.features.roomprofile.notifications.notificationStateMapped import im.vector.app.features.roomprofile.notifications.notificationStateMapped
@ -38,7 +38,8 @@ import javax.inject.Inject
class RoomListQuickActionsEpoxyController @Inject constructor( class RoomListQuickActionsEpoxyController @Inject constructor(
private val avatarRenderer: AvatarRenderer, private val avatarRenderer: AvatarRenderer,
private val colorProvider: ColorProvider, private val colorProvider: ColorProvider,
private val stringProvider: StringProvider private val stringProvider: StringProvider,
private val features: VectorFeatures
) : TypedEpoxyController<RoomListQuickActionViewState>() { ) : TypedEpoxyController<RoomListQuickActionViewState>() {
var listener: Listener? = null var listener: Listener? = null
@ -47,7 +48,7 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
val notificationViewState = state.notificationSettingsViewState val notificationViewState = state.notificationSettingsViewState
val roomSummary = notificationViewState.roomSummary() ?: return val roomSummary = notificationViewState.roomSummary() ?: return
val host = this val host = this
val isV2 = BuildConfig.USE_NOTIFICATION_SETTINGS_V2 val isV2 = features.notificationSettingsVersion() == VectorFeatures.NotificationSettingsVersion.V2
// V2 always shows full details as we no longer display the sheet from RoomProfile > Notifications // V2 always shows full details as we no longer display the sheet from RoomProfile > Notifications
val showFull = state.roomListActionsArgs.mode == RoomListActionsArgs.Mode.FULL || isV2 val showFull = state.roomListActionsArgs.mode == RoomListActionsArgs.Mode.FULL || isV2
@ -73,14 +74,14 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
} }
if (isV2) { if (isV2) {
notificationViewState.notificationOptions.forEach { notificationState -> notificationViewState.notificationOptions.forEach { notificationState ->
val title = titleForNotificationState(notificationState) val title = titleForNotificationState(notificationState)
radioButtonItem { radioButtonItem {
id(notificationState.name) id(notificationState.name)
titleRes(title) titleRes(title)
selected(notificationViewState.notificationStateMapped() == notificationState) selected(notificationViewState.notificationStateMapped() == notificationState)
listener { listener {
host.listener?.didSelectRoomNotificationState(notificationState) host.listener?.didSelectRoomNotificationState(notificationState)
} }
} }
} }
@ -102,8 +103,9 @@ class RoomListQuickActionsEpoxyController @Inject constructor(
RoomNotificationState.ALL_MESSAGES_NOISY -> R.string.room_settings_all_messages RoomNotificationState.ALL_MESSAGES_NOISY -> R.string.room_settings_all_messages
RoomNotificationState.MENTIONS_ONLY -> R.string.room_settings_mention_and_keyword_only RoomNotificationState.MENTIONS_ONLY -> R.string.room_settings_mention_and_keyword_only
RoomNotificationState.MUTE -> R.string.room_settings_none RoomNotificationState.MUTE -> R.string.room_settings_none
else -> null else -> null
} }
private fun RoomListQuickActionsSharedAction.toBottomSheetItem(index: Int, roomNotificationState: RoomNotificationState? = null) { private fun RoomListQuickActionsSharedAction.toBottomSheetItem(index: Int, roomNotificationState: RoomNotificationState? = null) {
val host = this@RoomListQuickActionsEpoxyController val host = this@RoomListQuickActionsEpoxyController
val selected = when (this) { val selected = when (this) {

View file

@ -18,6 +18,7 @@ package im.vector.app.features.login
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
@ -363,5 +364,11 @@ open class LoginActivity : VectorBaseActivity<ActivityLoginBinding>(), ToolbarCo
putExtra(EXTRA_CONFIG, loginConfig) putExtra(EXTRA_CONFIG, loginConfig)
} }
} }
fun redirectIntent(context: Context, data: Uri?): Intent {
return Intent(context, LoginActivity::class.java).apply {
setData(data)
}
}
} }
} }

View file

@ -0,0 +1,35 @@
/*
* 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.login
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.features.navigation.Navigator
import javax.inject.Inject
@AndroidEntryPoint
class SSORedirectRouterActivity : AppCompatActivity() {
@Inject lateinit var navigator: Navigator
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
navigator.loginSSORedirect(this, intent.data)
finish()
}
}

View file

@ -18,6 +18,7 @@ package im.vector.app.features.login2
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
@ -396,5 +397,11 @@ open class LoginActivity2 : VectorBaseActivity<ActivityLoginBinding>(), ToolbarC
putExtra(EXTRA_CONFIG, loginConfig) putExtra(EXTRA_CONFIG, loginConfig)
} }
} }
fun redirectIntent(context: Context, data: Uri?): Intent {
return Intent(context, LoginActivity2::class.java).apply {
setData(data)
}
}
} }
} }

View file

@ -19,6 +19,7 @@ package im.vector.app.features.navigation
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Build import android.os.Build
import android.view.View import android.view.View
import android.view.Window import android.view.Window
@ -36,6 +37,7 @@ import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.error.fatalError import im.vector.app.core.error.fatalError
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.utils.toast import im.vector.app.core.utils.toast
import im.vector.app.features.VectorFeatures
import im.vector.app.features.call.conference.JitsiCallViewModel import im.vector.app.features.call.conference.JitsiCallViewModel
import im.vector.app.features.call.conference.VectorJitsiActivity import im.vector.app.features.call.conference.VectorJitsiActivity
import im.vector.app.features.call.transfer.CallTransferActivity import im.vector.app.features.call.transfer.CallTransferActivity
@ -77,6 +79,8 @@ import im.vector.app.features.roomprofile.RoomProfileActivity
import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.settings.VectorSettingsActivity import im.vector.app.features.settings.VectorSettingsActivity
import im.vector.app.features.share.SharedData import im.vector.app.features.share.SharedData
import im.vector.app.features.signout.soft.SoftLogoutActivity
import im.vector.app.features.signout.soft.SoftLogoutActivity2
import im.vector.app.features.spaces.InviteRoomSpaceChooserBottomSheet import im.vector.app.features.spaces.InviteRoomSpaceChooserBottomSheet
import im.vector.app.features.spaces.SpaceExploreActivity import im.vector.app.features.spaces.SpaceExploreActivity
import im.vector.app.features.spaces.SpacePreviewActivity import im.vector.app.features.spaces.SpacePreviewActivity
@ -102,19 +106,35 @@ class DefaultNavigator @Inject constructor(
private val vectorPreferences: VectorPreferences, private val vectorPreferences: VectorPreferences,
private val widgetArgsBuilder: WidgetArgsBuilder, private val widgetArgsBuilder: WidgetArgsBuilder,
private val appStateHandler: AppStateHandler, private val appStateHandler: AppStateHandler,
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider,
private val features: VectorFeatures
) : Navigator { ) : Navigator {
override fun openLogin(context: Context, loginConfig: LoginConfig?, flags: Int) { override fun openLogin(context: Context, loginConfig: LoginConfig?, flags: Int) {
val intent = if (context.resources.getBoolean(R.bool.useLoginV2)) { val intent = when (features.loginVersion()) {
LoginActivity2.newIntent(context, loginConfig) VectorFeatures.LoginVersion.V1 -> LoginActivity.newIntent(context, loginConfig)
} else { VectorFeatures.LoginVersion.V2 -> LoginActivity2.newIntent(context, loginConfig)
LoginActivity.newIntent(context, loginConfig)
} }
intent.addFlags(flags) intent.addFlags(flags)
context.startActivity(intent) context.startActivity(intent)
} }
override fun loginSSORedirect(context: Context, data: Uri?) {
val intent = when (features.loginVersion()) {
VectorFeatures.LoginVersion.V1 -> LoginActivity.redirectIntent(context, data)
VectorFeatures.LoginVersion.V2 -> LoginActivity2.redirectIntent(context, data)
}
context.startActivity(intent)
}
override fun softLogout(context: Context) {
val intent = when (features.loginVersion()) {
VectorFeatures.LoginVersion.V1 -> SoftLogoutActivity.newIntent(context)
VectorFeatures.LoginVersion.V2 -> SoftLogoutActivity2.newIntent(context)
}
context.startActivity(intent)
}
override fun openRoom(context: Context, roomId: String, eventId: String?, buildTask: Boolean) { override fun openRoom(context: Context, roomId: String, eventId: String?, buildTask: Boolean) {
if (sessionHolder.getSafeActiveSession()?.getRoom(roomId) == null) { if (sessionHolder.getSafeActiveSession()?.getRoom(roomId) == null) {
fatalError("Trying to open an unknown room $roomId", vectorPreferences.failFast()) fatalError("Trying to open an unknown room $roomId", vectorPreferences.failFast())

View file

@ -19,6 +19,7 @@ package im.vector.app.features.navigation
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.view.View import android.view.View
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.core.util.Pair import androidx.core.util.Pair
@ -41,6 +42,10 @@ interface Navigator {
fun openLogin(context: Context, loginConfig: LoginConfig? = null, flags: Int = 0) fun openLogin(context: Context, loginConfig: LoginConfig? = null, flags: Int = 0)
fun loginSSORedirect(context: Context, data: Uri?)
fun softLogout(context: Context)
fun openRoom(context: Context, roomId: String, eventId: String? = null, buildTask: Boolean = false) fun openRoom(context: Context, roomId: String, eventId: String? = null, buildTask: Boolean = false)
sealed class PostSwitchSpaceAction { sealed class PostSwitchSpaceAction {

View file

@ -31,7 +31,6 @@ import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import im.vector.app.BuildConfig
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.animations.AppBarStateChangeListener import im.vector.app.core.animations.AppBarStateChangeListener
import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener import im.vector.app.core.animations.MatrixItemAppBarStateChangeListener
@ -45,6 +44,7 @@ import im.vector.app.core.utils.copyToClipboard
import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.core.utils.startSharePlainTextIntent
import im.vector.app.databinding.FragmentMatrixProfileBinding import im.vector.app.databinding.FragmentMatrixProfileBinding
import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding
import im.vector.app.features.VectorFeatures
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.detail.RoomDetailPendingAction import im.vector.app.features.home.room.detail.RoomDetailPendingAction
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
@ -70,6 +70,7 @@ class RoomProfileFragment @Inject constructor(
private val roomProfileController: RoomProfileController, private val roomProfileController: RoomProfileController,
private val avatarRenderer: AvatarRenderer, private val avatarRenderer: AvatarRenderer,
private val roomDetailPendingActionStore: RoomDetailPendingActionStore, private val roomDetailPendingActionStore: RoomDetailPendingActionStore,
private val features: VectorFeatures
) : ) :
VectorBaseFragment<FragmentMatrixProfileBinding>(), VectorBaseFragment<FragmentMatrixProfileBinding>(),
RoomProfileController.Callback { RoomProfileController.Callback {
@ -258,12 +259,15 @@ class RoomProfileFragment @Inject constructor(
} }
override fun onNotificationsClicked() { override fun onNotificationsClicked() {
if (BuildConfig.USE_NOTIFICATION_SETTINGS_V2) { when (features.notificationSettingsVersion()) {
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomNotificationSettings) VectorFeatures.NotificationSettingsVersion.V1 -> {
} else { RoomListQuickActionsBottomSheet
RoomListQuickActionsBottomSheet .newInstance(roomProfileArgs.roomId, RoomListActionsArgs.Mode.NOTIFICATIONS)
.newInstance(roomProfileArgs.roomId, RoomListActionsArgs.Mode.NOTIFICATIONS) .show(childFragmentManager, "ROOM_PROFILE_NOTIFICATIONS")
.show(childFragmentManager, "ROOM_PROFILE_NOTIFICATIONS") }
VectorFeatures.NotificationSettingsVersion.V2 -> {
roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomNotificationSettings)
}
} }
} }

View file

@ -47,6 +47,9 @@ class VectorPreferences @Inject constructor(private val context: Context) {
const val SETTINGS_DISCOVERY_PREFERENCE_KEY = "SETTINGS_DISCOVERY_PREFERENCE_KEY" const val SETTINGS_DISCOVERY_PREFERENCE_KEY = "SETTINGS_DISCOVERY_PREFERENCE_KEY"
const val SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY" const val SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY"
const val SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY"
const val SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY"
const val SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY"
const val SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY" const val SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY"
const val SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY" const val SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY"
const val SETTINGS_COPYRIGHT_PREFERENCE_KEY = "SETTINGS_COPYRIGHT_PREFERENCE_KEY" const val SETTINGS_COPYRIGHT_PREFERENCE_KEY = "SETTINGS_COPYRIGHT_PREFERENCE_KEY"

View file

@ -40,6 +40,7 @@ import im.vector.app.core.pushers.PushersManager
import im.vector.app.core.services.GuardServiceStarter import im.vector.app.core.services.GuardServiceStarter
import im.vector.app.core.utils.isIgnoringBatteryOptimizations import im.vector.app.core.utils.isIgnoringBatteryOptimizations
import im.vector.app.core.utils.requestDisablingBatteryOptimization import im.vector.app.core.utils.requestDisablingBatteryOptimization
import im.vector.app.features.VectorFeatures
import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.notifications.NotificationUtils
import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.BackgroundSyncMode
import im.vector.app.features.settings.BackgroundSyncModeChooserDialog import im.vector.app.features.settings.BackgroundSyncModeChooserDialog
@ -63,7 +64,8 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
private val pushManager: PushersManager, private val pushManager: PushersManager,
private val activeSessionHolder: ActiveSessionHolder, private val activeSessionHolder: ActiveSessionHolder,
private val vectorPreferences: VectorPreferences, private val vectorPreferences: VectorPreferences,
private val guardServiceStarter: GuardServiceStarter private val guardServiceStarter: GuardServiceStarter,
private val features: VectorFeatures
) : VectorSettingsBaseFragment(), ) : VectorSettingsBaseFragment(),
BackgroundSyncModeChooserDialog.InteractionListener { BackgroundSyncModeChooserDialog.InteractionListener {
@ -145,6 +147,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
refreshBackgroundSyncPrefs() refreshBackgroundSyncPrefs()
handleSystemPreference() handleSystemPreference()
handleVersionedSettings()
} }
private fun bindEmailNotifications() { private fun bindEmailNotifications() {
@ -309,6 +312,15 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
} }
} }
private fun handleVersionedSettings() {
val isNotificationSettingsV2Enabled = features.notificationSettingsVersion() == VectorFeatures.NotificationSettingsVersion.V2
findPreference<Preference>(VectorPreferences.SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY)?.isVisible = !isNotificationSettingsV2Enabled
findPreference<Preference>(VectorPreferences.SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled
findPreference<Preference>(VectorPreferences.SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled
findPreference<Preference>(VectorPreferences.SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
activeSessionHolder.getSafeActiveSession()?.refreshPushers() activeSessionHolder.getSafeActiveSession()?.refreshPushers()

View file

@ -26,38 +26,34 @@
android:persistent="false" android:persistent="false"
android:summary="@string/settings_notification_advanced_summary" android:summary="@string/settings_notification_advanced_summary"
android:title="@string/settings_notification_advanced" android:title="@string/settings_notification_advanced"
app:fragment="im.vector.app.features.settings.notifications.VectorSettingsAdvancedNotificationPreferenceFragment" app:fragment="im.vector.app.features.settings.notifications.VectorSettingsAdvancedNotificationPreferenceFragment" />
app:isPreferenceVisible="@bool/useNotificationSettingsV1" />
<im.vector.app.core.preference.VectorPreference <im.vector.app.core.preference.VectorPreference
android:dependency="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY" android:dependency="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY"
android:key="SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY" android:key="SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY"
android:persistent="false" android:persistent="false"
android:title="@string/settings_notification_default" android:title="@string/settings_notification_default"
app:fragment="im.vector.app.features.settings.notifications.VectorSettingsDefaultNotificationPreferenceFragment" app:fragment="im.vector.app.features.settings.notifications.VectorSettingsDefaultNotificationPreferenceFragment" />
app:isPreferenceVisible="@bool/useNotificationSettingsV2"/>
<im.vector.app.core.preference.VectorPreference <im.vector.app.core.preference.VectorPreference
android:dependency="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY" android:dependency="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY"
android:key="SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY" android:key="SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY"
android:persistent="false" android:persistent="false"
android:title="@string/settings_notification_mentions_and_keywords" android:title="@string/settings_notification_mentions_and_keywords"
app:fragment="im.vector.app.features.settings.notifications.VectorSettingsKeywordAndMentionsNotificationPreferenceFragment" app:fragment="im.vector.app.features.settings.notifications.VectorSettingsKeywordAndMentionsNotificationPreferenceFragment" />
app:isPreferenceVisible="@bool/useNotificationSettingsV2"/>
<im.vector.app.core.preference.VectorPreference <im.vector.app.core.preference.VectorPreference
android:dependency="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY" android:dependency="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY"
android:key="SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY" android:key="SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY"
android:persistent="false" android:persistent="false"
android:title="@string/settings_notification_other" android:title="@string/settings_notification_other"
app:fragment="im.vector.app.features.settings.notifications.VectorSettingsOtherNotificationPreferenceFragment" app:fragment="im.vector.app.features.settings.notifications.VectorSettingsOtherNotificationPreferenceFragment" />
app:isPreferenceVisible="@bool/useNotificationSettingsV2"/>
</im.vector.app.core.preference.VectorPreferenceCategory> </im.vector.app.core.preference.VectorPreferenceCategory>
<im.vector.app.core.preference.VectorPreferenceCategory <im.vector.app.core.preference.VectorPreferenceCategory
android:key="SETTINGS_EMAIL_NOTIFICATION_CATEGORY_PREFERENCE_KEY" android:key="SETTINGS_EMAIL_NOTIFICATION_CATEGORY_PREFERENCE_KEY"
android:title="@string/settings_notification_emails_category"/> android:title="@string/settings_notification_emails_category" />
<im.vector.app.core.preference.VectorPreferenceCategory <im.vector.app.core.preference.VectorPreferenceCategory
android:persistent="false" android:persistent="false"
@ -103,14 +99,14 @@
<im.vector.app.core.preference.VectorEditTextPreference <im.vector.app.core.preference.VectorEditTextPreference
android:inputType="numberDecimal" android:inputType="numberDecimal"
android:persistent="false"
android:key="SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY" android:key="SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY"
android:persistent="false"
android:title="@string/settings_set_sync_delay" /> android:title="@string/settings_set_sync_delay" />
<im.vector.app.core.preference.VectorEditTextPreference <im.vector.app.core.preference.VectorEditTextPreference
android:inputType="numberDecimal" android:inputType="numberDecimal"
android:persistent="false"
android:key="SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY" android:key="SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY"
android:persistent="false"
android:title="@string/settings_set_sync_timeout" /> android:title="@string/settings_set_sync_timeout" />
<im.vector.app.core.preference.VectorSwitchPreference <im.vector.app.core.preference.VectorSwitchPreference