Skip to content

Commit

Permalink
For mozilla-mobile#563: Restyles history management
Browse files Browse the repository at this point in the history
  • Loading branch information
sblatz committed May 10, 2019
1 parent 005f539 commit f957f35
Show file tree
Hide file tree
Showing 16 changed files with 313 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ sealed class BookmarkAction : Action {
data class Deselect(val item: BookmarkNode) : BookmarkAction()
data class Delete(val item: BookmarkNode) : BookmarkAction()
object BackPressed : BookmarkAction()
object ModeChanged : BookmarkAction()
object SwitchMode : BookmarkAction()
}

sealed class BookmarkChange : Change {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
refreshBookmarks(components)
}
}
is BookmarkAction.ModeChanged -> activity?.invalidateOptionsMenu()
is BookmarkAction.SwitchMode -> activity?.invalidateOptionsMenu()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class BookmarkUIView(
}
if (it.mode != mode) {
mode = it.mode
actionEmitter.onNext(BookmarkAction.ModeChanged)
actionEmitter.onNext(BookmarkAction.SwitchMode)
}
bookmarkAdapter.updateData(it.tree, it.mode)
when (val modeCopy = mode) {
Expand All @@ -78,7 +78,7 @@ class BookmarkUIView(
mode = BookmarkState.Mode.Normal
bookmarkAdapter.updateData(tree, mode)
setUIForNormalMode(tree)
actionEmitter.onNext(BookmarkAction.ModeChanged)
actionEmitter.onNext(BookmarkAction.SwitchMode)
true
}
canGoBack -> {
Expand Down Expand Up @@ -113,7 +113,7 @@ class BookmarkUIView(
context.getString(R.string.bookmarks_multi_select_title, mode.selectedItems.size)
setToolbarColors(
R.color.white_color,
R.attr.accentBright.getColorIntFromAttr(context!!)
R.attr.accentHighContrast.getColorIntFromAttr(context!!)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,13 @@ class HistoryAdapter(
private var historyList: HistoryList = HistoryList(emptyList())
private var mode: HistoryState.Mode = HistoryState.Mode.Normal
private lateinit var job: Job
var selected = listOf<HistoryItem>()

fun updateData(items: List<HistoryItem>, mode: HistoryState.Mode) {
this.historyList = HistoryList(items)
this.mode = mode
this.selected = if (mode is HistoryState.Mode.Editing) mode.selectedItems else listOf()

notifyDataSetChanged()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class HistoryComponent(
bus.getManagedEmitter(HistoryAction::class.java),
bus.getSafeManagedObservable(HistoryChange::class.java)
) {

override fun initView() = HistoryUIView(container, actionEmitter, changesObservable)

override fun render(): Observable<HistoryState> =
Expand All @@ -51,11 +52,12 @@ data class HistoryState(val items: List<HistoryItem>, val mode: Mode) : ViewStat
}

sealed class HistoryAction : Action {
data class Select(val item: HistoryItem) : HistoryAction()
data class Open(val item: HistoryItem) : HistoryAction()
data class EnterEditMode(val item: HistoryItem) : HistoryAction()
object BackPressed : HistoryAction()
data class AddItemForRemoval(val item: HistoryItem) : HistoryAction()
data class RemoveItemForRemoval(val item: HistoryItem) : HistoryAction()
object SwitchMode : HistoryAction()

sealed class Delete : HistoryAction() {
object All : Delete()
Expand Down Expand Up @@ -99,10 +101,13 @@ class HistoryViewModel(initialState: HistoryState, changesObservable: Observable
}
}
is HistoryChange.RemoveItemForRemoval -> {
val mode = state.mode
var mode = state.mode

if (mode is HistoryState.Mode.Editing) {
val items = mode.selectedItems.filter { it.id != change.item.id }
state.copy(mode = mode.copy(selectedItems = items))
mode = if (items.isEmpty()) HistoryState.Mode.Normal else HistoryState.Mode.Editing(items)

state.copy(mode = mode)
} else {
state
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package org.mozilla.fenix.library.history

import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
Expand All @@ -13,23 +15,30 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_history.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.coroutineScope
import mozilla.components.concept.storage.VisitType
import mozilla.components.support.base.feature.BackHandler
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.BrowsingModeManager
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.components.Components
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.share
import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter
import org.mozilla.fenix.utils.ItsNotBrokenSnack
import java.net.MalformedURLException
import java.net.URL
import kotlin.coroutines.CoroutineContext
Expand All @@ -39,6 +48,7 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler {

private lateinit var job: Job
private lateinit var historyComponent: HistoryComponent
private val navigation by lazy { Navigation.findNavController(requireView()) }

override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
Expand Down Expand Up @@ -66,7 +76,7 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler {
(activity as AppCompatActivity).supportActionBar?.show()
}

private fun selectItem(item: HistoryItem) {
private fun openItem(item: HistoryItem) {
(activity as HomeActivity).openToBrowserAndLoad(
searchTermOrURL = item.url,
newTab = false,
Expand All @@ -79,7 +89,19 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler {
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.library_menu, menu)
when (val mode = (historyComponent.uiView as HistoryUIView).mode) {
HistoryState.Mode.Normal -> inflater.inflate(R.menu.library_menu, menu)
is HistoryState.Mode.Editing -> {
inflater.inflate(R.menu.history_select_multi, menu)
menu.findItem(R.id.share_history_multi_select)?.run {
isVisible = mode.selectedItems.isNotEmpty()
icon.colorFilter = PorterDuffColorFilter(
ContextCompat.getColor(context!!, R.color.white_color),
PorterDuff.Mode.SRC_IN
)
}
}
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
Expand All @@ -96,7 +118,7 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler {
getAutoDisposeObservable<HistoryAction>()
.subscribe {
when (it) {
is HistoryAction.Select -> selectItem(it.item)
is HistoryAction.Open -> openItem(it.item)
is HistoryAction.EnterEditMode -> getManagedEmitter<HistoryChange>()
.onNext(HistoryChange.EnterEditMode(it.item))
is HistoryAction.AddItemForRemoval -> getManagedEmitter<HistoryChange>()
Expand All @@ -119,17 +141,59 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler {
}
reloadData()
}
is HistoryAction.SwitchMode -> activity?.invalidateOptionsMenu()
}
}
}

@Suppress("ComplexMethod")
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.share_history_multi_select -> {
val selectedHistory = (historyComponent.uiView as HistoryUIView).getSelected()
when {
selectedHistory.size == 1 -> context?.share(selectedHistory.first().url)
selectedHistory.size > 1 -> ItsNotBrokenSnack(context!!).showSnackbar(issueNumber = "2377")
}
true
}
R.id.libraryClose -> {
Navigation.findNavController(requireActivity(), R.id.container)
.popBackStack(R.id.libraryFragment, true)
true
}
R.id.delete_history_multi_select -> {
val components = context?.applicationContext?.components!!
val selectedHistory = (historyComponent.uiView as HistoryUIView).getSelected()

CoroutineScope(Main).launch {
deleteSelectedHistory(selectedHistory, components)
reloadData()
}
true
}
R.id.open_history_in_new_tabs_multi_select -> {
val selectedHistory = (historyComponent.uiView as HistoryUIView).getSelected()
selectedHistory.forEach {
requireComponents.useCases.tabsUseCases.addTab.invoke(it.url)
}

(activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Normal
(activity as HomeActivity).supportActionBar?.hide()
navigation.navigate(HistoryFragmentDirections.actionHistoryFragmentToHomeFragment())
true
}
R.id.open_history_in_private_tabs_multi_select -> {
val selectedHistory = (historyComponent.uiView as HistoryUIView).getSelected()
selectedHistory.forEach {
requireComponents.useCases.tabsUseCases.addPrivateTab.invoke(it.url)
}

(activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Private
(activity as HomeActivity).supportActionBar?.hide()
navigation.navigate(HistoryFragmentDirections.actionHistoryFragmentToHomeFragment())
true
}
else -> super.onOptionsItemSelected(item)
}
}
Expand Down Expand Up @@ -171,4 +235,13 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler {
}
}
}

private suspend fun deleteSelectedHistory(
selected: List<HistoryItem>,
components: Components = requireComponents
) {
selected.forEach {
components.core.historyStorage.deleteVisit(it.url, it.visitedAt)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,24 @@

package org.mozilla.fenix.library.history

import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.appcompat.widget.Toolbar
import android.widget.ImageButton
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.functions.Consumer
import kotlinx.android.synthetic.main.component_history.view.*
import mozilla.components.support.base.feature.BackHandler
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.asActivity
import org.mozilla.fenix.ext.getColorIntFromAttr
import org.mozilla.fenix.mvi.UIView

class HistoryUIView(
Expand All @@ -27,28 +35,103 @@ class HistoryUIView(
var mode: HistoryState.Mode = HistoryState.Mode.Normal
private set

private val historyAdapter: HistoryAdapter
private var items: List<HistoryItem> = listOf()
private val context = container.context
private val activity = context?.asActivity()

fun getSelected(): List<HistoryItem> = historyAdapter.selected

override val view: LinearLayout = LayoutInflater.from(container.context)
.inflate(R.layout.component_history, container, true)
.findViewById(R.id.history_wrapper)

init {
view.history_list.apply {
adapter = HistoryAdapter(actionEmitter)
historyAdapter = HistoryAdapter(actionEmitter)
adapter = historyAdapter
layoutManager = LinearLayoutManager(container.context)
}
}

override fun updateView() = Consumer<HistoryState> {
mode = it.mode
if (it.mode != mode) {
mode = it.mode
actionEmitter.onNext(HistoryAction.SwitchMode)
}
(view.history_list.adapter as HistoryAdapter).updateData(it.items, it.mode)

items = it.items
when (val modeCopy = mode) {
is HistoryState.Mode.Normal -> setUIForNormalMode()
is HistoryState.Mode.Editing -> setUIForSelectingMode(modeCopy)
}
}

override fun onBackPressed(): Boolean {
if (mode is HistoryState.Mode.Editing) {
actionEmitter.onNext(HistoryAction.BackPressed)
return true
private fun setUIForSelectingMode(
mode: HistoryState.Mode.Editing
) {
(activity as? AppCompatActivity)?.title =
context.getString(R.string.history_multi_select_title, mode.selectedItems.size)
setToolbarColors(
R.color.white_color,
R.attr.accentHighContrast.getColorIntFromAttr(context!!)
)
}

private fun setUIForNormalMode() {
(activity as? AppCompatActivity)?.title = context.getString(R.string.library_history)
setToolbarColors(
R.attr.primaryText.getColorIntFromAttr(context!!),
R.attr.foundation.getColorIntFromAttr(context)
)
}

private fun setToolbarColors(foreground: Int, background: Int) {
val toolbar = (activity as AppCompatActivity).findViewById<Toolbar>(R.id.navigationToolbar)
val colorFilter = PorterDuffColorFilter(
ContextCompat.getColor(context, foreground), PorterDuff.Mode.SRC_IN
)
toolbar.setBackgroundColor(ContextCompat.getColor(context, background))
toolbar.setTitleTextColor(ContextCompat.getColor(context, foreground))

themeToolbar(
toolbar, foreground,
background, colorFilter
)
}

private fun themeToolbar(
toolbar: androidx.appcompat.widget.Toolbar,
textColor: Int,
backgroundColor: Int,
colorFilter: PorterDuffColorFilter? = null
) {
toolbar.setTitleTextColor(ContextCompat.getColor(context!!, textColor))
toolbar.setBackgroundColor(ContextCompat.getColor(context, backgroundColor))

if (colorFilter == null) {
return
}

return false
toolbar.overflowIcon?.colorFilter = colorFilter
(0 until toolbar.childCount).forEach {
when (val item = toolbar.getChildAt(it)) {
is ImageButton -> item.drawable.colorFilter = colorFilter
}
}
}

override fun onBackPressed(): Boolean {
return when {
mode is HistoryState.Mode.Editing -> {
mode = HistoryState.Mode.Normal
historyAdapter.updateData(items, mode)
setUIForNormalMode()
actionEmitter.onNext(HistoryAction.SwitchMode)
true
}
else -> false
}
}
}
Loading

0 comments on commit f957f35

Please sign in to comment.