mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-03-18 04:08:44 +03:00
adding barebones splash carousel fragment, based on feature flag
This commit is contained in:
parent
773d335add
commit
955fb03532
8 changed files with 327 additions and 3 deletions
|
@ -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,
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* 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 android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.view.isVisible
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import com.airbnb.epoxy.TypedEpoxyController
|
||||
import com.airbnb.mvrx.withState
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import im.vector.app.BuildConfig
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||
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
|
||||
|
||||
@AndroidEntryPoint
|
||||
class FtueAuthSplashCarouselFragment : AbstractFtueAuthFragment<FragmentFtueSplashCarouselBinding>() {
|
||||
|
||||
@Inject lateinit var vectorPreferences: VectorPreferences
|
||||
@Inject lateinit var vectorFeatures: VectorFeatures
|
||||
@Inject lateinit var carouselController: SplashCarouselController
|
||||
|
||||
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(
|
||||
items = listOf(
|
||||
SplashCarouselState.Item(
|
||||
"hello world",
|
||||
R.drawable.element_logo_green
|
||||
),
|
||||
SplashCarouselState.Item(
|
||||
"2",
|
||||
R.drawable.element_logo_green
|
||||
),
|
||||
SplashCarouselState.Item(
|
||||
"3",
|
||||
R.drawable.element_logo_green
|
||||
),
|
||||
SplashCarouselState.Item(
|
||||
"4",
|
||||
R.drawable.element_logo_green
|
||||
)
|
||||
),
|
||||
currentPage = 0
|
||||
))
|
||||
|
||||
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}\n" +
|
||||
"Branch: ${BuildConfig.GIT_BRANCH_NAME}\n" +
|
||||
"Build: ${BuildConfig.BUILD_NUMBER}"
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class SplashCarouselState(
|
||||
val items: List<Item>,
|
||||
val currentPage: Int
|
||||
) {
|
||||
data class Item(val body: String, @DrawableRes val image: Int)
|
||||
}
|
||||
|
||||
class SplashCarouselController @Inject constructor() : TypedEpoxyController<SplashCarouselState>() {
|
||||
override fun buildModels(data: SplashCarouselState) {
|
||||
data.items.forEachIndexed { index, item ->
|
||||
splashCarouselItem {
|
||||
id(index)
|
||||
item(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EpoxyModelClass(layout = im.vector.app.R.layout.item_splash_carousel)
|
||||
abstract class SplashCarouselItem : VectorEpoxyModel<SplashCarouselItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
lateinit var item: SplashCarouselState.Item
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
holder.image.setImageResource(item.image)
|
||||
holder.body.text = item.body
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val image by bind<ImageView>(im.vector.app.R.id.carousel_item_image)
|
||||
val body by bind<TextView>(im.vector.app.R.id.carousel_item_body)
|
||||
}
|
||||
}
|
|
@ -33,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
|
||||
|
@ -60,7 +61,8 @@ class FtueAuthVariant(
|
|||
private val views: ActivityLoginBinding,
|
||||
private val onboardingViewModel: OnboardingViewModel,
|
||||
private val activity: VectorBaseActivity<ActivityLoginBinding>,
|
||||
private val supportFragmentManager: FragmentManager
|
||||
private val supportFragmentManager: FragmentManager,
|
||||
private val vectorFeatures: VectorFeatures
|
||||
) : OnboardingVariant {
|
||||
|
||||
private val enterAnim = R.anim.enter_fade_in
|
||||
|
@ -107,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) {
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape
|
||||
android:innerRadius="0dp"
|
||||
android:shape="ring"
|
||||
android:thickness="4dp"
|
||||
android:useLevel="false">
|
||||
<solid android:color="?vctr_content_quaternary" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape
|
||||
android:innerRadius="0dp"
|
||||
android:shape="ring"
|
||||
android:thickness="4dp"
|
||||
android:useLevel="false">
|
||||
<solid android:color="?colorAccent" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/indicator_onboarding_carousel_selected" android:state_selected="true" />
|
||||
<item android:drawable="@drawable/indicator_onboarding_carousel_inactive" />
|
||||
</selector>
|
88
vector/src/main/res/layout/fragment_ftue_splash_carousel.xml
Normal file
88
vector/src/main/res/layout/fragment_ftue_splash_carousel.xml
Normal file
|
@ -0,0 +1,88 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:colorBackground"
|
||||
android:paddingTop="@dimen/layout_vertical_margin"
|
||||
android:paddingBottom="@dimen/layout_vertical_margin">
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/splashCarousel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/loginSplashSubmit"
|
||||
app:layout_constraintHeight_percent="0.5"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/carouselIndicator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
app:layout_constraintBottom_toTopOf="@id/loginSplashSubmit"
|
||||
app:layout_constraintTop_toBottomOf="@id/splashCarousel"
|
||||
app:tabBackground="@drawable/indicator_onboarding_carousel_selector"
|
||||
app:tabGravity="center"
|
||||
app:tabIndicatorHeight="0dp"
|
||||
app:tabPaddingEnd="8dp"
|
||||
app:tabPaddingStart="8dp" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/splashCarouselGutterStart"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_begin="36dp" />
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/splashCarouselGutterEnd"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintGuide_end="36dp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/loginSplashSubmit"
|
||||
style="@style/Widget.Vector.Button.Login"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/login_splash_submit"
|
||||
android:textAllCaps="true"
|
||||
android:transitionName="loginSubmitTransition"
|
||||
app:layout_constraintBottom_toTopOf="@id/loginSplashAlreadyHaveAccount"
|
||||
app:layout_constraintEnd_toEndOf="@id/splashCarouselGutterEnd"
|
||||
app:layout_constraintStart_toStartOf="@id/splashCarouselGutterStart"
|
||||
app:layout_constraintTop_toBottomOf="@id/carouselIndicator" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginSplashAlreadyHaveAccount"
|
||||
style="@style/Widget.Vector.Button.Text.Login"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/login_splash_already_have_account"
|
||||
android:textAllCaps="true"
|
||||
android:transitionName="loginSubmitTransition"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/splashCarouselGutterEnd"
|
||||
app:layout_constraintStart_toStartOf="@id/splashCarouselGutterStart"
|
||||
app:layout_constraintTop_toBottomOf="@id/loginSplashSubmit" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/loginSplashVersion"
|
||||
style="@style/Widget.Vector.TextView.Caption"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawablePadding="12dp"
|
||||
android:textColor="?vctr_content_secondary"
|
||||
android:visibility="gone"
|
||||
app:drawableStartCompat="@drawable/ic_debug_icon"
|
||||
app:drawableTint="?colorPrimary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@id/splashCarouselGutterEnd"
|
||||
app:layout_constraintStart_toStartOf="@id/splashCarouselGutterStart"
|
||||
tools:text="@string/settings_version"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
28
vector/src/main/res/layout/item_splash_carousel.xml
Normal file
28
vector/src/main/res/layout/item_splash_carousel.xml
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/carousel_item_image"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_gravity="center"
|
||||
android:adjustViewBounds="true"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/carousel_item_body"
|
||||
style="@style/Widget.Vector.TextView.Title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:textColor="?vctr_content_primary"
|
||||
tools:text="Login version" />
|
||||
|
||||
</LinearLayout>
|
Loading…
Add table
Reference in a new issue