1
0
Fork 0

For #2205 & #1578: Integrates tab collection storage (#2478)

* For #2205: Adds TabCollectionStorage

* For #1578: Adds delete to TabCollection
master
Sawyer Blatz 2019-05-16 14:02:24 -07:00 committed by GitHub
parent 892a4b7bf4
commit 72d29c2a43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 228 additions and 98 deletions

View File

@ -309,6 +309,7 @@ dependencies {
implementation Deps.mozilla_feature_session_bundling
implementation Deps.mozilla_feature_site_permissions
implementation Deps.mozilla_feature_readerview
implementation Deps.mozilla_feature_tab_collections
implementation Deps.mozilla_service_firefox_accounts
implementation Deps.mozilla_service_fretboard

View File

@ -687,7 +687,7 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
launch {
val host = session.url.toUri()?.host
val sitePermissions: SitePermissions? = host?.let {
val storage = requireContext().components.storage
val storage = requireContext().components.core.permissionStorage
storage.findSitePermissionsBy(it)
}

View File

@ -14,20 +14,26 @@ import androidx.fragment.app.DialogFragment
import androidx.lifecycle.ViewModelProviders
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_create_collection.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.mozilla.fenix.FenixViewModelProvider
import mozilla.components.browser.session.Session
import org.mozilla.fenix.R
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.ext.getRootView
import org.mozilla.fenix.home.sessioncontrol.TabCollection
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter
import java.util.Random
import kotlin.coroutines.CoroutineContext
class CreateCollectionFragment : DialogFragment() {
// Temporary callback. In the future we will just directly add the collection to the core session manager.
var onCollectionSaved: ((TabCollection) -> Unit)? = null
class CreateCollectionFragment : DialogFragment(), CoroutineScope {
private lateinit var collectionCreationComponent: CollectionCreationComponent
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -40,6 +46,7 @@ class CreateCollectionFragment : DialogFragment() {
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
job = Job()
val view = inflater.inflate(R.layout.fragment_create_collection, container, false)
val viewModel = activity?.run {
@ -76,6 +83,12 @@ class CreateCollectionFragment : DialogFragment() {
subscribeToActions()
}
override fun onDestroyView() {
super.onDestroyView()
job.cancel()
}
@Suppress("ComplexMethod")
private fun subscribeToActions() {
getAutoDisposeObservable<CollectionCreationAction>().subscribe {
when (it) {
@ -97,8 +110,17 @@ class CreateCollectionFragment : DialogFragment() {
is CollectionCreationAction.SaveCollectionName -> {
showSavedSnackbar(it.tabs.size)
dismiss()
val newCollection = TabCollection(Random().nextInt(), it.name, it.tabs.toMutableList())
onCollectionSaved?.invoke(newCollection)
val sessionBundle = mutableListOf<Session>()
it.tabs.forEach {
requireComponents.core.sessionManager.findSessionById(it.sessionId)?.let { session ->
sessionBundle.add(session)
}
}
launch(Dispatchers.IO) {
requireComponents.core.tabCollectionStorage.createCollection(it.name, sessionBundle)
}
}
}
}

View File

@ -19,5 +19,4 @@ class Components(private val context: Context) {
val useCases by lazy { UseCases(context, core.sessionManager, search.searchEngineManager) }
val utils by lazy { Utilities(context, core.sessionManager, useCases.sessionUseCases, useCases.searchUseCases) }
val analytics by lazy { Analytics(context) }
val storage by lazy { Storage(context) }
}

View File

@ -127,8 +127,11 @@ class Core(private val context: Context) {
*/
val historyStorage by lazy { PlacesHistoryStorage(context) }
val bookmarksStorage
by lazy { PlacesBookmarksStorage(context) }
val bookmarksStorage by lazy { PlacesBookmarksStorage(context) }
val tabCollectionStorage by lazy { TabCollectionStorage(context, sessionManager) }
val permissionStorage by lazy { PermissionStorage(context) }
/**
* Constructs a [TrackingProtectionPolicy] based on current preferences.

View File

@ -12,7 +12,7 @@ import mozilla.components.feature.sitepermissions.SitePermissionsStorage
import org.mozilla.fenix.test.Mockable
@Mockable
class Storage(private val context: Context) {
class PermissionStorage(private val context: Context) {
private val permissionsStorage by lazy {
SitePermissionsStorage(context)

View File

@ -0,0 +1,55 @@
/* 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.components
import android.content.Context
import androidx.lifecycle.LiveData
import androidx.paging.DataSource
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import mozilla.components.feature.tab.collections.Tab
import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.tab.collections.TabCollectionStorage
import org.mozilla.fenix.test.Mockable
@Mockable
class TabCollectionStorage(private val context: Context, private val sessionManager: SessionManager) {
private val collectionStorage by lazy {
TabCollectionStorage(context, sessionManager)
}
fun createCollection(title: String, sessions: List<Session>) {
collectionStorage.createCollection(title, sessions)
}
fun addTabsToCollection(tabCollection: TabCollection, sessions: List<Session>) {
collectionStorage.addTabsToCollection(tabCollection, sessions)
}
fun getCollections(limit: Int = 20): LiveData<List<TabCollection>> {
return collectionStorage.getCollections(limit)
}
fun getCollectionsPaged(): DataSource.Factory<Int, TabCollection> {
return collectionStorage.getCollectionsPaged()
}
fun removeCollection(tabCollection: TabCollection) {
collectionStorage.removeCollection(tabCollection)
}
fun removeTabFromCollection(tabCollection: TabCollection, tab: Tab) {
if (tabCollection.tabs.size == 1) {
removeCollection(tabCollection)
} else {
collectionStorage.removeTabFromCollection(tabCollection, tab)
}
}
fun renameCollection(tabCollection: TabCollection, title: String) {
collectionStorage.renameCollection(tabCollection, title)
}
}

View File

@ -164,7 +164,7 @@ class DefaultToolbarMenu(
BrowserMenuImageText(
context.getString(R.string.browser_menu_save_to_collection),
R.drawable.ic_archive,
R.drawable.ic_tab_collection,
DefaultThemeManager.resolveAttribute(R.attr.primaryText, context)
) {
onItemTapped.invoke(ToolbarMenu.Item.SaveToCollection)

View File

@ -13,6 +13,7 @@ import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout.LayoutParams.PARENT_ID
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_home.*
@ -68,6 +69,8 @@ import kotlin.math.roundToInt
class HomeFragment : Fragment(), CoroutineScope {
private val bus = ActionBusFactory.get(this)
private var sessionObserver: SessionManager.Observer? = null
private var tabCollectionObserver: Observer<List<TabCollection>>? = null
private var homeMenu: HomeMenu? = null
var deleteSessionJob: (suspend () -> Unit)? = null
@ -79,9 +82,6 @@ class HomeFragment : Fragment(), CoroutineScope {
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
// TODO Remove this stub when we have the a-c version!
var storedCollections = mutableListOf<TabCollection>()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -99,7 +99,7 @@ class HomeFragment : Fragment(), CoroutineScope {
this,
SessionControlViewModel::class.java
) {
SessionControlViewModel(SessionControlState(listOf(), listOf(), mode))
SessionControlViewModel(SessionControlState(listOf(), setOf(), listOf(), mode))
}
)
@ -190,13 +190,6 @@ class HomeFragment : Fragment(), CoroutineScope {
) ?: arrayListOf()).toList()
)
)
getManagedEmitter<SessionControlChange>().onNext(
SessionControlChange.CollectionsChange(
(savedInstanceState.getParcelableArrayList<TabCollection>(
KEY_COLLECTIONS
) ?: arrayListOf()).toList()
)
)
}
}
@ -230,12 +223,17 @@ class HomeFragment : Fragment(), CoroutineScope {
emitSessionChanges()
sessionObserver = subscribeToSessions()
tabCollectionObserver = subscribeToTabCollections()
}
override fun onStop() {
sessionObserver?.let {
requireComponents.core.sessionManager.unregister(it)
}
tabCollectionObserver?.let {
requireComponents.core.tabCollectionStorage.getCollections().removeObserver(it)
}
super.onStop()
}
@ -317,13 +315,17 @@ class HomeFragment : Fragment(), CoroutineScope {
private fun handleCollectionAction(action: CollectionAction) {
when (action) {
is CollectionAction.Expand -> {
storedCollections.find { it.id == action.collection.id }?.apply { expanded = true }
getManagedEmitter<SessionControlChange>()
.onNext(SessionControlChange.ExpansionChange(action.collection, true))
}
is CollectionAction.Collapse -> {
storedCollections.find { it.id == action.collection.id }?.apply { expanded = false }
getManagedEmitter<SessionControlChange>()
.onNext(SessionControlChange.ExpansionChange(action.collection, false))
}
is CollectionAction.Delete -> {
storedCollections.find { it.id == action.collection.id }?.let { storedCollections.remove(it) }
launch(Dispatchers.IO) {
requireComponents.core.tabCollectionStorage.removeCollection(action.collection)
}
}
is CollectionAction.AddTab -> {
ItsNotBrokenSnack(context!!).showSnackbar(issueNumber = "1575")
@ -338,17 +340,11 @@ class HomeFragment : Fragment(), CoroutineScope {
ItsNotBrokenSnack(context!!).showSnackbar(issueNumber = "1585")
}
is CollectionAction.RemoveTab -> {
ItsNotBrokenSnack(context!!).showSnackbar(issueNumber = "1578")
launch(Dispatchers.IO) {
requireComponents.core.tabCollectionStorage.removeTabFromCollection(action.collection, action.tab)
}
}
}
emitCollectionChange()
}
private fun emitCollectionChange() {
storedCollections.map { it.copy() }.let {
getManagedEmitter<SessionControlChange>().onNext(SessionControlChange.CollectionsChange(it))
}
}
override fun onPause() {
@ -396,6 +392,14 @@ class HomeFragment : Fragment(), CoroutineScope {
return getString(resourceId)
}
private fun subscribeToTabCollections(): Observer<List<TabCollection>> {
val observer = Observer<List<TabCollection>> {
getManagedEmitter<SessionControlChange>().onNext(SessionControlChange.CollectionsChange(it))
}
requireComponents.core.tabCollectionStorage.getCollections().observe(this, observer)
return observer
}
private fun subscribeToSessions(): SessionManager.Observer {
val observer = object : SessionManager.Observer {
override fun onSessionAdded(session: Session) {
@ -520,6 +524,5 @@ class HomeFragment : Fragment(), CoroutineScope {
companion object {
private const val toolbarPaddingDp = 12f
private const val KEY_TABS = "tabs"
private const val KEY_COLLECTIONS = "collections"
}
}

View File

@ -43,7 +43,7 @@ class SessionBottomSheetFragment : BottomSheetDialogFragment(), LayoutContainer
view.current_session_card_title.text = getCardTitle()
view.current_session_card_tab_list.text = getTabTitles()
view.archive_session_button.apply {
val drawable = ContextCompat.getDrawable(context!!, R.drawable.ic_archive)
val drawable = ContextCompat.getDrawable(context!!, R.drawable.ic_tab_collection)
drawable?.setColorFilter(
ContextCompat.getColor(
context!!,

View File

@ -28,6 +28,7 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingPr
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingSectionHeaderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingThemePickerViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingTrackingProtectionViewHolder
import mozilla.components.feature.tab.collections.Tab as ComponentTab
import java.lang.IllegalStateException
sealed class AdapterItem {
@ -42,7 +43,11 @@ sealed class AdapterItem {
object CollectionHeader : AdapterItem()
object NoCollectionMessage : AdapterItem()
data class CollectionItem(val collection: TabCollection) : AdapterItem()
data class TabInCollectionItem(val collection: TabCollection, val tab: Tab, val isLastTab: Boolean) : AdapterItem()
data class TabInCollectionItem(
val collection: TabCollection,
val tab: ComponentTab,
val isLastTab: Boolean
) : AdapterItem()
object OnboardingHeader : AdapterItem()
data class OnboardingSectionHeader(val labelBuilder: (Context) -> String) : AdapterItem()
@ -82,9 +87,11 @@ class SessionControlAdapter(
private var items: List<AdapterItem> = listOf()
private lateinit var job: Job
private lateinit var expandedCollections: Set<Long>
fun reloadData(items: List<AdapterItem>) {
fun reloadData(items: List<AdapterItem>, expandedCollections: Set<Long>) {
this.items = items
this.expandedCollections = expandedCollections
notifyDataSetChanged()
}
@ -138,9 +145,10 @@ class SessionControlAdapter(
is TabViewHolder -> holder.bindSession(
(items[position] as AdapterItem.TabItem).tab
)
is CollectionViewHolder -> holder.bindSession(
(items[position] as AdapterItem.CollectionItem).collection
)
is CollectionViewHolder -> {
val collection = (items[position] as AdapterItem.CollectionItem).collection
holder.bindSession(collection, expandedCollections.contains(collection.id))
}
is TabInCollectionViewHolder -> {
val item = items[position] as AdapterItem.TabInCollectionItem
holder.bindSession(item.collection, item.tab, item.isLastTab)

View File

@ -4,6 +4,7 @@
package org.mozilla.fenix.home.sessioncontrol
import android.content.Context
import android.graphics.Bitmap
import android.os.Parcelable
import android.view.ViewGroup
@ -12,6 +13,10 @@ import io.reactivex.Observer
import kotlinx.android.parcel.Parcelize
import org.mozilla.fenix.mvi.ViewState
import org.mozilla.fenix.mvi.Change
import mozilla.components.browser.session.Session
import mozilla.components.feature.tab.collections.TabCollection as ACTabCollection
import mozilla.components.feature.tab.collections.Tab as ComponentTab
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.mvi.Action
import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.UIComponent
@ -49,15 +54,6 @@ data class Tab(
val thumbnail: Bitmap? = null
) : Parcelable
@Parcelize
data class TabCollection(
val id: Int,
val title: String,
val tabs: MutableList<Tab>,
val iconColor: Int = 0,
var expanded: Boolean = false
) : Parcelable
sealed class Mode {
object Normal : Mode()
object Private : Mode()
@ -66,10 +62,13 @@ sealed class Mode {
data class SessionControlState(
val tabs: List<Tab>,
val expandedCollections: Set<Long>,
val collections: List<TabCollection>,
val mode: Mode
) : ViewState
typealias TabCollection = ACTabCollection
sealed class TabAction : Action {
data class SaveTabGroup(val selectedTabSessionId: String?) : TabAction()
object Add : TabAction()
@ -89,7 +88,7 @@ sealed class CollectionAction : Action {
data class Rename(val collection: TabCollection) : CollectionAction()
data class OpenTabs(val collection: TabCollection) : CollectionAction()
data class ShareTabs(val collection: TabCollection) : CollectionAction()
data class RemoveTab(val collection: TabCollection, val tab: Tab) : CollectionAction()
data class RemoveTab(val collection: TabCollection, val tab: ComponentTab) : CollectionAction()
}
sealed class OnboardingAction : Action {
@ -118,17 +117,33 @@ sealed class SessionControlChange : Change {
data class TabsChange(val tabs: List<Tab>) : SessionControlChange()
data class ModeChange(val mode: Mode) : SessionControlChange()
data class CollectionsChange(val collections: List<TabCollection>) : SessionControlChange()
data class ExpansionChange(val collection: TabCollection, val expand: Boolean) : SessionControlChange()
}
class SessionControlViewModel(
initialState: SessionControlState
) : UIComponentViewModelBase<SessionControlState, SessionControlChange>(initialState, reducer) {
companion object {
fun getSessionFromTab(context: Context, tab: Tab): Session? {
return context.components.core.sessionManager.findSessionById(tab.sessionId)
}
val reducer: (SessionControlState, SessionControlChange) -> SessionControlState = { state, change ->
when (change) {
is SessionControlChange.CollectionsChange -> state.copy(collections = change.collections)
is SessionControlChange.TabsChange -> state.copy(tabs = change.tabs)
is SessionControlChange.ModeChange -> state.copy(mode = change.mode)
is SessionControlChange.ExpansionChange -> {
val newExpandedCollection = state.expandedCollections.toMutableSet()
if (change.expand) {
newExpandedCollection.add(change.collection.id)
} else {
newExpandedCollection.remove(change.collection.id)
}
state.copy(expandedCollections = newExpandedCollection)
}
}
}
}

View File

@ -16,7 +16,11 @@ import org.mozilla.fenix.mvi.UIView
import androidx.recyclerview.widget.ItemTouchHelper
import org.mozilla.fenix.BuildConfig
private fun normalModeAdapterItems(tabs: List<Tab>, collections: List<TabCollection>): List<AdapterItem> {
private fun normalModeAdapterItems(
tabs: List<Tab>,
collections: List<TabCollection>,
expandedCollections: Set<Long>
): List<AdapterItem> {
val items = mutableListOf<AdapterItem>()
items.add(AdapterItem.TabHeader(false, tabs.isNotEmpty()))
@ -33,9 +37,9 @@ private fun normalModeAdapterItems(tabs: List<Tab>, collections: List<TabCollect
if (collections.isNotEmpty()) {
// If the collection is expanded, we want to add all of its tabs beneath it in the adapter
collections.reversed().map(AdapterItem::CollectionItem).forEach {
collections.map(AdapterItem::CollectionItem).forEach {
items.add(it)
if (it.collection.expanded) {
if (it.collection.isExpanded(expandedCollections)) {
items.addAll(collectionTabItems(it.collection))
}
}
@ -76,14 +80,18 @@ private fun onboardingAdapterItems(): List<AdapterItem> = listOf(
)
private fun SessionControlState.toAdapterList(): List<AdapterItem> = when (mode) {
is Mode.Normal -> normalModeAdapterItems(tabs, collections)
is Mode.Normal -> normalModeAdapterItems(tabs, collections, expandedCollections)
is Mode.Private -> privateModeAdapterItems(tabs)
is Mode.Onboarding -> onboardingAdapterItems()
}
private fun collectionTabItems(collection: TabCollection) = collection.tabs.mapIndexed { index, tab ->
AdapterItem.TabInCollectionItem(collection, tab, index == collection.tabs.lastIndex)
}
}
private fun TabCollection.isExpanded(expandedCollections: Set<Long>): Boolean {
return expandedCollections.contains(this.id)
}
class SessionControlUIView(
container: ViewGroup,
@ -101,6 +109,7 @@ class SessionControlUIView(
.findViewById(R.id.home_component)
private val sessionControlAdapter = SessionControlAdapter(actionEmitter)
private var expandedCollections = setOf<Long>()
init {
view.apply {
@ -117,8 +126,8 @@ class SessionControlUIView(
}
override fun updateView() = Consumer<SessionControlState> {
sessionControlAdapter.reloadData(it.toAdapterList())
sessionControlAdapter.reloadData(it.toAdapterList(), it.expandedCollections)
expandedCollections = it.expandedCollections
// There is a current bug in the combination of MotionLayout~alhpa4 and RecyclerView where it doesn't think
// it has to redraw itself. For some reason calling scrollBy forces this to happen every time
// https://stackoverflow.com/a/42549611

View File

@ -21,6 +21,7 @@ import mozilla.components.browser.menu.BrowserMenuBuilder
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
import org.mozilla.fenix.DefaultThemeManager
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.urlToTrimmedHost
import org.mozilla.fenix.home.sessioncontrol.CollectionAction
import org.mozilla.fenix.home.sessioncontrol.SessionControlAction
import org.mozilla.fenix.home.sessioncontrol.TabCollection
@ -40,6 +41,7 @@ class CollectionViewHolder(
get() = Dispatchers.IO + job
private lateinit var collection: TabCollection
private var expanded = false
private var state = CollectionState.Collapsed
private var collectionMenu: CollectionItemMenu
@ -78,8 +80,9 @@ class CollectionViewHolder(
)
}
fun bindSession(collection: TabCollection) {
fun bindSession(collection: TabCollection, expanded: Boolean) {
this.collection = collection
this.expanded = expanded
updateCollectionUI()
}
@ -89,7 +92,7 @@ class CollectionViewHolder(
var hostNameList = listOf<String>()
collection.tabs.forEach {
hostNameList += it.hostname.capitalize()
hostNameList += it.url.urlToTrimmedHost().capitalize()
}
var tabsDisplayed = 0
@ -106,7 +109,7 @@ class CollectionViewHolder(
view.collection_description.text = titleList
if (collection.expanded) {
if (expanded) {
(view.layoutParams as ViewGroup.MarginLayoutParams).bottomMargin = 0
collection_title.setPadding(0, 0, 0, EXPANDED_PADDING)
view.background = ContextCompat.getDrawable(view.context, R.drawable.rounded_top_corners)

View File

@ -23,12 +23,13 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.getColorFromAttr
import org.mozilla.fenix.ext.increaseTapArea
import org.mozilla.fenix.ext.urlToTrimmedHost
import org.mozilla.fenix.home.sessioncontrol.CollectionAction
import org.mozilla.fenix.home.sessioncontrol.SessionControlAction
import org.mozilla.fenix.home.sessioncontrol.Tab
import org.mozilla.fenix.home.sessioncontrol.TabCollection
import org.mozilla.fenix.home.sessioncontrol.onNext
import kotlin.coroutines.CoroutineContext
import mozilla.components.feature.tab.collections.Tab as ComponentTab
class TabInCollectionViewHolder(
val view: View,
@ -42,7 +43,7 @@ class TabInCollectionViewHolder(
lateinit var collection: TabCollection
private set
lateinit var tab: Tab
lateinit var tab: ComponentTab
private set
var isLastTab = false
@ -66,7 +67,7 @@ class TabInCollectionViewHolder(
}
}
fun bindSession(collection: TabCollection, tab: Tab, isLastTab: Boolean) {
fun bindSession(collection: TabCollection, tab: ComponentTab, isLastTab: Boolean) {
this.collection = collection
this.tab = tab
this.isLastTab = isLastTab
@ -74,7 +75,7 @@ class TabInCollectionViewHolder(
}
private fun updateTabUI() {
collection_tab_hostname.text = tab.hostname
collection_tab_hostname.text = tab.url.urlToTrimmedHost()
collection_tab_title.text = tab.title
launch(Dispatchers.IO) {
val bitmap = collection_tab_icon.context.components.utils.icons

View File

@ -47,7 +47,7 @@ import org.mozilla.fenix.ext.allowUndo
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.share
import org.mozilla.fenix.ext.urlToHost
import org.mozilla.fenix.ext.urlToTrimmedHost
import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter
@ -238,10 +238,12 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
is BookmarkAction.Delete -> {
val components = context?.applicationContext?.components!!
getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.Change(currentRoot - it.item.guid))
getManagedEmitter<BookmarkChange>()
.onNext(BookmarkChange.Change(currentRoot - it.item.guid))
CoroutineScope(Main).allowUndo(
view!!, getString(R.string.bookmark_deletion_snackbar_message, it.item.url.urlToHost()),
view!!,
getString(R.string.bookmark_deletion_snackbar_message, it.item.url.urlToTrimmedHost()),
getString(R.string.bookmark_undo_deletion), { refreshBookmarks(components) }
) {
components.core.bookmarksStorage.deleteNode(it.item.guid)

View File

@ -53,7 +53,8 @@ class SitePermissionsDetailsExceptionsFragment : PreferenceFragmentCompat(), Cor
super.onResume()
launch(IO) {
val context = requireContext()
sitePermissions = requireNotNull(context.components.storage.findSitePermissionsBy(sitePermissions.origin))
sitePermissions =
requireNotNull(context.components.core.permissionStorage.findSitePermissionsBy(sitePermissions.origin))
launch(Main) {
bindCategoryPhoneFeatures()
}
@ -112,7 +113,7 @@ class SitePermissionsDetailsExceptionsFragment : PreferenceFragmentCompat(), Cor
private fun clearSitePermissions() {
launch(IO) {
requireContext().components.storage.deleteSitePermissions(sitePermissions)
requireContext().components.core.permissionStorage.deleteSitePermissions(sitePermissions)
launch(Main) {
Navigation.findNavController(requireNotNull(view)).popBackStack()
}

View File

@ -70,7 +70,7 @@ class SitePermissionsExceptionsFragment : Fragment(), View.OnClickListener, Coro
recyclerView = rootView.findViewById(R.id.exceptions)
recyclerView.layoutManager = LinearLayoutManager(requireContext())
val sitePermissionsPaged = requireContext().components.storage.getSitePermissionsPaged()
val sitePermissionsPaged = requireContext().components.core.permissionStorage.getSitePermissionsPaged()
val adapter = ExceptionsAdapter(this)
val liveData = LivePagedListBuilder(sitePermissionsPaged, MAX_ITEMS_PER_PAGE).build()
@ -124,7 +124,7 @@ class SitePermissionsExceptionsFragment : Fragment(), View.OnClickListener, Coro
private fun deleteAllSitePermissions() {
launch(IO) {
requireContext().components.storage.deleteAllSitePermissions()
requireContext().components.core.permissionStorage.deleteAllSitePermissions()
launch(Main) {
showEmptyListMessage()
}

View File

@ -172,7 +172,7 @@ class SitePermissionsManageExceptionsPhoneFeatureFragment : Fragment(), Coroutin
PhoneFeature.NOTIFICATION -> sitePermissions.copy(notification = status)
}
launch(IO) {
requireContext().components.storage.updateSitePermissions(updatedSitePermissions)
requireContext().components.core.permissionStorage.updateSitePermissions(updatedSitePermissions)
}
}
}

View File

@ -60,10 +60,11 @@ class QuickSettingsComponent(
PhoneFeature.MICROPHONE -> microphone = microphone.toggle()
PhoneFeature.NOTIFICATION -> notification = notification.toggle()
}
context.components.storage.addSitePermissionException(origin, location, notification, microphone, camera)
context.components.core.permissionStorage
.addSitePermissionException(origin, location, notification, microphone, camera)
} else {
val updatedSitePermissions = sitePermissions.toggle(featurePhone)
context.components.storage.updateSitePermissions(updatedSitePermissions)
context.components.core.permissionStorage.updateSitePermissions(updatedSitePermissions)
updatedSitePermissions
}
}

View File

@ -245,7 +245,7 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment(), CoroutineSco
launch {
val host = session.url.toUri()?.host
val sitePermissions: SitePermissions? = host?.let {
val storage = requireContext().components.storage
val storage = requireContext().components.core.permissionStorage
storage.findSitePermissionsBy(it)
}
launch(Dispatchers.Main) {

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,20 @@
<?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/. -->
<vector android:height="24dp" android:viewportHeight="20"
android:viewportWidth="20" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="?primaryText" android:fillType="nonZero"
android:pathData="M18,6L2,6L2,17C2,17.5523 2.4477,18 3,18L17,18C17.5523,18 18,17.5523 18,17L18,6ZM16.7908,4L15.333,2.3401C15.1432,2.1239 14.8694,2 14.5817,2L5.8284,2C5.5632,2 5.3089,2.1054 5.1213,2.2929L3.4142,4L16.7908,4ZM0,17L0,5.8284C0,5.0328 0.3161,4.2697 0.8787,3.7071L3.7071,0.8787C4.2697,0.3161 5.0328,0 5.8284,0L14.5817,0C15.4448,0 16.2662,0.3718 16.8358,1.0203L19.2541,3.7739C19.7349,4.3213 20,5.025 20,5.7536L20,17C20,18.6569 18.6569,20 17,20L3,20C1.3431,20 0,18.6569 0,17Z"
android:strokeColor="#00000000" android:strokeWidth="1"/>
<path android:fillColor="?primaryText" android:fillType="nonZero"
android:pathData="M14.95,8.5L5.05,8.5C4.7462,8.5 4.5,8.7239 4.5,9C4.5,9.2761 4.7462,9.5 5.05,9.5L14.95,9.5C15.2538,9.5 15.5,9.2761 15.5,9C15.5,8.7239 15.2538,8.5 14.95,8.5Z"
android:strokeColor="#00000000" android:strokeWidth="1"/>
<path android:fillColor="?primaryText" android:fillType="nonZero"
android:pathData="M14.95,14.5L5.05,14.5C4.7462,14.5 4.5,14.7239 4.5,15C4.5,15.2761 4.7462,15.5 5.05,15.5L14.95,15.5C15.2538,15.5 15.5,15.2761 15.5,15C15.5,14.7239 15.2538,14.5 14.95,14.5Z"
android:strokeColor="#00000000" android:strokeWidth="1"/>
<path android:fillColor="?primaryText" android:fillType="nonZero"
android:pathData="M14.95,11.5L5.05,11.5C4.7462,11.5 4.5,11.7239 4.5,12C4.5,12.2761 4.7462,12.5 5.05,12.5L14.95,12.5C15.2538,12.5 15.5,12.2761 15.5,12C15.5,11.7239 15.2538,11.5 14.95,11.5Z"
android:strokeColor="#00000000" android:strokeWidth="1"/>
</vector>

View File

@ -27,7 +27,7 @@
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:tint="@null"
android:src="@drawable/ic_archive"
android:src="@drawable/ic_tab_collection"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

View File

@ -13,7 +13,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?foundation"
android:drawableStart="@drawable/ic_archive"
android:drawableStart="@drawable/ic_tab_collection"
android:drawablePadding="14dp"
android:drawableTint="?accent"
android:paddingStart="20dp"

View File

@ -16,7 +16,7 @@
android:id="@+id/no_collection_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableEnd="@drawable/ic_archive"
android:drawableEnd="@drawable/ic_tab_collection"
android:drawableTint="?primaryText"
android:drawablePadding="8dp"
android:text="@string/no_collections_header"

View File

@ -23,7 +23,7 @@
android:layout_gravity="center"
android:clickable="false"
android:drawableTint="?foundation"
android:drawableStart="@drawable/ic_archive"
android:drawableStart="@drawable/ic_tab_collection"
android:drawablePadding="8dp"
android:focusable="false"
android:gravity="center"

View File

@ -100,7 +100,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?foundation"
android:drawableStart="@drawable/ic_archive"
android:drawableStart="@drawable/ic_tab_collection"
android:drawablePadding="14dp"
android:drawableTint="?accent"
android:paddingStart="20dp"

View File

@ -27,7 +27,7 @@
android:layout_marginBottom="24dp"
android:layout_marginStart="16dp"
android:tint="@null"
android:src="@drawable/ic_archive"
android:src="@drawable/ic_tab_collection"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

View File

@ -20,5 +20,4 @@ class TestComponents(private val context: Context) : Components(context) {
)
}
override val analytics by lazy { Analytics(context) }
override val storage by lazy { Storage(context) }
}

View File

@ -109,6 +109,7 @@ object Deps {
const val mozilla_feature_session_bundling = "org.mozilla.components:feature-session-bundling:${Versions.mozilla_android_components}"
const val mozilla_feature_site_permissions = "org.mozilla.components:feature-sitepermissions:${Versions.mozilla_android_components}"
const val mozilla_feature_readerview = "org.mozilla.components:feature-readerview:${Versions.mozilla_android_components}"
const val mozilla_feature_tab_collections = "org.mozilla.components:feature-tab-collections:${Versions.mozilla_android_components}"
const val mozilla_service_firefox_accounts = "org.mozilla.components:service-firefox-accounts:${Versions.mozilla_android_components}"
const val mozilla_service_fretboard = "org.mozilla.components:service-fretboard:${Versions.mozilla_android_components}"