From 00ad9d3f6f5c015aae829dd5df123d344315709e Mon Sep 17 00:00:00 2001 From: Jeff Boek Date: Fri, 29 Mar 2019 09:46:34 -0700 Subject: [PATCH] For #356 - Gives a user the ability to delete their history --- .../fenix/library/history/HistoryAdapter.kt | 44 ------------------- .../fenix/library/history/HistoryComponent.kt | 2 +- .../fenix/library/history/HistoryFragment.kt | 41 +++++++++++++---- .../fenix/library/history/HistoryUIView.kt | 37 +++++++++++++--- app/src/main/res/layout/component_history.xml | 42 ++++++++++++++++-- app/src/main/res/layout/history_delete.xml | 28 ------------ 6 files changed, 103 insertions(+), 91 deletions(-) delete mode 100644 app/src/main/res/layout/history_delete.xml diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryAdapter.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryAdapter.kt index 1726722b2..0135b1173 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryAdapter.kt @@ -13,8 +13,6 @@ import android.widget.CompoundButton import androidx.recyclerview.widget.RecyclerView import io.reactivex.Observer import org.mozilla.fenix.R -import androidx.core.content.ContextCompat -import kotlinx.android.synthetic.main.history_delete.view.* import kotlinx.android.synthetic.main.history_header.view.* import kotlinx.android.synthetic.main.history_list_item.view.* import mozilla.components.browser.menu.BrowserMenu @@ -226,48 +224,6 @@ class HistoryAdapter( } } - class HistoryDeleteViewHolder( - view: View, - private val actionEmitter: Observer - ) : RecyclerView.ViewHolder(view) { - private lateinit var mode: HistoryState.Mode - - private val button = view.delete_history_button.apply { - setOnClickListener { - val mode = mode - if (mode is HistoryState.Mode.Editing && mode.selectedItems.isNotEmpty()) { - actionEmitter.onNext(HistoryAction.Delete.Some(mode.selectedItems)) - } else { - actionEmitter.onNext(HistoryAction.Delete.All) - } - } - } - - private val text = view.delete_history_button_text.apply { - val color = ContextCompat.getColor(context, R.color.photonRed60) - val drawable = ContextCompat.getDrawable(context, R.drawable.ic_delete) - drawable?.setTint(color) - this.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null) - } - - fun bind(mode: HistoryState.Mode) { - this.mode = mode - - val text = if (mode is HistoryState.Mode.Editing && mode.selectedItems.isNotEmpty()) { - text.context.resources.getString(R.string.history_delete_some, mode.selectedItems.size) - } else { - text.context.resources.getString(R.string.history_delete_all) - } - - button.contentDescription = text - this.text.text = text - } - - companion object { - const val LAYOUT_ID = R.layout.history_delete - } - } - private var historyList: HistoryList = HistoryList(emptyList()) private var mode: HistoryState.Mode = HistoryState.Mode.Normal diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryComponent.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryComponent.kt index 46269259e..a87bfe313 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryComponent.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryComponent.kt @@ -39,7 +39,7 @@ class HistoryComponent( override val reducer: (HistoryState, HistoryChange) -> HistoryState = { state, change -> when (change) { - is HistoryChange.Change -> state.copy(items = change.list) + is HistoryChange.Change -> state.copy(mode = HistoryState.Mode.Normal, items = change.list) is HistoryChange.EnterEditMode -> state.copy(mode = HistoryState.Mode.Editing(listOf(change.item))) is HistoryChange.AddItemForRemoval -> { val mode = state.mode diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt index 5dff7d071..03d002618 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryFragment.kt @@ -17,9 +17,10 @@ import androidx.navigation.NavOptions import androidx.navigation.Navigation import kotlinx.android.synthetic.main.fragment_history.view.* import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.coroutineScope import mozilla.components.support.base.feature.BackHandler import org.mozilla.fenix.utils.ItsNotBrokenSnack import org.mozilla.fenix.R @@ -29,6 +30,7 @@ import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getManagedEmitter import kotlin.coroutines.CoroutineContext +@SuppressWarnings("TooManyFunctions") class HistoryFragment : Fragment(), CoroutineScope, BackHandler { private lateinit var job: Job @@ -81,18 +83,13 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - launch(Dispatchers.IO) { - val items = requireComponents.core.historyStorage.getDetailedVisits(0) - .asReversed() - .mapIndexed { id, item -> HistoryItem(id, item.url, item.visitTime) } - - launch(Dispatchers.Main) { - getManagedEmitter().onNext(HistoryChange.Change(items)) - } + reloadData() } } + // This method triggers the complexity warning. However it's actually not that hard to understand. + @SuppressWarnings("ComplexMethod") override fun onStart() { super.onStart() getAutoDisposeObservable() @@ -107,6 +104,20 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler { .onNext(HistoryChange.RemoveItemForRemoval(it.item)) is HistoryAction.BackPressed -> getManagedEmitter() .onNext(HistoryChange.ExitEditMode) + is HistoryAction.Delete.All -> launch(Dispatchers.IO) { + requireComponents.core.historyStorage.deleteEverything() + reloadData() + } + is HistoryAction.Delete.One -> launch(Dispatchers.IO) { + requireComponents.core.historyStorage.deleteVisit(it.item.url, it.item.visitedAt) + reloadData() + } + is HistoryAction.Delete.Some -> launch(Dispatchers.IO) { + it.items.forEach { item -> + requireComponents.core.historyStorage.deleteVisit(item.url, item.visitedAt) + } + reloadData() + } } } } @@ -128,4 +139,16 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler { } override fun onBackPressed(): Boolean = (historyComponent.uiView as HistoryUIView).onBackPressed() + + private suspend fun reloadData() { + val items = requireComponents.core.historyStorage.getDetailedVisits(0) + .asReversed() + .mapIndexed { id, item -> HistoryItem(id, item.url, item.visitTime) } + + coroutineScope { + launch(Dispatchers.Main) { + getManagedEmitter().onNext(HistoryChange.Change(items)) + } + } + } } diff --git a/app/src/main/java/org/mozilla/fenix/library/history/HistoryUIView.kt b/app/src/main/java/org/mozilla/fenix/library/history/HistoryUIView.kt index 502f4f298..120481df0 100644 --- a/app/src/main/java/org/mozilla/fenix/library/history/HistoryUIView.kt +++ b/app/src/main/java/org/mozilla/fenix/library/history/HistoryUIView.kt @@ -6,11 +6,12 @@ package org.mozilla.fenix.library.history import android.view.LayoutInflater import android.view.ViewGroup +import androidx.core.widget.NestedScrollView import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView 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.mvi.UIView @@ -26,22 +27,48 @@ class HistoryUIView( var mode: HistoryState.Mode = HistoryState.Mode.Normal private set - override val view: RecyclerView = LayoutInflater.from(container.context) + override val view: NestedScrollView = LayoutInflater.from(container.context) .inflate(R.layout.component_history, container, true) - .findViewById(R.id.history_list) + .findViewById(R.id.history_wrapper) init { - view.apply { + view.history_list.apply { adapter = HistoryAdapter(actionEmitter) layoutManager = LinearLayoutManager(container.context) } + + view.delete_history_button.setOnClickListener { + val mode = mode + val action = when (mode) { + is HistoryState.Mode.Normal -> HistoryAction.Delete.All + is HistoryState.Mode.Editing -> HistoryAction.Delete.Some(mode.selectedItems) + } + + actionEmitter.onNext(action) + } } override fun updateView() = Consumer { mode = it.mode - (view.adapter as HistoryAdapter).updateData(it.items, it.mode) + updateDeleteButton() + (view.history_list.adapter as HistoryAdapter).updateData(it.items, it.mode) } + private fun updateDeleteButton() { + val mode = mode + + val text = if (mode is HistoryState.Mode.Editing && mode.selectedItems.isNotEmpty()) { + view.delete_history_button_text.context.resources.getString( + R.string.history_delete_some, + mode.selectedItems.size + ) + } else { + view.delete_history_button_text.context.resources.getString(R.string.history_delete_all) + } + + view.delete_history_button.contentDescription = text + view.delete_history_button_text.text = text + } override fun onBackPressed(): Boolean { if (mode is HistoryState.Mode.Editing) { actionEmitter.onNext(HistoryAction.BackPressed) diff --git a/app/src/main/res/layout/component_history.xml b/app/src/main/res/layout/component_history.xml index dc970adc2..b322d5336 100644 --- a/app/src/main/res/layout/component_history.xml +++ b/app/src/main/res/layout/component_history.xml @@ -3,8 +3,42 @@ - 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/. --> - + xmlns:android="http://schemas.android.com/apk/res/android"> + + + + + + + + diff --git a/app/src/main/res/layout/history_delete.xml b/app/src/main/res/layout/history_delete.xml deleted file mode 100644 index 9e82722ba..000000000 --- a/app/src/main/res/layout/history_delete.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - \ No newline at end of file