1
0
Fork 0
fenix/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt

258 lines
10 KiB
Kotlin
Raw Normal View History

/* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
2019-01-09 23:22:58 +01:00
package org.mozilla.fenix.home
2019-01-29 00:26:37 +01:00
import android.content.res.Resources
import android.graphics.drawable.BitmapDrawable
2019-01-09 23:22:58 +01:00
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.fragment_home.view.*
import mozilla.components.browser.menu.BrowserMenu
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import org.mozilla.fenix.BrowsingModeManager
import org.mozilla.fenix.DefaultThemeManager
import org.mozilla.fenix.HomeActivity
2019-01-09 23:22:58 +01:00
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.home.sessions.ArchivedSession
2019-02-26 00:43:30 +01:00
import org.mozilla.fenix.home.sessions.SessionsAction
import org.mozilla.fenix.home.sessions.SessionsChange
2019-01-28 17:46:39 +01:00
import org.mozilla.fenix.home.sessions.SessionsComponent
import org.mozilla.fenix.home.tabs.TabsAction
import org.mozilla.fenix.home.tabs.TabsChange
import org.mozilla.fenix.home.tabs.TabsComponent
import org.mozilla.fenix.home.tabs.TabsState
import org.mozilla.fenix.home.tabs.toSessionViewState
2019-01-28 17:46:39 +01:00
import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter
2019-01-29 00:26:37 +01:00
import kotlin.math.roundToInt
2019-01-09 23:22:58 +01:00
class HomeFragment : Fragment() {
private val bus = ActionBusFactory.get(this)
private var sessionObserver: SessionManager.Observer? = null
private lateinit var homeMenu: HomeMenu
private lateinit var tabsComponent: TabsComponent
private lateinit var sessionsComponent: SessionsComponent
2019-01-09 23:22:58 +01:00
override fun onCreateView(
2019-01-30 17:36:14 +01:00
inflater: LayoutInflater,
container: ViewGroup?,
2019-01-09 23:22:58 +01:00
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_home, container, false)
val sessionManager = requireComponents.core.sessionManager
tabsComponent = TabsComponent(view.homeContainer, bus, (activity as HomeActivity).browsingModeManager.isPrivate,
TabsState(sessionManager.sessions.map { it.toSessionViewState(it == sessionManager.selectedSession) })
)
sessionsComponent = SessionsComponent(view.homeContainer, bus)
ActionBusFactory.get(this).logMergedObservables()
val activity = activity as HomeActivity
DefaultThemeManager.applyStatusBarTheme(activity.window, activity.themeManager, activity)
return view
2019-01-09 23:22:58 +01:00
}
2019-01-10 01:07:33 +01:00
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setupHomeMenu()
tabsComponent.view.isNestedScrollingEnabled = false
sessionsComponent.view.isNestedScrollingEnabled = false
val bundles = requireComponents.core.sessionStorage.bundles(temporaryNumberOfSessions)
bundles.observe(this, Observer { sessionBundles ->
val archivedSessions = sessionBundles.mapNotNull { sessionBundle ->
sessionBundle.id?.let {
ArchivedSession(it, sessionBundle, sessionBundle.lastSavedAt, sessionBundle.urls)
}
}
getManagedEmitter<SessionsChange>().onNext(SessionsChange.Changed(archivedSessions))
})
2019-01-29 00:26:37 +01:00
val searchIcon = requireComponents.search.searchEngineManager.getDefaultSearchEngine(requireContext()).let {
BitmapDrawable(resources, it.icon)
}
2019-01-25 17:11:43 +01:00
view.menuButton.setOnClickListener {
homeMenu.menuBuilder.build(requireContext()).show(
anchor = it,
orientation = BrowserMenu.Orientation.DOWN)
}
view.toolbar.setCompoundDrawablesWithIntrinsicBounds(searchIcon, null, null, null)
2019-01-30 17:36:14 +01:00
val roundToInt = (toolbarPaddingDp * Resources.getSystem().displayMetrics.density).roundToInt()
view.toolbar.compoundDrawablePadding = roundToInt
view.toolbar.setOnClickListener {
val directions = HomeFragmentDirections.actionHomeFragmentToSearchFragment(null)
Navigation.findNavController(it).navigate(directions)
}
// There is currently an issue with visibility changes in ConstraintLayout 2.0.0-alpha3
// https://issuetracker.google.com/issues/122090772
// For now we're going to manually implement KeyTriggers.
view.homeLayout.setTransitionListener(object : MotionLayout.TransitionListener {
private val firstKeyTrigger = KeyTrigger(
firstKeyTriggerFrame,
{ view.toolbar_wrapper.transitionToDark() },
{ view.toolbar_wrapper.transitionToLight() }
)
private val secondKeyTrigger = KeyTrigger(
secondKeyTriggerFrame,
{ view.toolbar_wrapper.transitionToDarkNoBorder() },
{ view.toolbar_wrapper.transitionToDarkFromNoBorder() }
)
override fun onTransitionChange(
motionLayout: MotionLayout?,
startId: Int,
endId: Int,
progress: Float
) {
firstKeyTrigger.conditionallyFire(progress)
secondKeyTrigger.conditionallyFire(progress)
}
override fun onTransitionCompleted(p0: MotionLayout?, p1: Int) { }
})
view.toolbar_wrapper.isPrivateModeEnabled = (activity as HomeActivity).browsingModeManager.isPrivate
privateBrowsingButton.setOnClickListener {
val browsingModeManager = (activity as HomeActivity).browsingModeManager
browsingModeManager.mode = when (browsingModeManager.mode) {
BrowsingModeManager.Mode.Normal -> BrowsingModeManager.Mode.Private
BrowsingModeManager.Mode.Private -> BrowsingModeManager.Mode.Normal
}
}
}
override fun onResume() {
super.onResume()
(activity as AppCompatActivity).supportActionBar?.hide()
}
override fun onStart() {
super.onStart()
if (isAdded) {
getAutoDisposeObservable<TabsAction>()
.subscribe {
when (it) {
is TabsAction.Select -> {
val session = requireComponents.core.sessionManager.findSessionById(it.sessionId)
requireComponents.core.sessionManager.select(session!!)
val directions = HomeFragmentDirections.actionHomeFragmentToBrowserFragment(it.sessionId)
Navigation.findNavController(view!!).navigate(directions)
}
is TabsAction.Close -> {
requireComponents.core.sessionManager.findSessionById(it.sessionId)?.let { session ->
requireComponents.core.sessionManager.remove(session)
}
}
}
}
2019-02-26 00:43:30 +01:00
getAutoDisposeObservable<SessionsAction>()
.subscribe {
when (it) {
is SessionsAction.Select -> {
it.archivedSession.bundle.restoreSnapshot(requireComponents.core.engine)?.apply {
requireComponents.core.sessionManager.restore(this)
}
}
is SessionsAction.Delete -> {
requireComponents.core.sessionStorage.remove(it.archivedSession.bundle)
}
2019-02-26 00:43:30 +01:00
}
}
}
sessionObserver = subscribeToSessions()
sessionObserver?.onSessionsRestored()
}
override fun onPause() {
super.onPause()
sessionObserver?.let {
requireComponents.core.sessionManager.unregister(it)
}
}
private fun setupHomeMenu() {
homeMenu = HomeMenu(requireContext()) {
val directions = when (it) {
HomeMenu.Item.Settings -> HomeFragmentDirections.actionHomeFragmentToSettingsFragment()
HomeMenu.Item.Library -> HomeFragmentDirections.actionHomeFragmentToLibraryFragment()
HomeMenu.Item.Help -> return@HomeMenu // Not implemented yetN
}
Navigation.findNavController(homeLayout).navigate(directions)
}
}
private fun subscribeToSessions(): SessionManager.Observer {
val observer = object : SessionManager.Observer {
override fun onSessionAdded(session: Session) {
super.onSessionAdded(session)
emitSessionChanges()
}
override fun onSessionRemoved(session: Session) {
super.onSessionRemoved(session)
emitSessionChanges()
}
override fun onSessionSelected(session: Session) {
super.onSessionSelected(session)
emitSessionChanges()
}
override fun onSessionsRestored() {
super.onSessionsRestored()
emitSessionChanges()
}
override fun onAllSessionsRemoved() {
super.onAllSessionsRemoved()
emitSessionChanges()
}
}
requireComponents.core.sessionManager.register(observer)
return observer
}
private fun emitSessionChanges() {
val sessionManager = requireComponents.core.sessionManager
getManagedEmitter<TabsChange>().onNext(
TabsChange.Changed(
sessionManager.sessions
.filter { (activity as HomeActivity).browsingModeManager.isPrivate == it.private }
.map { it.toSessionViewState(it == sessionManager.selectedSession) }
)
)
}
2019-01-30 17:36:14 +01:00
companion object {
const val addTabButtonIncreaseDps = 8
const val overflowButtonIncreaseDps = 8
2019-01-30 17:36:14 +01:00
const val toolbarPaddingDp = 12f
const val firstKeyTriggerFrame = 55
const val secondKeyTriggerFrame = 90
const val temporaryNumberOfSessions = 25
2019-01-30 17:36:14 +01:00
}
2019-01-09 23:22:58 +01:00
}