Skip to content

Commit e657354

Browse files
authored
Android: streamline home screen load (#1124)
* mockup version of our omnibar to load it in browserActivity and speed up first rendered screen * replace contraintlayout for framelayout, optimization * show mockup toolbar in browseractivity * Refactor DDGLogoListener to just hide-show background image * no transitions to smooth process restart * Remove Toast from BrowserActivity * Avoid to initialise dependency injection when process restarting due to clear data * should notify if data cleared triggered by system and not the user * hide mockup omnibar when fragment attached * logo margin dimens added to resource file * avoid crash if no clicklistener set for TabSwitcherButton * remove any HomeTopPanelCta reference from code
1 parent c3b4098 commit e657354

27 files changed

+298
-412
lines changed

app/src/main/java/com/duckduckgo/app/browser/BrowserActivity.kt

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import android.content.Intent
2222
import android.content.Intent.EXTRA_TEXT
2323
import android.os.Bundle
2424
import android.os.Message
25+
import android.view.View
2526
import android.widget.Toast
2627
import androidx.fragment.app.DialogFragment
2728
import androidx.lifecycle.Observer
@@ -53,6 +54,7 @@ import com.duckduckgo.app.statistics.pixels.Pixel.PixelName.FIRE_DIALOG_CANCEL
5354
import com.duckduckgo.app.statistics.pixels.Pixel.PixelName.FIRE_DIALOG_PROMOTED_CANCEL
5455
import com.duckduckgo.app.tabs.model.TabEntity
5556
import kotlinx.android.synthetic.main.activity_browser.*
57+
import kotlinx.android.synthetic.main.include_omnibar_toolbar_mockup.*
5658
import kotlinx.coroutines.*
5759
import org.jetbrains.anko.longToast
5860
import timber.log.Timber
@@ -203,14 +205,14 @@ class BrowserActivity : DuckDuckGoActivity(), CoroutineScope by MainScope() {
203205
GlobalScope.launch {
204206
clearPersonalDataAction.clearTabsAndAllDataAsync(appInForeground = true, shouldFireDataClearPixel = true)
205207
clearPersonalDataAction.setAppUsedSinceLastClearFlag(false)
206-
clearPersonalDataAction.killAndRestartProcess()
208+
clearPersonalDataAction.killAndRestartProcess(notifyDataCleared = false)
207209
}
208210

209211
return
210212
}
211213

212-
if (intent.getBooleanExtra(LAUNCHED_FROM_FIRE_EXTRA, false)) {
213-
Timber.i("Launched from fire")
214+
if (intent.getBooleanExtra(NOTIFY_DATA_CLEARED_EXTRA, false)) {
215+
Timber.i("Should notify data cleared")
214216
Toast.makeText(applicationContext, R.string.fireDataCleared, Toast.LENGTH_LONG).show()
215217
}
216218

@@ -365,24 +367,33 @@ class BrowserActivity : DuckDuckGoActivity(), CoroutineScope by MainScope() {
365367
}
366368
}
367369

370+
override fun onAttachFragment(fragment: androidx.fragment.app.Fragment) {
371+
super.onAttachFragment(fragment)
372+
hideMockupOmnibar()
373+
}
374+
375+
private fun hideMockupOmnibar() {
376+
appBarLayoutMockup.visibility = View.GONE
377+
}
378+
368379
companion object {
369380

370381
fun intent(
371382
context: Context,
372383
queryExtra: String? = null,
373384
newSearch: Boolean = false,
374-
launchedFromFireAction: Boolean = false
385+
notifyDataCleared: Boolean = false
375386
): Intent {
376387
val intent = Intent(context, BrowserActivity::class.java)
377388
intent.putExtra(EXTRA_TEXT, queryExtra)
378389
intent.putExtra(NEW_SEARCH_EXTRA, newSearch)
379-
intent.putExtra(LAUNCHED_FROM_FIRE_EXTRA, launchedFromFireAction)
390+
intent.putExtra(NOTIFY_DATA_CLEARED_EXTRA, notifyDataCleared)
380391
return intent
381392
}
382393

383394
const val NEW_SEARCH_EXTRA = "NEW_SEARCH_EXTRA"
384395
const val PERFORM_FIRE_ON_ENTRY_EXTRA = "PERFORM_FIRE_ON_ENTRY_EXTRA"
385-
const val LAUNCHED_FROM_FIRE_EXTRA = "LAUNCHED_FROM_FIRE_EXTRA"
396+
const val NOTIFY_DATA_CLEARED_EXTRA = "NOTIFY_DATA_CLEARED_EXTRA"
386397
const val LAUNCH_FROM_DEFAULT_BROWSER_DIALOG = "LAUNCH_FROM_DEFAULT_BROWSER_DIALOG"
387398

388399
private const val APP_ENJOYMENT_DIALOG_TAG = "AppEnjoyment"

app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt

Lines changed: 6 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
package com.duckduckgo.app.browser
1818

1919
import android.Manifest
20-
import android.animation.LayoutTransition.CHANGING
21-
import android.animation.LayoutTransition.DISAPPEARING
2220
import android.annotation.SuppressLint
2321
import android.app.Activity.RESULT_OK
2422
import android.app.ActivityOptions
@@ -28,10 +26,7 @@ import android.content.pm.PackageManager
2826
import android.content.res.Configuration
2927
import android.media.MediaScannerConnection
3028
import android.net.Uri
31-
import android.os.Bundle
32-
import android.os.Environment
33-
import android.os.Handler
34-
import android.os.Message
29+
import android.os.*
3530
import android.provider.Settings
3631
import android.text.Editable
3732
import android.view.*
@@ -111,7 +106,6 @@ import com.duckduckgo.widget.SearchWidgetLight
111106
import com.google.android.material.snackbar.Snackbar
112107
import dagger.android.support.AndroidSupportInjection
113108
import kotlinx.android.synthetic.main.fragment_browser_tab.*
114-
import kotlinx.android.synthetic.main.include_add_widget_instruction_buttons.view.*
115109
import kotlinx.android.synthetic.main.include_cta_buttons.view.*
116110
import kotlinx.android.synthetic.main.include_dax_dialog_cta.*
117111
import kotlinx.android.synthetic.main.include_dax_dialog_cta.view.*
@@ -265,7 +259,7 @@ class BrowserTabFragment :
265259
}
266260
}
267261

268-
private val logoHidingListener by lazy { LogoHidingLayoutChangeLifecycleListener(ddgLogo) }
262+
private val homeBackgroundLogo by lazy { HomeBackgroundLogo(ddgLogo) }
269263

270264
private val ctaViewStateObserver = Observer<CtaViewState> {
271265
it?.let { renderer.renderCtaViewState(it) }
@@ -304,7 +298,6 @@ class BrowserTabFragment :
304298
configureOmnibarTextInput()
305299
configureFindInPage()
306300
configureAutoComplete()
307-
configureKeyboardAwareLogoAnimation()
308301

309302
decorator.decorateWithFeatures()
310303

@@ -366,7 +359,6 @@ class BrowserTabFragment :
366359

367360
appBarLayout.setExpanded(true)
368361
viewModel.onViewResumed()
369-
logoHidingListener.onResume()
370362

371363
// onResume can be called for a hidden/backgrounded fragment, ensure this tab is visible.
372364
if (fragmentIsVisible()) {
@@ -377,7 +369,6 @@ class BrowserTabFragment :
377369
}
378370

379371
override fun onPause() {
380-
logoHidingListener.onPause()
381372
dismissDownloadFragment()
382373
dismissAuthenticationDialog()
383374
super.onPause()
@@ -492,14 +483,15 @@ class BrowserTabFragment :
492483
webView?.onPause()
493484
webView?.hide()
494485
omnibarScrolling.disableOmnibarScrolling(toolbarContainer)
495-
logoHidingListener.onReadyToShowLogo()
486+
homeBackgroundLogo.showLogo()
496487
}
497488

498489
private fun showBrowser() {
499490
newTabLayout.gone()
500491
webView?.show()
501492
webView?.onResume()
502493
omnibarScrolling.enableOmnibarScrolling(toolbarContainer)
494+
homeBackgroundLogo.hideLogo()
503495
}
504496

505497
fun submitQuery(query: String) {
@@ -934,16 +926,6 @@ class BrowserTabFragment :
934926
clearTextButton.setOnClickListener { omnibarTextInput.setText("") }
935927
}
936928

937-
private fun configureKeyboardAwareLogoAnimation() {
938-
newTabLayout.layoutTransition?.apply {
939-
// we want layout transitions for when the size changes; we don't want them when items disappear (can cause glitch on call to action button)
940-
enableTransitionType(CHANGING)
941-
disableTransitionType(DISAPPEARING)
942-
setDuration(LAYOUT_TRANSITION_MS)
943-
}
944-
rootView.addOnLayoutChangeListener(logoHidingListener)
945-
}
946-
947929
private fun userSelectedAutocomplete(suggestion: AutoCompleteSuggestion) {
948930
// send pixel before submitting the query and changing the autocomplete state to empty; otherwise will send the wrong params
949931
GlobalScope.launch {
@@ -1817,16 +1799,13 @@ class BrowserTabFragment :
18171799
}
18181800

18191801
renderIfChanged(viewState, lastSeenCtaViewState) {
1820-
1821-
ddgLogo.show()
18221802
lastSeenCtaViewState = viewState
18231803
removeNewTabLayoutClickListener()
18241804
if (viewState.cta != null) {
18251805
showCta(viewState.cta)
18261806
} else {
18271807
hideHomeCta()
18281808
hideDaxCta()
1829-
hideHomeTopCta()
18301809
}
18311810
}
18321811
}
@@ -1836,7 +1815,6 @@ class BrowserTabFragment :
18361815
is HomePanelCta -> showHomeCta(configuration)
18371816
is DaxBubbleCta -> showDaxCta(configuration)
18381817
is DialogCta -> showDaxDialogCta(configuration)
1839-
is HomeTopPanelCta -> showHomeTopCta(configuration)
18401818
}
18411819

18421820
viewModel.onCtaShown()
@@ -1859,9 +1837,8 @@ class BrowserTabFragment :
18591837
}
18601838

18611839
private fun showDaxCta(configuration: DaxBubbleCta) {
1862-
ddgLogo.hide()
1840+
homeBackgroundLogo.hideLogo()
18631841
hideHomeCta()
1864-
hideHomeTopCta()
18651842
configuration.showCta(daxCtaContainer)
18661843
newTabLayout.setOnClickListener { daxCtaContainer.dialogTextCta.finishAnimation() }
18671844
}
@@ -1870,29 +1847,14 @@ class BrowserTabFragment :
18701847
newTabLayout.setOnClickListener(null)
18711848
}
18721849

1873-
private fun showHomeTopCta(configuration: HomeTopPanelCta) {
1874-
hideDaxCta()
1875-
hideHomeCta()
1876-
1877-
logoHidingListener.callToActionView = ctaTopContainer
1878-
1879-
configuration.showCta(ctaTopContainer)
1880-
ctaTopContainer.setOnClickListener {
1881-
viewModel.onUserClickTopCta(configuration)
1882-
}
1883-
ctaTopContainer.closeButton.setOnClickListener {
1884-
viewModel.onUserDismissedCta()
1885-
}
1886-
}
1887-
18881850
private fun showHomeCta(configuration: HomePanelCta) {
18891851
hideDaxCta()
1890-
hideHomeTopCta()
18911852
if (ctaContainer.isEmpty()) {
18921853
renderHomeCta()
18931854
} else {
18941855
configuration.showCta(ctaContainer)
18951856
}
1857+
homeBackgroundLogo.showLogo()
18961858
}
18971859

18981860
private fun hideDaxCta() {
@@ -1904,10 +1866,6 @@ class BrowserTabFragment :
19041866
ctaContainer.gone()
19051867
}
19061868

1907-
private fun hideHomeTopCta() {
1908-
ctaTopContainer.gone()
1909-
}
1910-
19111869
fun renderHomeCta() {
19121870
val context = context ?: return
19131871
val cta = lastSeenCtaViewState?.cta ?: return
@@ -1916,7 +1874,6 @@ class BrowserTabFragment :
19161874
ctaContainer.removeAllViews()
19171875

19181876
inflate(context, R.layout.include_cta, ctaContainer)
1919-
logoHidingListener.callToActionView = ctaContainer
19201877

19211878
configuration.showCta(ctaContainer)
19221879
ctaContainer.ctaOkButton.setOnClickListener {

app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1630,9 +1630,6 @@ class BrowserTabViewModel(
16301630
}
16311631
}
16321632

1633-
fun onUserClickTopCta(cta: HomeTopPanelCta) {
1634-
}
1635-
16361633
fun onUserClickCtaOkButton() {
16371634
val cta = currentCtaViewState().cta ?: return
16381635
ctaViewModel.onUserClickCtaOkButton(cta)
@@ -1678,9 +1675,6 @@ class BrowserTabViewModel(
16781675
viewModelScope.launch {
16791676
ctaViewModel.onUserDismissedCta(cta)
16801677
when (cta) {
1681-
is HomeTopPanelCta -> {
1682-
ctaViewState.value = currentCtaViewState().copy(cta = null)
1683-
}
16841678
is HomePanelCta -> refreshCta()
16851679
else -> ctaViewState.value = currentCtaViewState().copy(cta = null)
16861680
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright (c) 2018 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.app.browser
18+
19+
import android.view.View
20+
import android.view.animation.AccelerateInterpolator
21+
import com.duckduckgo.app.global.view.hide
22+
import com.duckduckgo.app.global.view.show
23+
import timber.log.Timber
24+
25+
class HomeBackgroundLogo(private var ddgLogoView: View) {
26+
27+
private var readyToShowLogo = false
28+
29+
fun showLogo() {
30+
this.readyToShowLogo = true
31+
update()
32+
}
33+
34+
fun hideLogo() {
35+
readyToShowLogo = false
36+
update()
37+
}
38+
39+
private fun update() {
40+
if (readyToShowLogo) {
41+
fadeLogoIn()
42+
} else {
43+
fadeLogoOut()
44+
}
45+
}
46+
47+
private fun fadeLogoIn() {
48+
Timber.v("showLogo")
49+
// To avoid glitches when calling show/hide logo within a small amount of time we keep this 50ms animation
50+
ddgLogoView.animate().apply {
51+
duration = FADE_IN_DURATION
52+
interpolator = AccelerateInterpolator()
53+
alpha(1f)
54+
ddgLogoView.show()
55+
}
56+
}
57+
58+
private fun fadeLogoOut() {
59+
Timber.v("hideLogo")
60+
ddgLogoView.hide()
61+
}
62+
63+
companion object {
64+
private const val FADE_IN_DURATION = 50L
65+
}
66+
}

0 commit comments

Comments
 (0)