* For #347: Adds private browsing logic * For #347: Adds private session explainer * Adds persistencemaster
parent
fe74df8b7f
commit
e5fe80f928
|
@ -0,0 +1,51 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.fenix
|
||||
|
||||
import android.preference.PreferenceManager
|
||||
|
||||
interface BrowsingModeManager {
|
||||
enum class Mode {
|
||||
Normal, Private
|
||||
}
|
||||
}
|
||||
|
||||
var temporaryModeStorage: BrowsingModeManager.Mode? = null
|
||||
class DefaultBrowsingModeManager(private val homeActivity: HomeActivity) : BrowsingModeManager {
|
||||
val isPrivate: Boolean
|
||||
get() = mode == BrowsingModeManager.Mode.Private
|
||||
var mode: BrowsingModeManager.Mode
|
||||
get() = temporaryModeStorage!!
|
||||
set(value) {
|
||||
temporaryModeStorage = value
|
||||
updateTheme(value)
|
||||
setPreference()
|
||||
}
|
||||
|
||||
private fun updateTheme(mode: BrowsingModeManager.Mode) {
|
||||
homeActivity.themeManager.apply {
|
||||
val newTheme = when (mode) {
|
||||
BrowsingModeManager.Mode.Normal -> ThemeManager.Theme.Light
|
||||
BrowsingModeManager.Mode.Private -> ThemeManager.Theme.Private
|
||||
}
|
||||
setTheme(newTheme)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setPreference() {
|
||||
PreferenceManager.getDefaultSharedPreferences(homeActivity)
|
||||
.edit().putBoolean(homeActivity.getString(R.string.pref_key_private_mode), isPrivate).apply()
|
||||
}
|
||||
|
||||
init {
|
||||
if (temporaryModeStorage == null) {
|
||||
mode = when (PreferenceManager.getDefaultSharedPreferences(homeActivity)
|
||||
.getBoolean(homeActivity.getString(R.string.pref_key_private_mode), false)) {
|
||||
true -> BrowsingModeManager.Mode.Private
|
||||
false -> BrowsingModeManager.Mode.Normal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,8 +29,12 @@ open class HomeActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
lateinit var browsingModeManager: DefaultBrowsingModeManager
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
browsingModeManager = DefaultBrowsingModeManager(this)
|
||||
|
||||
setContentView(R.layout.activity_home)
|
||||
|
||||
setTheme(themeManager.currentTheme)
|
||||
|
@ -85,7 +89,7 @@ open class HomeActivity : AppCompatActivity() {
|
|||
private fun openToBrowser() {
|
||||
val sessionId = SafeIntent(intent).getStringExtra(IntentProcessor.ACTIVE_SESSION_ID)
|
||||
val host = supportFragmentManager.findFragmentById(R.id.container) as NavHostFragment
|
||||
val directions = NavGraphDirections.actionGlobalBrowser(sessionId)
|
||||
val directions = NavGraphDirections.actionGlobalBrowser(sessionId, browsingModeManager.isPrivate)
|
||||
host.navController.navigate(directions)
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import android.annotation.SuppressLint
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.preference.PreferenceManager
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -31,6 +30,7 @@ import mozilla.components.feature.session.SessionFeature
|
|||
import mozilla.components.feature.session.SessionUseCases
|
||||
import mozilla.components.support.base.feature.BackHandler
|
||||
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
|
||||
import org.mozilla.fenix.BrowsingModeManager
|
||||
import org.mozilla.fenix.DefaultThemeManager
|
||||
import org.mozilla.fenix.HomeActivity
|
||||
import org.mozilla.fenix.R
|
||||
|
@ -56,6 +56,7 @@ class BrowserFragment : Fragment(), BackHandler {
|
|||
private val findInPageIntegration = ViewBoundFeatureWrapper<FindInPageIntegration>()
|
||||
private val customTabsToolbarFeature = ViewBoundFeatureWrapper<CustomTabsToolbarFeature>()
|
||||
private val toolbarIntegration = ViewBoundFeatureWrapper<ToolbarIntegration>()
|
||||
private var isPrivate = false
|
||||
var sessionId: String? = null
|
||||
|
||||
override fun onCreateView(
|
||||
|
@ -63,12 +64,16 @@ class BrowserFragment : Fragment(), BackHandler {
|
|||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
require(arguments != null)
|
||||
sessionId = BrowserFragmentArgs.fromBundle(arguments!!).sessionId
|
||||
isPrivate = BrowserFragmentArgs.fromBundle(arguments!!).isPrivateTab
|
||||
|
||||
val view = inflater.inflate(R.layout.fragment_browser, container, false)
|
||||
|
||||
toolbarComponent = ToolbarComponent(
|
||||
view.browserLayout,
|
||||
ActionBusFactory.get(this), sessionId,
|
||||
isPrivate,
|
||||
SearchState("", isEditing = false)
|
||||
)
|
||||
|
||||
|
@ -105,7 +110,8 @@ class BrowserFragment : Fragment(), BackHandler {
|
|||
when (it) {
|
||||
is SearchAction.ToolbarTapped -> Navigation.findNavController(toolbar)
|
||||
.navigate(BrowserFragmentDirections.actionBrowserFragmentToSearchFragment(
|
||||
requireComponents.core.sessionManager.selectedSession?.id
|
||||
requireComponents.core.sessionManager.selectedSession?.id,
|
||||
(activity as HomeActivity).browsingModeManager.isPrivate
|
||||
))
|
||||
is SearchAction.ToolbarMenuItemTapped -> handleToolbarItemInteraction(it)
|
||||
}
|
||||
|
@ -224,12 +230,11 @@ class BrowserFragment : Fragment(), BackHandler {
|
|||
ToolbarMenu.Item.Share -> requireComponents.core.sessionManager
|
||||
.selectedSession?.url?.apply { requireContext().share(this) }
|
||||
ToolbarMenu.Item.NewPrivateTab -> {
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.edit().putBoolean(
|
||||
context!!.getString(R.string.pref_key_private_mode),
|
||||
!PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.getBoolean(context!!.getString(R.string.pref_key_private_mode), false)
|
||||
).apply()
|
||||
val directions = BrowserFragmentDirections
|
||||
.actionBrowserFragmentToSearchFragment(requireComponents.core.sessionManager.selectedSession?.id,
|
||||
(activity as HomeActivity).browsingModeManager.isPrivate)
|
||||
Navigation.findNavController(view!!).navigate(directions)
|
||||
(activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Private
|
||||
}
|
||||
ToolbarMenu.Item.FindInPage -> FindInPageIntegration.launch?.invoke()
|
||||
ToolbarMenu.Item.ReportIssue -> requireComponents.core.sessionManager
|
||||
|
@ -241,9 +246,11 @@ class BrowserFragment : Fragment(), BackHandler {
|
|||
// TODO Help
|
||||
}
|
||||
ToolbarMenu.Item.NewTab -> {
|
||||
val directions =
|
||||
BrowserFragmentDirections.actionBrowserFragmentToSearchFragment(null)
|
||||
val directions = BrowserFragmentDirections
|
||||
.actionBrowserFragmentToSearchFragment(null,
|
||||
(activity as HomeActivity).browsingModeManager.isPrivate)
|
||||
Navigation.findNavController(view!!).navigate(directions)
|
||||
(activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Normal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ class ToolbarComponent(
|
|||
private val container: ViewGroup,
|
||||
bus: ActionBusFactory,
|
||||
private val sessionId: String?,
|
||||
private val isPrivate: Boolean,
|
||||
override var initialState: SearchState = SearchState("", false)
|
||||
) :
|
||||
UIComponent<SearchState, SearchAction, SearchChange>(
|
||||
|
@ -34,7 +35,7 @@ class ToolbarComponent(
|
|||
}
|
||||
}
|
||||
|
||||
override fun initView() = ToolbarUIView(sessionId, container, actionEmitter, changesObservable)
|
||||
override fun initView() = ToolbarUIView(sessionId, isPrivate, container, actionEmitter, changesObservable)
|
||||
init {
|
||||
render(reducer)
|
||||
applyTheme()
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.graphics.PorterDuff
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.navigation.Navigation
|
||||
import mozilla.components.browser.domains.autocomplete.DomainAutocompleteProvider
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.browser.session.SessionManager
|
||||
import mozilla.components.browser.session.runWithSession
|
||||
import mozilla.components.browser.toolbar.BrowserToolbar
|
||||
|
@ -28,7 +29,8 @@ class ToolbarIntegration(
|
|||
domainAutocompleteProvider: DomainAutocompleteProvider,
|
||||
historyStorage: HistoryStorage,
|
||||
sessionManager: SessionManager,
|
||||
sessionId: String? = null
|
||||
sessionId: String? = null,
|
||||
isPrivate: Boolean
|
||||
) : LifecycleAwareFeature {
|
||||
init {
|
||||
toolbar.setMenuBuilder(toolbarMenu.menuBuilder)
|
||||
|
@ -68,10 +70,15 @@ class ToolbarIntegration(
|
|||
toolbar,
|
||||
context.components.core.sessionManager,
|
||||
if (sessionId == null) {
|
||||
context.components.useCases.tabsUseCases.addTab
|
||||
if (isPrivate) {
|
||||
context.components.useCases.tabsUseCases.addPrivateTab
|
||||
} else {
|
||||
context.components.useCases.tabsUseCases.addTab
|
||||
}
|
||||
} else context.components.useCases.sessionUseCases.loadUrl,
|
||||
{ searchTerms -> if (sessionId == null) {
|
||||
context.components.useCases.searchUseCases.newTabSearch.invoke(searchTerms)
|
||||
context.components.useCases.searchUseCases.newTabSearch
|
||||
.invoke(searchTerms, Session.Source.USER_ENTERED, true, isPrivate)
|
||||
} else context.components.useCases.searchUseCases.defaultSearch.invoke(searchTerms) },
|
||||
sessionId
|
||||
)
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.mozilla.fenix.mvi.UIView
|
|||
|
||||
class ToolbarUIView(
|
||||
sessionId: String?,
|
||||
isPrivate: Boolean,
|
||||
container: ViewGroup,
|
||||
actionEmitter: Observer<SearchAction>,
|
||||
changesObservable: Observable<SearchChange>
|
||||
|
@ -72,7 +73,8 @@ class ToolbarUIView(
|
|||
ShippedDomainsProvider().also { it.initialize(this) },
|
||||
components.core.historyStorage,
|
||||
components.core.sessionManager,
|
||||
sessionId
|
||||
sessionId,
|
||||
isPrivate
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@ import mozilla.components.browser.menu.BrowserMenu
|
|||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.browser.session.SessionManager
|
||||
import org.mozilla.fenix.DefaultThemeManager
|
||||
import org.mozilla.fenix.BrowsingModeManager
|
||||
import org.mozilla.fenix.HomeActivity
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ThemeManager
|
||||
import org.mozilla.fenix.ext.requireComponents
|
||||
import org.mozilla.fenix.home.sessions.SessionsComponent
|
||||
import org.mozilla.fenix.home.tabs.TabsAction
|
||||
|
@ -47,8 +47,9 @@ class HomeFragment : Fragment() {
|
|||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val view = inflater.inflate(R.layout.fragment_home, container, false)
|
||||
TabsComponent(view.homeLayout, bus, TabsState(requireComponents.core.sessionManager.sessions))
|
||||
SessionsComponent(view.homeLayout, bus)
|
||||
TabsComponent(view.homeLayout, bus, (activity as HomeActivity).browsingModeManager.isPrivate,
|
||||
TabsState(requireComponents.core.sessionManager.sessions))
|
||||
SessionsComponent(view.homeLayout, bus, (activity as HomeActivity).browsingModeManager.isPrivate)
|
||||
layoutComponents(view)
|
||||
ActionBusFactory.get(this).logMergedObservables()
|
||||
val activity = activity as HomeActivity
|
||||
|
@ -68,7 +69,8 @@ class HomeFragment : Fragment() {
|
|||
when (it) {
|
||||
is TabsAction.Select -> {
|
||||
requireComponents.core.sessionManager.select(it.session)
|
||||
val directions = HomeFragmentDirections.actionHomeFragmentToBrowserFragment(it.session.id)
|
||||
val directions = HomeFragmentDirections.actionHomeFragmentToBrowserFragment(it.session.id,
|
||||
(activity as HomeActivity).browsingModeManager.isPrivate)
|
||||
Navigation.findNavController(view).navigate(directions)
|
||||
}
|
||||
is TabsAction.Close -> {
|
||||
|
@ -90,8 +92,9 @@ class HomeFragment : Fragment() {
|
|||
view.toolbar.setCompoundDrawablesWithIntrinsicBounds(searchIcon, null, null, null)
|
||||
val roundToInt = (toolbarPaddingDp * Resources.getSystem().displayMetrics.density).roundToInt()
|
||||
view.toolbar.compoundDrawablePadding = roundToInt
|
||||
view.toolbar.setOnClickListener {
|
||||
val directions = HomeFragmentDirections.actionHomeFragmentToSearchFragment(null)
|
||||
view.toolbar.setOnClickListener { it ->
|
||||
val directions = HomeFragmentDirections.actionHomeFragmentToSearchFragment(null,
|
||||
(activity as HomeActivity).browsingModeManager.isPrivate)
|
||||
Navigation.findNavController(it).navigate(directions)
|
||||
}
|
||||
|
||||
|
@ -129,14 +132,10 @@ class HomeFragment : Fragment() {
|
|||
.isPrivate()
|
||||
|
||||
privateBrowsingButton.setOnClickListener {
|
||||
// When we build out private mode we will want to handle this logic elsewhere.
|
||||
(requireActivity() as HomeActivity).themeManager.apply {
|
||||
val newTheme = when (this.currentTheme) {
|
||||
ThemeManager.Theme.Light -> ThemeManager.Theme.Private
|
||||
ThemeManager.Theme.Private -> ThemeManager.Theme.Light
|
||||
}
|
||||
|
||||
setTheme(newTheme)
|
||||
val browsingModeManager = (activity as HomeActivity).browsingModeManager
|
||||
browsingModeManager.mode = when (browsingModeManager.mode) {
|
||||
BrowsingModeManager.Mode.Normal -> BrowsingModeManager.Mode.Private
|
||||
BrowsingModeManager.Mode.Private -> BrowsingModeManager.Mode.Normal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,6 +143,7 @@ class HomeFragment : Fragment() {
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
sessionObserver = subscribeToSessions()
|
||||
sessionObserver?.onSessionsRestored()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
|
@ -170,31 +170,36 @@ class HomeFragment : Fragment() {
|
|||
override fun onSessionAdded(session: Session) {
|
||||
super.onSessionAdded(session)
|
||||
getManagedEmitter<TabsChange>().onNext(
|
||||
TabsChange.Changed(requireComponents.core.sessionManager.sessions))
|
||||
TabsChange.Changed(requireComponents.core.sessionManager.sessions
|
||||
.filter { (activity as HomeActivity).browsingModeManager.isPrivate == it.private }))
|
||||
}
|
||||
|
||||
override fun onSessionRemoved(session: Session) {
|
||||
super.onSessionRemoved(session)
|
||||
getManagedEmitter<TabsChange>().onNext(
|
||||
TabsChange.Changed(requireComponents.core.sessionManager.sessions))
|
||||
TabsChange.Changed(requireComponents.core.sessionManager.sessions
|
||||
.filter { (activity as HomeActivity).browsingModeManager.isPrivate == it.private }))
|
||||
}
|
||||
|
||||
override fun onSessionSelected(session: Session) {
|
||||
super.onSessionSelected(session)
|
||||
getManagedEmitter<TabsChange>().onNext(
|
||||
TabsChange.Changed(requireComponents.core.sessionManager.sessions))
|
||||
TabsChange.Changed(requireComponents.core.sessionManager.sessions
|
||||
.filter { (activity as HomeActivity).browsingModeManager.isPrivate == it.private }))
|
||||
}
|
||||
|
||||
override fun onSessionsRestored() {
|
||||
super.onSessionsRestored()
|
||||
getManagedEmitter<TabsChange>().onNext(
|
||||
TabsChange.Changed(requireComponents.core.sessionManager.sessions))
|
||||
TabsChange.Changed(requireComponents.core.sessionManager.sessions
|
||||
.filter { (activity as HomeActivity).browsingModeManager.isPrivate == it.private }))
|
||||
}
|
||||
|
||||
override fun onAllSessionsRemoved() {
|
||||
super.onAllSessionsRemoved()
|
||||
getManagedEmitter<TabsChange>().onNext(
|
||||
TabsChange.Changed(requireComponents.core.sessionManager.sessions))
|
||||
TabsChange.Changed(requireComponents.core.sessionManager.sessions
|
||||
.filter { (activity as HomeActivity).browsingModeManager.isPrivate == it.private }))
|
||||
}
|
||||
}
|
||||
requireComponents.core.sessionManager.register(observer)
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
|
||||
package org.mozilla.fenix.home.sessions
|
||||
|
||||
import android.content.Context
|
||||
import android.text.SpannableString
|
||||
import android.text.style.ClickableSpan
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -12,38 +16,70 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import org.mozilla.fenix.R
|
||||
|
||||
class SessionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
var isPrivate = false
|
||||
var context: Context? = null
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
|
||||
|
||||
return when (viewType) {
|
||||
HeaderViewHolder.LAYOUT_ID -> HeaderViewHolder(view)
|
||||
EmptyListViewHolder.LAYOUT_ID -> EmptyListViewHolder(view)
|
||||
PrivateEmptyListViewHolder.LAYOUT_ID -> PrivateEmptyListViewHolder(view)
|
||||
else -> EmptyListViewHolder(view)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int) = when (position) {
|
||||
0 -> HeaderViewHolder.LAYOUT_ID
|
||||
1 -> EmptyListViewHolder.LAYOUT_ID
|
||||
1 -> if (isPrivate) PrivateEmptyListViewHolder.LAYOUT_ID else EmptyListViewHolder.LAYOUT_ID
|
||||
else -> -1
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = 2
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
if (holder is HeaderViewHolder) {
|
||||
holder.headerText.text = "Today"
|
||||
when (holder) {
|
||||
is HeaderViewHolder -> if (isPrivate) {
|
||||
holder.headerText.text = "Private Session"
|
||||
} else {
|
||||
holder.headerText.text = "Today"
|
||||
}
|
||||
is PrivateEmptyListViewHolder -> {
|
||||
// Format the description text to include a hyperlink
|
||||
val descriptionText = String
|
||||
.format(holder.description.text.toString(), System.getProperty("line.separator"))
|
||||
val linkStartIndex = descriptionText.indexOf("\n\n") + 2
|
||||
val linkAction = object : ClickableSpan() {
|
||||
override fun onClick(widget: View?) {
|
||||
// TODO Go to SUMO page
|
||||
}
|
||||
}
|
||||
val textWithLink = SpannableString(descriptionText).apply {
|
||||
setSpan(linkAction, linkStartIndex, descriptionText.length, 0)
|
||||
|
||||
val colorSpan = ForegroundColorSpan(holder.description.currentTextColor)
|
||||
setSpan(colorSpan, linkStartIndex, descriptionText.length, 0)
|
||||
}
|
||||
holder.description.text = textWithLink
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class HeaderViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
|
||||
val headerText = view.findViewById<TextView>(R.id.header_text)
|
||||
|
||||
companion object {
|
||||
const val LAYOUT_ID = R.layout.session_list_header
|
||||
}
|
||||
}
|
||||
|
||||
private class PrivateEmptyListViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
|
||||
val description = view.findViewById<TextView>(R.id.session_description)
|
||||
companion object {
|
||||
const val LAYOUT_ID = R.layout.session_list_empty_private
|
||||
}
|
||||
}
|
||||
|
||||
private class EmptyListViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
|
||||
companion object {
|
||||
const val LAYOUT_ID = R.layout.session_list_empty
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.mozilla.fenix.mvi.ViewState
|
|||
class SessionsComponent(
|
||||
private val container: ViewGroup,
|
||||
bus: ActionBusFactory,
|
||||
private val isPrivate: Boolean,
|
||||
override var initialState: SessionsState = SessionsState(emptyList())
|
||||
) :
|
||||
UIComponent<SessionsState, SessionsAction, SessionsChange>(
|
||||
|
@ -28,19 +29,19 @@ class SessionsComponent(
|
|||
}
|
||||
}
|
||||
|
||||
override fun initView() = SessionsUIView(container, actionEmitter, changesObservable)
|
||||
override fun initView() = SessionsUIView(container, actionEmitter, isPrivate, changesObservable)
|
||||
|
||||
init {
|
||||
render(reducer)
|
||||
}
|
||||
}
|
||||
|
||||
data class SessionsState(val sessions: List<Session>) : ViewState
|
||||
data class SessionsState(val sessions: List<Session>, val isPrivate: Boolean = false) : ViewState
|
||||
|
||||
sealed class SessionsAction : Action {
|
||||
object Select : SessionsAction()
|
||||
}
|
||||
|
||||
sealed class SessionsChange : Change {
|
||||
object Changed : SessionsChange()
|
||||
data class Changed(val isPrivate: Boolean) : SessionsChange()
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.mozilla.fenix.mvi.UIView
|
|||
class SessionsUIView(
|
||||
container: ViewGroup,
|
||||
actionEmitter: Observer<SessionsAction>,
|
||||
isPrivate: Boolean,
|
||||
changesObservable: Observable<SessionsChange>
|
||||
) :
|
||||
UIView<SessionsState, SessionsAction, SessionsChange>(container, actionEmitter, changesObservable) {
|
||||
|
@ -30,6 +31,8 @@ class SessionsUIView(
|
|||
init {
|
||||
view.apply {
|
||||
layoutManager = LinearLayoutManager(container.context)
|
||||
sessionsAdapter.isPrivate = isPrivate
|
||||
sessionsAdapter.context = context
|
||||
adapter = sessionsAdapter
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.mozilla.fenix.mvi.ViewState
|
|||
class TabsComponent(
|
||||
private val container: ViewGroup,
|
||||
bus: ActionBusFactory,
|
||||
private val isPrivate: Boolean,
|
||||
override var initialState: TabsState = TabsState(listOf())
|
||||
) :
|
||||
UIComponent<TabsState, TabsAction, TabsChange>(
|
||||
|
@ -28,7 +29,7 @@ class TabsComponent(
|
|||
}
|
||||
}
|
||||
|
||||
override fun initView() = TabsUIView(container, actionEmitter, changesObservable)
|
||||
override fun initView() = TabsUIView(container, actionEmitter, isPrivate, changesObservable)
|
||||
|
||||
init {
|
||||
render(reducer)
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.mozilla.fenix.mvi.UIView
|
|||
class TabsUIView(
|
||||
container: ViewGroup,
|
||||
actionEmitter: Observer<TabsAction>,
|
||||
isPrivate: Boolean,
|
||||
changesObservable: Observable<TabsChange>
|
||||
) :
|
||||
UIView<TabsState, TabsAction, TabsChange>(container, actionEmitter, changesObservable) {
|
||||
|
@ -50,7 +51,8 @@ class TabsUIView(
|
|||
}
|
||||
header.add_tab_button.increaseTapArea(HomeFragment.addTabButtonIncreaseDps)
|
||||
header.add_tab_button.setOnClickListener {
|
||||
val directions = HomeFragmentDirections.actionHomeFragmentToSearchFragment(null)
|
||||
val directions = HomeFragmentDirections.actionHomeFragmentToSearchFragment(null,
|
||||
isPrivate)
|
||||
Navigation.findNavController(it).navigate(directions)
|
||||
}
|
||||
header.tabs_overflow_button.increaseTapArea(HomeFragment.overflowButtonIncreaseDps)
|
||||
|
|
|
@ -21,6 +21,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import org.mozilla.fenix.HomeActivity
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.requireComponents
|
||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||
|
@ -57,7 +58,8 @@ class HistoryFragment : Fragment(), CoroutineScope {
|
|||
if (it is HistoryAction.Select) {
|
||||
Navigation.findNavController(requireActivity(), R.id.container).apply {
|
||||
navigate(
|
||||
HistoryFragmentDirections.actionGlobalBrowser(null),
|
||||
HistoryFragmentDirections.actionGlobalBrowser(null,
|
||||
(activity as HomeActivity).browsingModeManager.isPrivate),
|
||||
NavOptions.Builder().setPopUpTo(R.id.homeFragment, false).build()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.Navigation
|
||||
import kotlinx.android.synthetic.main.fragment_search.view.*
|
||||
import org.mozilla.fenix.HomeActivity
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||
import org.mozilla.fenix.mvi.getManagedEmitter
|
||||
|
@ -36,11 +37,13 @@ class SearchFragment : Fragment() {
|
|||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val sessionId = SearchFragmentArgs.fromBundle(arguments!!).sessionId
|
||||
val isPrivate = SearchFragmentArgs.fromBundle(arguments!!).isPrivateTab
|
||||
val view = inflater.inflate(R.layout.fragment_search, container, false)
|
||||
toolbarComponent = ToolbarComponent(
|
||||
view.toolbar_wrapper,
|
||||
ActionBusFactory.get(this),
|
||||
sessionId,
|
||||
isPrivate,
|
||||
SearchState("", isEditing = true)
|
||||
)
|
||||
awesomeBarComponent = AwesomeBarComponent(
|
||||
|
@ -83,7 +86,9 @@ class SearchFragment : Fragment() {
|
|||
|
||||
private fun transitionToBrowser() {
|
||||
val sessionId = SearchFragmentArgs.fromBundle(arguments!!).sessionId
|
||||
val directions = SearchFragmentDirections.actionSearchFragmentToBrowserFragment(sessionId)
|
||||
val directions = SearchFragmentDirections.actionSearchFragmentToBrowserFragment(sessionId,
|
||||
(activity as HomeActivity).browsingModeManager.isPrivate)
|
||||
|
||||
Navigation.findNavController(view!!.search_layout).navigate(directions)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
|||
Navigation.findNavController(it)
|
||||
.navigate(
|
||||
SettingsFragmentDirections.actionGlobalBrowser(
|
||||
null
|
||||
null, false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
|
||||
<solid android:color="@color/photonGrey40" />
|
||||
<corners
|
||||
android:bottomLeftRadius="7dp"
|
||||
android:bottomRightRadius="7dp" />
|
||||
</shape>
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<stroke android:width="2dp"
|
||||
android:color="?attr/sessionBorderColor"/>
|
||||
|
||||
<padding android:left="1dp" android:top="1dp" android:right="1dp" android:bottom="1dp"/>
|
||||
|
||||
<corners android:radius="8dp"/>
|
||||
</shape>
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/private_no_sessions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/session_description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
android:ellipsize="none"
|
||||
android:gravity="center_vertical"
|
||||
android:scrollHorizontally="false"
|
||||
android:text="@string/private_browsing_explanation"
|
||||
android:textColor="@color/off_white"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -5,8 +5,8 @@
|
|||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/header_text"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:textSize="12dp"
|
||||
android:textColor="@color/session_list_header"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
|
||||
android:textColor="?attr/toolbarTextColor"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
</TextView>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:text="@string/tabs_header_title"
|
||||
android:textSize="24sp"
|
||||
android:textColor="@android:color/black"
|
||||
android:textColor="?attr/toolbarTextColor"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
<ImageView
|
||||
|
@ -25,6 +25,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:src="@drawable/ic_new"
|
||||
android:tint="?attr/toolbarTextColor"
|
||||
android:baselineAlignBottom="true"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/header_text"
|
||||
app:layout_constraintEnd_toStartOf="@id/tabs_overflow_button"/>
|
||||
|
@ -33,6 +34,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:tint="?attr/toolbarTextColor"
|
||||
android:src="@drawable/ic_menu"
|
||||
android:baselineAlignBottom="true"
|
||||
app:layout_constraintBaseline_toBaselineOf="@id/header_text"
|
||||
|
|
|
@ -8,9 +8,11 @@
|
|||
android:layout_marginBottom="8dp"
|
||||
android:padding="10dp"
|
||||
android:elevation="5dp"
|
||||
app:cardCornerRadius="10dp">
|
||||
app:cardCornerRadius="10dp"
|
||||
android:clipChildren="true">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:background="@drawable/session_border"
|
||||
android:id="@+id/item_tab"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -50,7 +52,10 @@
|
|||
|
||||
<ImageView android:layout_width="0dp"
|
||||
android:layout_height="100dp"
|
||||
android:src="@color/photonBlue40"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_marginBottom="1dp"
|
||||
android:background="@drawable/session_background"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_url"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
app:destination="@id/browserFragment"
|
||||
app:popUpTo="@id/homeFragment" />
|
||||
<argument android:name="session_id" app:argType="string" app:nullable="true"/>
|
||||
<argument android:name="is_private_tab" app:argType="boolean"/>
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
|
@ -57,6 +58,9 @@
|
|||
android:name="session_id"
|
||||
app:argType="string"
|
||||
app:nullable="true" />
|
||||
<argument
|
||||
android:name="is_private_tab"
|
||||
app:argType="boolean"/>
|
||||
<action
|
||||
android:id="@+id/action_browserFragment_to_settingsFragment"
|
||||
app:destination="@id/settingsFragment" />
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
<attr name="toolbarTextColor" format="reference"/>
|
||||
<attr name="navigationBarColorHome" format="reference"/>
|
||||
<attr name="homeDividerColor" format="reference" />
|
||||
<attr name="sessionBorderColor" format="reference"/>
|
||||
|
||||
<!-- Search fragment -->
|
||||
<attr name="searchBackground" format="reference"/>
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<color name="off_white">#f9f9fa</color>
|
||||
<color name="url_box_view">#E9E9ED</color>
|
||||
<color name="icons">#20233E</color>
|
||||
<color name="session_border_color">#2f26c1</color>
|
||||
|
||||
<color name="session_list_empty_bg">#1A665BFD</color>
|
||||
<color name="session_list_empty_fg">#544CD9</color>
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
<!-- Explanation for private browsing displayed to users on home view when they first enable private mode -->
|
||||
<string name="private_browsing_explanation">Fenix clears your search and browsing history when you close all
|
||||
Private Sessions tabs. While this doesn\'t make you anonymous to websites or your internet service provider,
|
||||
it makes it easier to keep what you do online private from anyone else who uses this device.</string>
|
||||
it makes it easier to keep what you do online private from anyone else who uses this device.\n\nCommon myths
|
||||
about private browsing</string>
|
||||
<!-- Delete session button to erase your history in a private session -->
|
||||
<string name="private_browsing_delete_session">Delete Session</string>
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
<item name="toolbarWrapperBackground">@drawable/home_search_background_light</item>
|
||||
<item name="toolbarTextColor">@color/search_text</item>
|
||||
<item name="homeDividerColor">@color/photonGrey30</item>
|
||||
<item name="sessionBorderColor">@color/session_border_color</item>
|
||||
|
||||
<!-- Search fragment colors -->
|
||||
<item name="searchBackground">@color/off_white</item>
|
||||
|
@ -64,6 +65,7 @@
|
|||
<item name="toolbarWrapperBackground">@drawable/home_search_background_private</item>
|
||||
<item name="toolbarTextColor">@color/off_white</item>
|
||||
<item name="homeDividerColor">@color/search_private_background</item>
|
||||
<item name="sessionBorderColor">@color/private_browsing_primary</item>
|
||||
|
||||
<!-- Search fragment colors -->
|
||||
<item name="searchBackground">@color/private_browsing_bottom_gradient</item>
|
||||
|
|
Loading…
Reference in New Issue