Remove Welcome screen from the FTUE
Keep the screen UI + logic around in case we want to reuse it in the future.
This commit is contained in:
parent
fb5ab95401
commit
1eaae2def5
4 changed files with 8 additions and 58 deletions
1
changelog.d/2584.misc
Normal file
1
changelog.d/2584.misc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Remove Welcome screen from the FTUE.
|
||||||
|
|
@ -36,7 +36,6 @@ import io.element.android.features.ftue.api.FtueEntryPoint
|
||||||
import io.element.android.features.ftue.impl.notifications.NotificationsOptInNode
|
import io.element.android.features.ftue.impl.notifications.NotificationsOptInNode
|
||||||
import io.element.android.features.ftue.impl.state.DefaultFtueState
|
import io.element.android.features.ftue.impl.state.DefaultFtueState
|
||||||
import io.element.android.features.ftue.impl.state.FtueStep
|
import io.element.android.features.ftue.impl.state.FtueStep
|
||||||
import io.element.android.features.ftue.impl.welcome.WelcomeNode
|
|
||||||
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
|
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
|
||||||
import io.element.android.libraries.architecture.BackstackView
|
import io.element.android.libraries.architecture.BackstackView
|
||||||
import io.element.android.libraries.architecture.BaseFlowNode
|
import io.element.android.libraries.architecture.BaseFlowNode
|
||||||
|
|
@ -73,9 +72,6 @@ class FtueFlowNode @AssistedInject constructor(
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data object Placeholder : NavTarget
|
data object Placeholder : NavTarget
|
||||||
|
|
||||||
@Parcelize
|
|
||||||
data object WelcomeScreen : NavTarget
|
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data object NotificationsOptIn : NavTarget
|
data object NotificationsOptIn : NavTarget
|
||||||
|
|
||||||
|
|
@ -110,15 +106,6 @@ class FtueFlowNode @AssistedInject constructor(
|
||||||
NavTarget.Placeholder -> {
|
NavTarget.Placeholder -> {
|
||||||
createNode<PlaceholderNode>(buildContext)
|
createNode<PlaceholderNode>(buildContext)
|
||||||
}
|
}
|
||||||
NavTarget.WelcomeScreen -> {
|
|
||||||
val callback = object : WelcomeNode.Callback {
|
|
||||||
override fun onContinueClicked() {
|
|
||||||
ftueState.setWelcomeScreenShown()
|
|
||||||
lifecycleScope.launch { moveToNextStep() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
createNode<WelcomeNode>(buildContext, listOf(callback))
|
|
||||||
}
|
|
||||||
NavTarget.NotificationsOptIn -> {
|
NavTarget.NotificationsOptIn -> {
|
||||||
val callback = object : NotificationsOptInNode.Callback {
|
val callback = object : NotificationsOptInNode.Callback {
|
||||||
override fun onNotificationsOptInFinished() {
|
override fun onNotificationsOptInFinished() {
|
||||||
|
|
@ -146,9 +133,6 @@ class FtueFlowNode @AssistedInject constructor(
|
||||||
|
|
||||||
private fun moveToNextStep() {
|
private fun moveToNextStep() {
|
||||||
when (ftueState.getNextStep()) {
|
when (ftueState.getNextStep()) {
|
||||||
FtueStep.WelcomeScreen -> {
|
|
||||||
backstack.newRoot(NavTarget.WelcomeScreen)
|
|
||||||
}
|
|
||||||
FtueStep.NotificationsOptIn -> {
|
FtueStep.NotificationsOptIn -> {
|
||||||
backstack.newRoot(NavTarget.NotificationsOptIn)
|
backstack.newRoot(NavTarget.NotificationsOptIn)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import android.os.Build
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import com.squareup.anvil.annotations.ContributesBinding
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
import io.element.android.features.ftue.api.state.FtueState
|
import io.element.android.features.ftue.api.state.FtueState
|
||||||
import io.element.android.features.ftue.impl.welcome.state.WelcomeScreenState
|
|
||||||
import io.element.android.features.lockscreen.api.LockScreenService
|
import io.element.android.features.lockscreen.api.LockScreenService
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.permissions.api.PermissionStateProvider
|
import io.element.android.libraries.permissions.api.PermissionStateProvider
|
||||||
|
|
@ -40,14 +39,12 @@ class DefaultFtueState @Inject constructor(
|
||||||
private val sdkVersionProvider: BuildVersionSdkIntProvider,
|
private val sdkVersionProvider: BuildVersionSdkIntProvider,
|
||||||
coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
private val analyticsService: AnalyticsService,
|
private val analyticsService: AnalyticsService,
|
||||||
private val welcomeScreenState: WelcomeScreenState,
|
|
||||||
private val permissionStateProvider: PermissionStateProvider,
|
private val permissionStateProvider: PermissionStateProvider,
|
||||||
private val lockScreenService: LockScreenService,
|
private val lockScreenService: LockScreenService,
|
||||||
) : FtueState {
|
) : FtueState {
|
||||||
override val shouldDisplayFlow = MutableStateFlow(isAnyStepIncomplete())
|
override val shouldDisplayFlow = MutableStateFlow(isAnyStepIncomplete())
|
||||||
|
|
||||||
override suspend fun reset() {
|
override suspend fun reset() {
|
||||||
welcomeScreenState.reset()
|
|
||||||
analyticsService.reset()
|
analyticsService.reset()
|
||||||
if (sdkVersionProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
|
if (sdkVersionProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
|
||||||
permissionStateProvider.resetPermission(Manifest.permission.POST_NOTIFICATIONS)
|
permissionStateProvider.resetPermission(Manifest.permission.POST_NOTIFICATIONS)
|
||||||
|
|
@ -62,12 +59,7 @@ class DefaultFtueState @Inject constructor(
|
||||||
|
|
||||||
fun getNextStep(currentStep: FtueStep? = null): FtueStep? =
|
fun getNextStep(currentStep: FtueStep? = null): FtueStep? =
|
||||||
when (currentStep) {
|
when (currentStep) {
|
||||||
null -> if (shouldDisplayWelcomeScreen()) {
|
null -> if (shouldAskNotificationPermissions()) {
|
||||||
FtueStep.WelcomeScreen
|
|
||||||
} else {
|
|
||||||
getNextStep(FtueStep.WelcomeScreen)
|
|
||||||
}
|
|
||||||
FtueStep.WelcomeScreen -> if (shouldAskNotificationPermissions()) {
|
|
||||||
FtueStep.NotificationsOptIn
|
FtueStep.NotificationsOptIn
|
||||||
} else {
|
} else {
|
||||||
getNextStep(FtueStep.NotificationsOptIn)
|
getNextStep(FtueStep.NotificationsOptIn)
|
||||||
|
|
@ -87,7 +79,6 @@ class DefaultFtueState @Inject constructor(
|
||||||
|
|
||||||
private fun isAnyStepIncomplete(): Boolean {
|
private fun isAnyStepIncomplete(): Boolean {
|
||||||
return listOf(
|
return listOf(
|
||||||
{ shouldDisplayWelcomeScreen() },
|
|
||||||
{ shouldAskNotificationPermissions() },
|
{ shouldAskNotificationPermissions() },
|
||||||
{ needsAnalyticsOptIn() },
|
{ needsAnalyticsOptIn() },
|
||||||
{ shouldDisplayLockscreenSetup() },
|
{ shouldDisplayLockscreenSetup() },
|
||||||
|
|
@ -99,10 +90,6 @@ class DefaultFtueState @Inject constructor(
|
||||||
return runBlocking { analyticsService.didAskUserConsent().first().not() }
|
return runBlocking { analyticsService.didAskUserConsent().first().not() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldDisplayWelcomeScreen(): Boolean {
|
|
||||||
return welcomeScreenState.isWelcomeScreenNeeded()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun shouldAskNotificationPermissions(): Boolean {
|
private fun shouldAskNotificationPermissions(): Boolean {
|
||||||
return if (sdkVersionProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
|
return if (sdkVersionProvider.isAtLeast(Build.VERSION_CODES.TIRAMISU)) {
|
||||||
val permission = Manifest.permission.POST_NOTIFICATIONS
|
val permission = Manifest.permission.POST_NOTIFICATIONS
|
||||||
|
|
@ -120,11 +107,6 @@ class DefaultFtueState @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setWelcomeScreenShown() {
|
|
||||||
welcomeScreenState.setWelcomeScreenShown()
|
|
||||||
updateState()
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||||
internal fun updateState() {
|
internal fun updateState() {
|
||||||
shouldDisplayFlow.value = isAnyStepIncomplete()
|
shouldDisplayFlow.value = isAnyStepIncomplete()
|
||||||
|
|
@ -132,7 +114,6 @@ class DefaultFtueState @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface FtueStep {
|
sealed interface FtueStep {
|
||||||
data object WelcomeScreen : FtueStep
|
|
||||||
data object NotificationsOptIn : FtueStep
|
data object NotificationsOptIn : FtueStep
|
||||||
data object AnalyticsOptIn : FtueStep
|
data object AnalyticsOptIn : FtueStep
|
||||||
data object LockscreenSetup : FtueStep
|
data object LockscreenSetup : FtueStep
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ import android.os.Build
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.ftue.impl.state.DefaultFtueState
|
import io.element.android.features.ftue.impl.state.DefaultFtueState
|
||||||
import io.element.android.features.ftue.impl.state.FtueStep
|
import io.element.android.features.ftue.impl.state.FtueStep
|
||||||
import io.element.android.features.ftue.impl.welcome.state.FakeWelcomeState
|
|
||||||
import io.element.android.features.lockscreen.api.LockScreenService
|
import io.element.android.features.lockscreen.api.LockScreenService
|
||||||
import io.element.android.features.lockscreen.test.FakeLockScreenService
|
import io.element.android.features.lockscreen.test.FakeLockScreenService
|
||||||
import io.element.android.libraries.permissions.impl.FakePermissionStateProvider
|
import io.element.android.libraries.permissions.impl.FakePermissionStateProvider
|
||||||
|
|
@ -47,7 +46,6 @@ class DefaultFtueStateTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given all checks being true, should display flow is false`() = runTest {
|
fun `given all checks being true, should display flow is false`() = runTest {
|
||||||
val welcomeState = FakeWelcomeState()
|
|
||||||
val analyticsService = FakeAnalyticsService()
|
val analyticsService = FakeAnalyticsService()
|
||||||
val permissionStateProvider = FakePermissionStateProvider(permissionGranted = true)
|
val permissionStateProvider = FakePermissionStateProvider(permissionGranted = true)
|
||||||
val lockScreenService = FakeLockScreenService()
|
val lockScreenService = FakeLockScreenService()
|
||||||
|
|
@ -55,13 +53,11 @@ class DefaultFtueStateTests {
|
||||||
|
|
||||||
val state = createState(
|
val state = createState(
|
||||||
coroutineScope = coroutineScope,
|
coroutineScope = coroutineScope,
|
||||||
welcomeState = welcomeState,
|
|
||||||
analyticsService = analyticsService,
|
analyticsService = analyticsService,
|
||||||
permissionStateProvider = permissionStateProvider,
|
permissionStateProvider = permissionStateProvider,
|
||||||
lockScreenService = lockScreenService,
|
lockScreenService = lockScreenService,
|
||||||
)
|
)
|
||||||
|
|
||||||
welcomeState.setWelcomeScreenShown()
|
|
||||||
analyticsService.setDidAskUserConsent()
|
analyticsService.setDidAskUserConsent()
|
||||||
permissionStateProvider.setPermissionGranted()
|
permissionStateProvider.setPermissionGranted()
|
||||||
lockScreenService.setIsPinSetup(true)
|
lockScreenService.setIsPinSetup(true)
|
||||||
|
|
@ -75,7 +71,6 @@ class DefaultFtueStateTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `traverse flow`() = runTest {
|
fun `traverse flow`() = runTest {
|
||||||
val welcomeState = FakeWelcomeState()
|
|
||||||
val analyticsService = FakeAnalyticsService()
|
val analyticsService = FakeAnalyticsService()
|
||||||
val permissionStateProvider = FakePermissionStateProvider(permissionGranted = false)
|
val permissionStateProvider = FakePermissionStateProvider(permissionGranted = false)
|
||||||
val lockScreenService = FakeLockScreenService()
|
val lockScreenService = FakeLockScreenService()
|
||||||
|
|
@ -83,26 +78,21 @@ class DefaultFtueStateTests {
|
||||||
|
|
||||||
val state = createState(
|
val state = createState(
|
||||||
coroutineScope = coroutineScope,
|
coroutineScope = coroutineScope,
|
||||||
welcomeState = welcomeState,
|
|
||||||
analyticsService = analyticsService,
|
analyticsService = analyticsService,
|
||||||
permissionStateProvider = permissionStateProvider,
|
permissionStateProvider = permissionStateProvider,
|
||||||
lockScreenService = lockScreenService,
|
lockScreenService = lockScreenService,
|
||||||
)
|
)
|
||||||
val steps = mutableListOf<FtueStep?>()
|
val steps = mutableListOf<FtueStep?>()
|
||||||
|
|
||||||
// First step, welcome screen
|
// Notifications opt in
|
||||||
steps.add(state.getNextStep(steps.lastOrNull()))
|
|
||||||
welcomeState.setWelcomeScreenShown()
|
|
||||||
|
|
||||||
// Second step, notifications opt in
|
|
||||||
steps.add(state.getNextStep(steps.lastOrNull()))
|
steps.add(state.getNextStep(steps.lastOrNull()))
|
||||||
permissionStateProvider.setPermissionGranted()
|
permissionStateProvider.setPermissionGranted()
|
||||||
|
|
||||||
// Third step, entering PIN code
|
// Entering PIN code
|
||||||
steps.add(state.getNextStep(steps.lastOrNull()))
|
steps.add(state.getNextStep(steps.lastOrNull()))
|
||||||
lockScreenService.setIsPinSetup(true)
|
lockScreenService.setIsPinSetup(true)
|
||||||
|
|
||||||
// Fourth step, analytics opt in
|
// Analytics opt in
|
||||||
steps.add(state.getNextStep(steps.lastOrNull()))
|
steps.add(state.getNextStep(steps.lastOrNull()))
|
||||||
analyticsService.setDidAskUserConsent()
|
analyticsService.setDidAskUserConsent()
|
||||||
|
|
||||||
|
|
@ -110,7 +100,6 @@ class DefaultFtueStateTests {
|
||||||
steps.add(state.getNextStep(steps.lastOrNull()))
|
steps.add(state.getNextStep(steps.lastOrNull()))
|
||||||
|
|
||||||
assertThat(steps).containsExactly(
|
assertThat(steps).containsExactly(
|
||||||
FtueStep.WelcomeScreen,
|
|
||||||
FtueStep.NotificationsOptIn,
|
FtueStep.NotificationsOptIn,
|
||||||
FtueStep.LockscreenSetup,
|
FtueStep.LockscreenSetup,
|
||||||
FtueStep.AnalyticsOptIn,
|
FtueStep.AnalyticsOptIn,
|
||||||
|
|
@ -135,15 +124,14 @@ class DefaultFtueStateTests {
|
||||||
lockScreenService = lockScreenService,
|
lockScreenService = lockScreenService,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Skip first 3 steps
|
// Skip first 2 steps
|
||||||
state.setWelcomeScreenShown()
|
|
||||||
permissionStateProvider.setPermissionGranted()
|
permissionStateProvider.setPermissionGranted()
|
||||||
lockScreenService.setIsPinSetup(true)
|
lockScreenService.setIsPinSetup(true)
|
||||||
|
|
||||||
assertThat(state.getNextStep()).isEqualTo(FtueStep.AnalyticsOptIn)
|
assertThat(state.getNextStep()).isEqualTo(FtueStep.AnalyticsOptIn)
|
||||||
|
|
||||||
analyticsService.setDidAskUserConsent()
|
analyticsService.setDidAskUserConsent()
|
||||||
assertThat(state.getNextStep(FtueStep.WelcomeScreen)).isNull()
|
assertThat(state.getNextStep(null)).isNull()
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
coroutineScope.cancel()
|
coroutineScope.cancel()
|
||||||
|
|
@ -162,14 +150,12 @@ class DefaultFtueStateTests {
|
||||||
lockScreenService = lockScreenService,
|
lockScreenService = lockScreenService,
|
||||||
)
|
)
|
||||||
|
|
||||||
assertThat(state.getNextStep()).isEqualTo(FtueStep.WelcomeScreen)
|
|
||||||
state.setWelcomeScreenShown()
|
|
||||||
lockScreenService.setIsPinSetup(true)
|
lockScreenService.setIsPinSetup(true)
|
||||||
|
|
||||||
assertThat(state.getNextStep()).isEqualTo(FtueStep.AnalyticsOptIn)
|
assertThat(state.getNextStep()).isEqualTo(FtueStep.AnalyticsOptIn)
|
||||||
|
|
||||||
analyticsService.setDidAskUserConsent()
|
analyticsService.setDidAskUserConsent()
|
||||||
assertThat(state.getNextStep(FtueStep.WelcomeScreen)).isNull()
|
assertThat(state.getNextStep(null)).isNull()
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
coroutineScope.cancel()
|
coroutineScope.cancel()
|
||||||
|
|
@ -177,7 +163,6 @@ class DefaultFtueStateTests {
|
||||||
|
|
||||||
private fun createState(
|
private fun createState(
|
||||||
coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
welcomeState: FakeWelcomeState = FakeWelcomeState(),
|
|
||||||
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
||||||
permissionStateProvider: FakePermissionStateProvider = FakePermissionStateProvider(permissionGranted = false),
|
permissionStateProvider: FakePermissionStateProvider = FakePermissionStateProvider(permissionGranted = false),
|
||||||
lockScreenService: LockScreenService = FakeLockScreenService(),
|
lockScreenService: LockScreenService = FakeLockScreenService(),
|
||||||
|
|
@ -187,7 +172,6 @@ class DefaultFtueStateTests {
|
||||||
sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkIntVersion),
|
sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkIntVersion),
|
||||||
coroutineScope = coroutineScope,
|
coroutineScope = coroutineScope,
|
||||||
analyticsService = analyticsService,
|
analyticsService = analyticsService,
|
||||||
welcomeScreenState = welcomeState,
|
|
||||||
permissionStateProvider = permissionStateProvider,
|
permissionStateProvider = permissionStateProvider,
|
||||||
lockScreenService = lockScreenService,
|
lockScreenService = lockScreenService,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue