diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt index 2217c5ece..686fea468 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -19,14 +19,10 @@ import android.widget.LinearLayout import android.widget.PopupWindow import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog -import androidx.constraintlayout.widget.ConstraintSet -import androidx.constraintlayout.widget.ConstraintSet.BOTTOM -import androidx.constraintlayout.widget.ConstraintSet.END -import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID -import androidx.constraintlayout.widget.ConstraintSet.START -import androidx.constraintlayout.widget.ConstraintSet.TOP -import androidx.core.view.updateLayoutParams +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.ContextCompat +import androidx.core.view.updateLayoutParams import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.lifecycle.Lifecycle @@ -41,6 +37,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE import androidx.transition.TransitionInflater +import com.google.android.material.appbar.AppBarLayout import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.fragment_home.view.* @@ -91,6 +88,7 @@ import org.mozilla.fenix.theme.ThemeManager import org.mozilla.fenix.utils.FragmentPreDrawManager import org.mozilla.fenix.utils.allowUndo import org.mozilla.fenix.whatsnew.WhatsNew +import kotlin.math.abs import kotlin.math.min @ExperimentalCoroutinesApi @@ -106,7 +104,7 @@ class HomeFragment : Fragment() { } private val browsingModeManager get() = (activity as HomeActivity).browsingModeManager - + private var homeAppBarOffset = 0 private val singleSessionObserver = object : Session.Observer { override fun onTitleChanged(session: Session, title: String) { if (deleteAllSessionsJob == null) emitSessionChanges() @@ -142,7 +140,7 @@ class HomeFragment : Fragment() { private val onboarding by lazy { FenixOnboarding(requireContext()) } private lateinit var homeFragmentStore: HomeFragmentStore private lateinit var sessionControlInteractor: SessionControlInteractor - private lateinit var sessionControlView: SessionControlView + private var sessionControlView: SessionControlView? = null private lateinit var currentMode: CurrentMode override fun onCreate(savedInstanceState: Bundle?) { @@ -195,7 +193,6 @@ class HomeFragment : Fragment() { activity = activity, store = homeFragmentStore, navController = findNavController(), - homeLayout = view.homeLayout, browsingModeManager = browsingModeManager, lifecycleScope = viewLifecycleOwner.lifecycleScope, closeTab = ::closeTab, @@ -209,37 +206,32 @@ class HomeFragment : Fragment() { ) ) - sessionControlView = SessionControlView(homeFragmentStore, view.homeLayout, sessionControlInteractor) + view.homeAppBar.addOnOffsetChangedListener( + AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> + appBarLayout.alpha = + 1.0f - abs(verticalOffset / appBarLayout.totalScrollRange.toFloat()) + } + ) + setOffset(view) + + + sessionControlView = SessionControlView(homeFragmentStore, + view.sessionControlRecyclerView, sessionControlInteractor) updateLayout(view) - activity.themeManager.applyStatusBarTheme(activity) - return view } private fun updateLayout(view: View) { val shouldUseBottomToolbar = view.context.settings().shouldUseBottomToolbar - ConstraintSet().apply { - clone(view.homeLayout) - if (shouldUseBottomToolbar) { - connect(sessionControlView.view.id, TOP, view.wordmark.id, BOTTOM) - connect(sessionControlView.view.id, BOTTOM, view.toolbarLayout.id, TOP) - - connect(view.toolbarLayout.id, BOTTOM, PARENT_ID, BOTTOM) - connect(view.privateBrowsingButton.id, TOP, PARENT_ID, TOP) - } else { - connect(sessionControlView.view.id, TOP, view.wordmark.id, TOP) - connect(sessionControlView.view.id, BOTTOM, PARENT_ID, BOTTOM) - - connect(view.privateBrowsingButton.id, TOP, view.toolbarLayout.id, BOTTOM) - } - connect(sessionControlView.view.id, START, PARENT_ID, START) - connect(sessionControlView.view.id, END, PARENT_ID, END) - - applyTo(view.homeLayout) + if(!shouldUseBottomToolbar){ + view.toolbarLayout.layoutParams = CoordinatorLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.WRAP_CONTENT) + .apply { + gravity = Gravity.TOP + } } val headingsTopMargins = if (shouldUseBottomToolbar) { HEADER_MARGIN } else { TOP_TOOLBAR_HEADER_MARGIN } @@ -253,7 +245,7 @@ class HomeFragment : Fragment() { topMargin = headingsTopMargins.dpToPx(resources.displayMetrics) } - sessionControlView.view.updateLayoutParams { + sessionControlView!!.view.updateLayoutParams { topMargin = sessionControlViewTopMargin.dpToPx(resources.displayMetrics) } @@ -263,7 +255,6 @@ class HomeFragment : Fragment() { } } } - @ExperimentalCoroutinesApi @SuppressWarnings("LongMethod") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -274,9 +265,8 @@ class HomeFragment : Fragment() { ViewModelProvider.NewInstanceFactory() // this is a workaround for #4652 } homeViewModel.layoutManagerState?.also { parcelable -> - sessionControlView.view.layoutManager?.onRestoreInstanceState(parcelable) + sessionControlView!!.view.layoutManager?.onRestoreInstanceState(parcelable) } - homeLayout?.progress = homeViewModel.motionLayoutProgress homeViewModel.layoutManagerState = null } @@ -350,6 +340,11 @@ class HomeFragment : Fragment() { } } + override fun onDestroyView() { + sessionControlView = null + super.onDestroyView() + } + override fun onStart() { super.onStart() subscribeToTabCollections() @@ -476,8 +471,7 @@ class HomeFragment : Fragment() { ViewModelProvider.NewInstanceFactory() // this is a workaround for #4652 } homeViewModel.layoutManagerState = - sessionControlView.view.layoutManager?.onSaveInstanceState() - homeViewModel.motionLayoutProgress = homeLayout?.progress ?: 0F + sessionControlView!!.view.layoutManager?.onSaveInstanceState() } override fun onResume() { @@ -485,6 +479,11 @@ class HomeFragment : Fragment() { hideToolbar() } + override fun onPause() { + super.onPause() + calculateNewOffset() + } + private fun recommendPrivateBrowsingShortcut() { context?.let { val layout = LayoutInflater.from(it) @@ -710,7 +709,7 @@ class HomeFragment : Fragment() { private fun scrollToTheTop() { lifecycleScope.launch(Main) { delay(ANIM_SCROLL_DELAY) - sessionControlView.view.smoothScrollToPosition(0) + sessionControlView!!.view.smoothScrollToPosition(0) } } @@ -720,7 +719,7 @@ class HomeFragment : Fragment() { ) { if (view != null) { viewLifecycleOwner.lifecycleScope.launch { - val recyclerView = sessionControlView.view + val recyclerView = sessionControlView!!.view delay(ANIM_SCROLL_DELAY) val tabsSize = getListOfSessions().size @@ -763,7 +762,7 @@ class HomeFragment : Fragment() { private fun animateCollection(addedTabsSize: Int, indexOfCollection: Int) { viewLifecycleOwner.lifecycleScope.launch { val viewHolder = - sessionControlView.view.findViewHolderForAdapterPosition(indexOfCollection) + sessionControlView!!.view.findViewHolderForAdapterPosition(indexOfCollection) val border = (viewHolder as? CollectionViewHolder)?.view?.findViewById(R.id.selected_border) val listener = object : Animator.AnimatorListener { @@ -830,6 +829,23 @@ class HomeFragment : Fragment() { } } + private fun calculateNewOffset() { + homeAppBarOffset = ((view!!.findViewById(R.id.homeAppBar) + .layoutParams as CoordinatorLayout.LayoutParams) + .behavior as AppBarLayout.Behavior).topAndBottomOffset + } + + private fun setOffset(currentView: View) { + if (homeAppBarOffset <= 0) { + (currentView.homeAppBar.layoutParams as CoordinatorLayout.LayoutParams) + .behavior = AppBarLayout.Behavior().apply { + topAndBottomOffset = this@HomeFragment.homeAppBarOffset + } + } else { + currentView.homeAppBar.setExpanded(false) + } + } + companion object { private const val NON_TAB_ITEM_NUM = 3 private const val ANIM_SCROLL_DELAY = 100L diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt index d706bace1..78932e0d7 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt @@ -5,7 +5,6 @@ package org.mozilla.fenix.home.sessioncontrol import android.view.View -import androidx.constraintlayout.motion.widget.MotionLayout import androidx.navigation.NavController import androidx.navigation.fragment.FragmentNavigator import kotlinx.coroutines.CoroutineScope @@ -151,7 +150,6 @@ class DefaultSessionControlController( private val activity: HomeActivity, private val store: HomeFragmentStore, private val navController: NavController, - private val homeLayout: MotionLayout, private val browsingModeManager: BrowsingModeManager, private val lifecycleScope: CoroutineScope, private val closeTab: (sessionId: String) -> Unit, @@ -357,7 +355,6 @@ class DefaultSessionControlController( } override fun handleStartBrowsingClicked() { - homeLayout.progress = 0F hideOnboarding() } diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt index 82cbc5725..e5bcf349b 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt @@ -5,9 +5,7 @@ package org.mozilla.fenix.home.sessioncontrol import android.os.Build -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup import androidx.lifecycle.ProcessLifecycleOwner import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager @@ -135,22 +133,18 @@ private fun collectionTabItems(collection: TabCollection) = collection.tabs.mapI @ExperimentalCoroutinesApi class SessionControlView( private val homeFragmentStore: HomeFragmentStore, - private val container: ViewGroup, + override val containerView: View?, interactor: SessionControlInteractor ) : LayoutContainer { - override val containerView: View? - get() = container - val view: RecyclerView = LayoutInflater.from(container.context) - .inflate(R.layout.component_session_control, container, true) - .findViewById(R.id.home_component) + val view: RecyclerView = containerView as RecyclerView private val sessionControlAdapter = SessionControlAdapter(interactor) init { view.apply { adapter = sessionControlAdapter - layoutManager = LinearLayoutManager(container.context) + layoutManager = LinearLayoutManager(containerView!!.context) val itemTouchHelper = ItemTouchHelper( SwipeToDeleteCallback( diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 49f80d54a..d4a89c0d2 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -2,62 +2,101 @@ - + + android:background="?homeBackground"> - + - + + + + + + + + + + - - + android:overScrollMode="never" + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"/> + android:layout_gravity="bottom" + tools:context=".home.HomeFragment"> + + + app:layout_constraintStart_toStartOf="parent" /> + app:layout_constraintTop_toTopOf="@id/bottom_bar"> @@ -118,8 +157,9 @@ android:layout_width="36dp" android:layout_height="48dp" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent"/> + app:layout_constraintTop_toTopOf="@id/bottom_bar" + app:layout_constraintBottom_toBottomOf="@id/bottom_bar"/> + - + \ No newline at end of file diff --git a/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt b/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt index ea6bf4098..52c8531c9 100644 --- a/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt +++ b/app/src/test/java/org/mozilla/fenix/home/DefaultSessionControlControllerTest.kt @@ -72,7 +72,6 @@ class DefaultSessionControlControllerTest { activity = activity, store = store, navController = navController, - homeLayout = homeLayout, browsingModeManager = browsingModeManager, lifecycleScope = MainScope(), closeTab = closeTab,