diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt index fcdf4074bd31..de701ebb767c 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt @@ -114,6 +114,7 @@ import kotlinx.android.synthetic.main.fragment_browser_tab.* import kotlinx.android.synthetic.main.include_add_widget_instruction_buttons.view.* import kotlinx.android.synthetic.main.include_cta_buttons.view.* import kotlinx.android.synthetic.main.include_dax_dialog_cta.* +import kotlinx.android.synthetic.main.include_dax_dialog_cta.view.* import kotlinx.android.synthetic.main.include_find_in_page.* import kotlinx.android.synthetic.main.include_new_browser_tab.* import kotlinx.android.synthetic.main.include_omnibar_toolbar.* @@ -1793,6 +1794,7 @@ class BrowserTabFragment : ddgLogo.show() lastSeenCtaViewState = viewState + removeNewTabLayoutClickListener() if (viewState.cta != null) { showCta(viewState.cta) } else { @@ -1835,6 +1837,11 @@ class BrowserTabFragment : hideHomeCta() hideHomeTopCta() configuration.showCta(daxCtaContainer) + newTabLayout.setOnClickListener { daxCtaContainer.dialogTextCta.finishAnimation() } + } + + private fun removeNewTabLayoutClickListener() { + newTabLayout.setOnClickListener(null) } private fun showHomeTopCta(configuration: HomeTopPanelCta) { diff --git a/app/src/main/java/com/duckduckgo/app/cta/ui/Cta.kt b/app/src/main/java/com/duckduckgo/app/cta/ui/Cta.kt index 9f7226e38079..ce98c72b4346 100644 --- a/app/src/main/java/com/duckduckgo/app/cta/ui/Cta.kt +++ b/app/src/main/java/com/duckduckgo/app/cta/ui/Cta.kt @@ -132,7 +132,7 @@ sealed class DaxDialogCta( ) : Cta, DialogCta, DaxCta { override fun createCta(activity: FragmentActivity): DaxDialog = - TypewriterDaxDialog.newInstance(getDaxText(activity), activity.resources.getString(okButton)) + TypewriterDaxDialog.newInstance(daxText = getDaxText(activity), primaryButtonText = activity.resources.getString(okButton)) override fun pixelCancelParameters(): Map = mapOf(Pixel.PixelParameter.CTA_SHOWN to ctaPixelParam) @@ -255,7 +255,6 @@ sealed class DaxDialogCta( private const val MAX_TRACKERS_SHOWS = 2 const val SERP = "duckduckgo" private val mainTrackerDomains = listOf("facebook", "google") - private val networkPropertyPercentages = mapOf(Pair("Google", "90%"), Pair("Facebook", "40%")) val mainTrackerNetworks = listOf("Facebook", "Google") } } diff --git a/app/src/main/java/com/duckduckgo/app/global/view/DaxDialog.kt b/app/src/main/java/com/duckduckgo/app/global/view/DaxDialog.kt index 899dfddca6e3..4d4654eb1205 100644 --- a/app/src/main/java/com/duckduckgo/app/global/view/DaxDialog.kt +++ b/app/src/main/java/com/duckduckgo/app/global/view/DaxDialog.kt @@ -51,7 +51,7 @@ class TypewriterDaxDialog : DialogFragment(), DaxDialog { private var primaryButtonText: String = "" private var secondaryButtonText: String = "" private var toolbarDimmed: Boolean = true - private var dismissible: Boolean = true + private var dismissible: Boolean = false private var typingDelayInMs: Long = DEFAULT_TYPING_DELAY private var showHideButton: Boolean = true @@ -161,10 +161,14 @@ class TypewriterDaxDialog : DialogFragment(), DaxDialog { dismiss() } - if (dismissible) { - dialogContainer.setOnClickListener { + dialogContainer.setOnClickListener { + if (dismissible) { dialogText.cancelAnimation() dismiss() + } else { + if (!dialogText.hasAnimationFinished()) { + dialogText.finishAnimation() + } } } } @@ -194,7 +198,7 @@ class TypewriterDaxDialog : DialogFragment(), DaxDialog { primaryButtonText: String, secondaryButtonText: String? = "", toolbarDimmed: Boolean = true, - dismissible: Boolean = true, + dismissible: Boolean = false, typingDelayInMs: Long = DEFAULT_TYPING_DELAY, showHideButton: Boolean = true ): TypewriterDaxDialog { diff --git a/app/src/main/java/com/duckduckgo/app/global/view/TypeAnimationTextView.kt b/app/src/main/java/com/duckduckgo/app/global/view/TypeAnimationTextView.kt index 8d459d4bad53..ab9a0c6a44c7 100644 --- a/app/src/main/java/com/duckduckgo/app/global/view/TypeAnimationTextView.kt +++ b/app/src/main/java/com/duckduckgo/app/global/view/TypeAnimationTextView.kt @@ -17,6 +17,7 @@ package com.duckduckgo.app.global.view import android.content.Context +import android.text.Spanned import android.util.AttributeSet import androidx.appcompat.widget.AppCompatTextView import kotlinx.coroutines.* @@ -34,29 +35,40 @@ class TypeAnimationTextView @JvmOverloads constructor( private var typingAnimationJob: Job? = null private var delayAfterAnimationInMs: Long = 300 var typingDelayInMs: Long = 20 + var textInDialog: Spanned? = null fun startTypingAnimation(textDialog: String, isCancellable: Boolean = true, afterAnimation: () -> Unit = {}) { - val inputText = textDialog.html(context) + textInDialog = textDialog.html(context) if (isCancellable) { setOnClickListener { - if (typingAnimationJob?.isActive == true) { - cancelAnimation() - text = inputText + if (hasAnimationStarted()) { + finishAnimation() afterAnimation() } } } typingAnimationJob = launch { - inputText.mapIndexed { index, _ -> - text = inputText.subSequence(0, index + 1) - delay(typingDelayInMs) + textInDialog?.let { + it.mapIndexed { index, _ -> + text = it.subSequence(0, index + 1) + delay(typingDelayInMs) + } + delay(delayAfterAnimationInMs) + afterAnimation() } - delay(delayAfterAnimationInMs) - afterAnimation() } } + fun hasAnimationStarted() = typingAnimationJob?.isActive == true + + fun hasAnimationFinished() = typingAnimationJob?.isCompleted == true + + fun finishAnimation() { + cancelAnimation() + textInDialog?.let { text = it } + } + fun cancelAnimation() = typingAnimationJob?.cancel() override fun onDetachedFromWindow() { diff --git a/app/src/main/java/com/duckduckgo/app/onboarding/ui/page/WelcomePage.kt b/app/src/main/java/com/duckduckgo/app/onboarding/ui/page/WelcomePage.kt index 02b15bfd125e..50e44338c409 100644 --- a/app/src/main/java/com/duckduckgo/app/onboarding/ui/page/WelcomePage.kt +++ b/app/src/main/java/com/duckduckgo/app/onboarding/ui/page/WelcomePage.kt @@ -51,6 +51,7 @@ class WelcomePage : OnboardingPageFragment() { private var ctaText: String = "" private var welcomeAnimation: ViewPropertyAnimatorCompat? = null private var typingAnimation: ViewPropertyAnimatorCompat? = null + private var welcomeAnimationFinished = false // we use a BroadcastChannel because we don't want to emit the last value upon subscription private val events = BroadcastChannel(1) @@ -65,7 +66,8 @@ class WelcomePage : OnboardingPageFragment() { super.onActivityCreated(savedInstanceState) configureDaxCta() - beginWelcomeAnimation(ctaText) + scheduleWelcomeAnimation() + setSkipAnimationListener() } override fun onAttach(context: Context) { @@ -145,28 +147,48 @@ class WelcomePage : OnboardingPageFragment() { context?.let { ctaText = it.getString(R.string.onboardingDaxText) hiddenTextCta.text = ctaText.html(it) + dialogTextCta.textInDialog = ctaText.html(it) dialogTextCta.setTextColor(ContextCompat.getColor(it, R.color.grayishBrown)) cardView.backgroundTintList = ContextCompat.getColorStateList(it, R.color.white) } triangle.setImageResource(R.drawable.ic_triangle_bubble_white) } - private fun beginWelcomeAnimation(ctaText: String) { + private fun setSkipAnimationListener() { + longDescriptionContainer.setOnClickListener { + if (dialogTextCta.hasAnimationStarted()) { + finishTypingAnimation() + } else if (!welcomeAnimationFinished) { + welcomeAnimation?.cancel() + scheduleWelcomeAnimation(0L) + } + welcomeAnimationFinished = true + } + } + + private fun scheduleWelcomeAnimation(startDelay: Long = ANIMATION_DELAY) { welcomeAnimation = ViewCompat.animate(welcomeContent as View) .alpha(MIN_ALPHA) .setDuration(ANIMATION_DURATION) - .setStartDelay(ANIMATION_DELAY) + .setStartDelay(startDelay) .withEndAction { typingAnimation = ViewCompat.animate(daxCtaContainer) .alpha(MAX_ALPHA) .setDuration(ANIMATION_DURATION) .withEndAction { + welcomeAnimationFinished = true dialogTextCta.startTypingAnimation(ctaText) setPrimaryCtaListenerAfterWelcomeAlphaAnimation() } } } + private fun finishTypingAnimation() { + welcomeAnimation?.cancel() + dialogTextCta.finishAnimation() + setPrimaryCtaListenerAfterWelcomeAlphaAnimation() + } + private fun setPrimaryCtaListenerAfterWelcomeAlphaAnimation() { primaryCta.setOnClickListener { event(WelcomePageView.Event.OnPrimaryCtaClicked) } } diff --git a/app/src/main/res/drawable/ic_dax_icon.xml b/app/src/main/res/drawable/ic_dax_icon.xml index ea6e5b3b5cbf..392c832cdd97 100644 --- a/app/src/main/res/drawable/ic_dax_icon.xml +++ b/app/src/main/res/drawable/ic_dax_icon.xml @@ -1,5 +1,5 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/include_new_browser_tab.xml b/app/src/main/res/layout/include_new_browser_tab.xml index df4521ae1bc9..f6c9bfe78b18 100644 --- a/app/src/main/res/layout/include_new_browser_tab.xml +++ b/app/src/main/res/layout/include_new_browser_tab.xml @@ -22,6 +22,7 @@ android:layout_height="match_parent" android:layout_marginTop="?attr/actionBarSize" android:animateLayoutChanges="true" + android:foreground="@android:color/transparent" tools:context="com.duckduckgo.app.browser.BrowserActivity" tools:showIn="@layout/fragment_browser_tab">