diff --git a/docs/design.md b/docs/design.md
index 2e27f00ebf..a79f19cf3e 100644
--- a/docs/design.md
+++ b/docs/design.md
@@ -50,6 +50,17 @@ It's also possible for any icon to go to the main component by right-clicking on
- open the created vector drawable
- optionally update the color(s) to "#FF0000" (red) to ensure that the drawable is correctly tinted at runtime.
+### Images
+
+Android 4.3 (18+) fully supports the WebP image format which can often provide smaller image sizes without drastically impacting image quality (depending on the output encoding quality).
+When importing non vector images, WebP is the preferred format.
+
+Images can be converted to the WebP within Android Studio by
+ - right clicking the image file within the project file explorer
+ - select `Convert to WebP`
+
+https://developer.android.com/studio/write/convert-webp
+
## Figma links
Figma links can be included in the layout, for future reference, but it is also OK to add a paragraph below here, to centralize the information
diff --git a/library/ui-styles/src/main/res/drawable/bg_carousel_page_1.xml b/library/ui-styles/src/main/res/drawable/bg_carousel_page_1.xml
new file mode 100644
index 0000000000..bff828fb22
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/bg_carousel_page_1.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/library/ui-styles/src/main/res/drawable/bg_carousel_page_2.xml b/library/ui-styles/src/main/res/drawable/bg_carousel_page_2.xml
new file mode 100644
index 0000000000..54e5286ded
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/bg_carousel_page_2.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/library/ui-styles/src/main/res/drawable/bg_carousel_page_3.xml b/library/ui-styles/src/main/res/drawable/bg_carousel_page_3.xml
new file mode 100644
index 0000000000..c31c70c078
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/bg_carousel_page_3.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/library/ui-styles/src/main/res/drawable/bg_carousel_page_4.xml b/library/ui-styles/src/main/res/drawable/bg_carousel_page_4.xml
new file mode 100644
index 0000000000..56989688af
--- /dev/null
+++ b/library/ui-styles/src/main/res/drawable/bg_carousel_page_4.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/library/ui-styles/src/main/res/values-sw600dp/dimens.xml b/library/ui-styles/src/main/res/values-sw600dp/dimens.xml
index 204d663d9c..f399a350b1 100644
--- a/library/ui-styles/src/main/res/values-sw600dp/dimens.xml
+++ b/library/ui-styles/src/main/res/values-sw600dp/dimens.xml
@@ -2,4 +2,8 @@
400dp
+
+
+ - 0.25
+ - 0.75
\ No newline at end of file
diff --git a/library/ui-styles/src/main/res/values/dimens.xml b/library/ui-styles/src/main/res/values/dimens.xml
index 9fbf8958da..a2a6b34b0f 100644
--- a/library/ui-styles/src/main/res/values/dimens.xml
+++ b/library/ui-styles/src/main/res/values/dimens.xml
@@ -47,4 +47,8 @@
56dp
52dp
1dp
+
+
+ - 0.05
+ - 0.95
\ No newline at end of file
diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt
index 7ae7a53963..87d7e36ed5 100644
--- a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt
+++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt
@@ -16,8 +16,11 @@
package im.vector.app.features.debug.features
+import androidx.datastore.preferences.core.Preferences
import im.vector.app.features.DefaultVectorFeatures
+import im.vector.app.features.VectorFeatures
import javax.inject.Inject
+import kotlin.reflect.KFunction1
class DebugFeaturesStateFactory @Inject constructor(
private val debugFeatures: DebugVectorFeatures,
@@ -31,18 +34,23 @@ class DebugFeaturesStateFactory @Inject constructor(
featureOverride = debugFeatures.onboardingVariant(),
featureDefault = defaultFeatures.onboardingVariant()
),
-
- Feature.BooleanFeature(
+ createBooleanFeature(
label = "FTUE Splash - I already have an account",
- featureOverride = debugFeatures.isAlreadyHaveAccountSplashEnabled().takeIf {
- debugFeatures.hasOverride(DebugFeatureKeys.alreadyHaveAnAccount)
- },
- featureDefault = defaultFeatures.isAlreadyHaveAccountSplashEnabled(),
+ factory = VectorFeatures::isAlreadyHaveAccountSplashEnabled,
key = DebugFeatureKeys.alreadyHaveAnAccount
)
))
}
+ private fun createBooleanFeature(key: Preferences.Key, label: String, factory: KFunction1): Feature {
+ return Feature.BooleanFeature(
+ label = label,
+ featureOverride = factory.invoke(debugFeatures).takeIf { debugFeatures.hasOverride(key) },
+ featureDefault = factory.invoke(defaultFeatures),
+ key = key
+ )
+ }
+
private inline fun > createEnumFeature(label: String, featureOverride: T, featureDefault: T): Feature {
return Feature.EnumFeature(
label = label,
diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt
index daab981956..2e11017ef3 100644
--- a/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt
+++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt
@@ -43,9 +43,11 @@ class DebugVectorFeatures(
return readPreferences().getEnum() ?: vectorFeatures.onboardingVariant()
}
- override fun isAlreadyHaveAccountSplashEnabled(): Boolean = readPreferences()[DebugFeatureKeys.alreadyHaveAnAccount]
+ override fun isAlreadyHaveAccountSplashEnabled(): Boolean = read(DebugFeatureKeys.alreadyHaveAnAccount)
?: vectorFeatures.isAlreadyHaveAccountSplashEnabled()
+ override fun isSplashCarouselEnabled(): Boolean = read(DebugFeatureKeys.splashCarousel) ?: vectorFeatures.isSplashCarouselEnabled()
+
fun override(value: T?, key: Preferences.Key) = updatePreferences {
if (value == null) {
it.remove(key)
@@ -66,6 +68,8 @@ class DebugVectorFeatures(
}
}
+ private fun read(key: Preferences.Key): Boolean? = readPreferences()[key]
+
private fun readPreferences() = runBlocking { dataStore.data.first() }
private fun updatePreferences(block: (MutablePreferences) -> Unit) = runBlocking {
@@ -92,6 +96,6 @@ private inline fun > enumPreferencesKey() = enumPreferencesK
private fun > enumPreferencesKey(type: KClass) = stringPreferencesKey("enum-${type.simpleName}")
object DebugFeatureKeys {
-
val alreadyHaveAnAccount = booleanPreferencesKey("already-have-an-account")
+ val splashCarousel = booleanPreferencesKey("splash-carousel")
}
diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
index 217abd495a..c27309fad6 100644
--- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
+++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt
@@ -102,6 +102,7 @@ import im.vector.app.features.onboarding.ftueauth.FtueAuthResetPasswordMailConfi
import im.vector.app.features.onboarding.ftueauth.FtueAuthResetPasswordSuccessFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthServerSelectionFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthSignUpSignInSelectionFragment
+import im.vector.app.features.onboarding.ftueauth.FtueAuthSplashCarouselFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthSplashFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthWaitForEmailFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthWebFragment
@@ -443,6 +444,11 @@ interface FragmentModule {
@FragmentKey(FtueAuthSplashFragment::class)
fun bindFtueAuthSplashFragment(fragment: FtueAuthSplashFragment): Fragment
+ @Binds
+ @IntoMap
+ @FragmentKey(FtueAuthSplashCarouselFragment::class)
+ fun bindFtueAuthSplashCarouselFragment(fragment: FtueAuthSplashCarouselFragment): Fragment
+
@Binds
@IntoMap
@FragmentKey(FtueAuthWaitForEmailFragment::class)
diff --git a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt
index 0349b15c4d..c53ff0f433 100644
--- a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt
+++ b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt
@@ -24,19 +24,17 @@ interface VectorFeatures {
fun isAlreadyHaveAccountSplashEnabled(): Boolean
+ fun isSplashCarouselEnabled(): Boolean
+
enum class OnboardingVariant {
LEGACY,
LOGIN_2,
FTUE_AUTH
}
-
- enum class NotificationSettingsVersion {
- V1,
- V2
- }
}
class DefaultVectorFeatures : VectorFeatures {
override fun onboardingVariant(): VectorFeatures.OnboardingVariant = BuildConfig.ONBOARDING_VARIANT
override fun isAlreadyHaveAccountSplashEnabled() = true
+ override fun isSplashCarouselEnabled() = false
}
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingVariantFactory.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingVariantFactory.kt
index 5f861d8808..c171fc223d 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingVariantFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingVariantFactory.kt
@@ -36,7 +36,8 @@ class OnboardingVariantFactory @Inject constructor(
views = views,
onboardingViewModel = onboardingViewModel.value,
activity = activity,
- supportFragmentManager = activity.supportFragmentManager
+ supportFragmentManager = activity.supportFragmentManager,
+ vectorFeatures = vectorFeatures
)
VectorFeatures.OnboardingVariant.LOGIN_2 -> Login2Variant(
views = views,
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthSplashCarouselFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthSplashCarouselFragment.kt
new file mode 100644
index 0000000000..f89ae36eb6
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthSplashCarouselFragment.kt
@@ -0,0 +1,105 @@
+/*
+ * 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.onboarding.ftueauth
+
+import android.annotation.SuppressLint
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.isVisible
+import com.airbnb.mvrx.withState
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.google.android.material.tabs.TabLayoutMediator
+import im.vector.app.BuildConfig
+import im.vector.app.R
+import im.vector.app.databinding.FragmentFtueSplashCarouselBinding
+import im.vector.app.features.VectorFeatures
+import im.vector.app.features.onboarding.OnboardingAction
+import im.vector.app.features.onboarding.OnboardingFlow
+import im.vector.app.features.settings.VectorPreferences
+import org.matrix.android.sdk.api.failure.Failure
+import java.net.UnknownHostException
+import javax.inject.Inject
+
+class FtueAuthSplashCarouselFragment @Inject constructor(
+ private val vectorPreferences: VectorPreferences,
+ private val vectorFeatures: VectorFeatures,
+ private val carouselController: SplashCarouselController
+) : AbstractFtueAuthFragment() {
+
+ override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentFtueSplashCarouselBinding {
+ return FragmentFtueSplashCarouselBinding.inflate(inflater, container, false)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ setupViews()
+ }
+
+ private fun setupViews() {
+ views.splashCarousel.adapter = carouselController.adapter
+ TabLayoutMediator(views.carouselIndicator, views.splashCarousel) { _, _ -> }.attach()
+ carouselController.setData(SplashCarouselState())
+
+ views.loginSplashSubmit.debouncedClicks { getStarted() }
+ views.loginSplashAlreadyHaveAccount.apply {
+ isVisible = vectorFeatures.isAlreadyHaveAccountSplashEnabled()
+ debouncedClicks { alreadyHaveAnAccount() }
+ }
+
+ if (BuildConfig.DEBUG || vectorPreferences.developerMode()) {
+ views.loginSplashVersion.isVisible = true
+ @SuppressLint("SetTextI18n")
+ views.loginSplashVersion.text = "Version : ${BuildConfig.VERSION_NAME}#${BuildConfig.BUILD_NUMBER}\n" +
+ "Branch: ${BuildConfig.GIT_BRANCH_NAME}"
+ views.loginSplashVersion.debouncedClicks { navigator.openDebug(requireContext()) }
+ }
+ }
+
+ private fun getStarted() {
+ val getStartedFlow = if (vectorFeatures.isAlreadyHaveAccountSplashEnabled()) OnboardingFlow.SignUp else OnboardingFlow.SignInSignUp
+ viewModel.handle(OnboardingAction.OnGetStarted(resetLoginConfig = false, onboardingFlow = getStartedFlow))
+ }
+
+ private fun alreadyHaveAnAccount() {
+ viewModel.handle(OnboardingAction.OnIAlreadyHaveAnAccount(resetLoginConfig = false, onboardingFlow = OnboardingFlow.SignIn))
+ }
+
+ override fun resetViewModel() {
+ // Nothing to do
+ }
+
+ override fun onError(throwable: Throwable) {
+ if (throwable is Failure.NetworkConnection &&
+ throwable.ioException is UnknownHostException) {
+ // Invalid homeserver from URL config
+ val url = viewModel.getInitialHomeServerUrl().orEmpty()
+ MaterialAlertDialogBuilder(requireActivity())
+ .setTitle(R.string.dialog_title_error)
+ .setMessage(getString(R.string.login_error_homeserver_from_url_not_found, url))
+ .setPositiveButton(R.string.login_error_homeserver_from_url_not_found_enter_manual) { _, _ ->
+ val flow = withState(viewModel) { it.onboardingFlow } ?: OnboardingFlow.SignInSignUp
+ viewModel.handle(OnboardingAction.OnGetStarted(resetLoginConfig = true, flow))
+ }
+ .setNegativeButton(R.string.action_cancel, null)
+ .show()
+ } else {
+ super.onError(throwable)
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt
index f17899dff6..f177eda114 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt
@@ -15,7 +15,6 @@
*/
package im.vector.app.features.onboarding.ftueauth
-
import android.content.Intent
import android.view.View
import android.view.ViewGroup
@@ -34,6 +33,7 @@ import im.vector.app.core.extensions.addFragmentToBackstack
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivityLoginBinding
+import im.vector.app.features.VectorFeatures
import im.vector.app.features.home.HomeActivity
import im.vector.app.features.login.LoginConfig
import im.vector.app.features.login.LoginMode
@@ -61,7 +61,8 @@ class FtueAuthVariant(
private val views: ActivityLoginBinding,
private val onboardingViewModel: OnboardingViewModel,
private val activity: VectorBaseActivity,
- private val supportFragmentManager: FragmentManager
+ private val supportFragmentManager: FragmentManager,
+ private val vectorFeatures: VectorFeatures
) : OnboardingVariant {
private val enterAnim = R.anim.enter_fade_in
@@ -108,7 +109,11 @@ class FtueAuthVariant(
}
private fun addFirstFragment() {
- activity.addFragment(views.loginFragmentContainer, FtueAuthSplashFragment::class.java)
+ val splashFragment = when (vectorFeatures.isSplashCarouselEnabled()) {
+ true -> FtueAuthSplashCarouselFragment::class.java
+ else -> FtueAuthSplashFragment::class.java
+ }
+ activity.addFragment(views.loginFragmentContainer, splashFragment)
}
private fun handleOnboardingViewEvents(viewEvents: OnboardingViewEvents) {
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt
index a90d919c05..94758c7fad 100644
--- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthWaitForEmailFragment.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 New Vector Ltd
+ * Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/SplashCarouselController.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/SplashCarouselController.kt
new file mode 100644
index 0000000000..95df0a6eed
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/SplashCarouselController.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.onboarding.ftueauth
+
+import com.airbnb.epoxy.TypedEpoxyController
+import javax.inject.Inject
+
+class SplashCarouselController @Inject constructor() : TypedEpoxyController() {
+ override fun buildModels(data: SplashCarouselState) {
+ data.items.forEachIndexed { index, item ->
+ splashCarouselItem {
+ id(index)
+ item(item)
+ }
+ }
+ }
+}
diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/SplashCarouselItem.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/SplashCarouselItem.kt
new file mode 100644
index 0000000000..1230d8109a
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/SplashCarouselItem.kt
@@ -0,0 +1,47 @@
+/*
+ * 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.onboarding.ftueauth
+
+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(layout = R.layout.item_splash_carousel)
+abstract class SplashCarouselItem : VectorEpoxyModel() {
+
+ @EpoxyAttribute
+ lateinit var item: SplashCarouselState.Item
+
+ override fun bind(holder: Holder) {
+ super.bind(holder)
+
+ holder.view.setBackgroundResource(item.pageBackground)
+ 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/onboarding/ftueauth/SplashCarouselState.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/SplashCarouselState.kt
new file mode 100644
index 0000000000..c86e78d139
--- /dev/null
+++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/SplashCarouselState.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.onboarding.ftueauth
+
+import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import im.vector.app.R
+
+data class SplashCarouselState(
+ val items: List- = listOf(
+ Item(
+ R.string.ftue_auth_carousel_1_title,
+ R.string.ftue_auth_carousel_1_body,
+ R.drawable.onboarding_carousel_conversations,
+ R.drawable.bg_carousel_page_1
+ ),
+ Item(
+ R.string.ftue_auth_carousel_2_title,
+ R.string.ftue_auth_carousel_2_body,
+ R.drawable.onboarding_carousel_ems,
+ R.drawable.bg_carousel_page_2
+ ),
+ Item(
+ R.string.ftue_auth_carousel_3_title,
+ R.string.ftue_auth_carousel_3_body,
+ R.drawable.onboarding_carousel_connect,
+ R.drawable.bg_carousel_page_3
+ ),
+ Item(
+ R.string.ftue_auth_carousel_4_title,
+ R.string.ftue_auth_carousel_4_body,
+ R.drawable.onboarding_carousel_universal,
+ R.drawable.bg_carousel_page_4
+ )
+ )
+) {
+ data class Item(
+ @StringRes val title: Int,
+ @StringRes val body: Int,
+ @DrawableRes val image: Int,
+ @DrawableRes val pageBackground: Int
+ )
+}
diff --git a/vector/src/main/res/drawable-xhdpi/onboarding_carousel_connect.webp b/vector/src/main/res/drawable-xhdpi/onboarding_carousel_connect.webp
new file mode 100644
index 0000000000..50aa2bc0f0
Binary files /dev/null and b/vector/src/main/res/drawable-xhdpi/onboarding_carousel_connect.webp differ
diff --git a/vector/src/main/res/drawable-xhdpi/onboarding_carousel_conversations.webp b/vector/src/main/res/drawable-xhdpi/onboarding_carousel_conversations.webp
new file mode 100644
index 0000000000..cb1038db14
Binary files /dev/null and b/vector/src/main/res/drawable-xhdpi/onboarding_carousel_conversations.webp differ
diff --git a/vector/src/main/res/drawable-xhdpi/onboarding_carousel_ems.webp b/vector/src/main/res/drawable-xhdpi/onboarding_carousel_ems.webp
new file mode 100644
index 0000000000..4f1754b300
Binary files /dev/null and b/vector/src/main/res/drawable-xhdpi/onboarding_carousel_ems.webp differ
diff --git a/vector/src/main/res/drawable-xhdpi/onboarding_carousel_universal.webp b/vector/src/main/res/drawable-xhdpi/onboarding_carousel_universal.webp
new file mode 100644
index 0000000000..de4c5f18cf
Binary files /dev/null and b/vector/src/main/res/drawable-xhdpi/onboarding_carousel_universal.webp differ
diff --git a/vector/src/main/res/drawable/indicator_onboarding_carousel_inactive.xml b/vector/src/main/res/drawable/indicator_onboarding_carousel_inactive.xml
new file mode 100644
index 0000000000..cdc99d6718
--- /dev/null
+++ b/vector/src/main/res/drawable/indicator_onboarding_carousel_inactive.xml
@@ -0,0 +1,12 @@
+
+
+
-
+
+
+
+
+
\ No newline at end of file
diff --git a/vector/src/main/res/drawable/indicator_onboarding_carousel_selected.xml b/vector/src/main/res/drawable/indicator_onboarding_carousel_selected.xml
new file mode 100644
index 0000000000..46aeb80298
--- /dev/null
+++ b/vector/src/main/res/drawable/indicator_onboarding_carousel_selected.xml
@@ -0,0 +1,12 @@
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/vector/src/main/res/drawable/indicator_onboarding_carousel_selector.xml b/vector/src/main/res/drawable/indicator_onboarding_carousel_selector.xml
new file mode 100644
index 0000000000..03249ff429
--- /dev/null
+++ b/vector/src/main/res/drawable/indicator_onboarding_carousel_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/vector/src/main/res/layout/fragment_ftue_splash.xml b/vector/src/main/res/layout/fragment_ftue_splash.xml
new file mode 100644
index 0000000000..f38bbc049e
--- /dev/null
+++ b/vector/src/main/res/layout/fragment_ftue_splash.xml
@@ -0,0 +1,226 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/res/layout/fragment_ftue_splash_carousel.xml b/vector/src/main/res/layout/fragment_ftue_splash_carousel.xml
new file mode 100644
index 0000000000..6791a09130
--- /dev/null
+++ b/vector/src/main/res/layout/fragment_ftue_splash_carousel.xml
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/res/layout/item_splash_carousel.xml b/vector/src/main/res/layout/item_splash_carousel.xml
new file mode 100644
index 0000000000..bb1b9fa0d2
--- /dev/null
+++ b/vector/src/main/res/layout/item_splash_carousel.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml
index 7ad3aeac08..1816e0d1fa 100644
--- a/vector/src/main/res/values/strings.xml
+++ b/vector/src/main/res/values/strings.xml
@@ -2516,6 +2516,16 @@
You made this invite only.
Unread messages
+
+ Own your conversions.
+ End-to-end encrypted messaging for secure and independent communication, connected via Matrix.
+ You\'re in control.
+ Element lets you choose where you messages are stored, keeping you in control of your data.
+ Connect with anyone.
+ Element works with all Matrix-based apps and can even bridge into proprietary messengers.
+ Cut the slack from teams.
+ As universal as email, Element is a completely new type of collaboration.
+
It\'s your conversation. Own it.
Chat with people directly or in groups
Keep conversations private with encryption