Skip to content

Commit

Permalink
# This is a combination of 5 commits.
Browse files Browse the repository at this point in the history
# This is the 1st commit message:

View holders and interactors for recently saved bookmarks

# This is the commit message #2:

Recent bookmark item view holder binding

# This is the commit message mozilla-mobile#3:

Create adapter for recent bookmarks. Implement controller methods. Implement view holder bindings for items

# This is the commit message mozilla-mobile#4:

Top level adapter for recent bookmarks section

# This is the commit message mozilla-mobile#5:

Retrieve list of recent bookmarks on home
  • Loading branch information
Elise Richards committed Jun 10, 2021
1 parent 17f541a commit 2b17998
Show file tree
Hide file tree
Showing 13 changed files with 384 additions and 64 deletions.
29 changes: 29 additions & 0 deletions app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import mozilla.appservices.places.BookmarkRoot
import mozilla.components.browser.menu.view.MenuButton
import mozilla.components.browser.state.selector.findTab
Expand All @@ -70,6 +71,7 @@ import mozilla.components.browser.state.selector.privateTabs
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.selectedOrDefaultSearchEngine
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.storage.BookmarkNode
import mozilla.components.concept.storage.FrecencyThresholdOption
import mozilla.components.concept.sync.AccountObserver
import mozilla.components.concept.sync.AuthType
Expand Down Expand Up @@ -308,6 +310,17 @@ class HomeFragment : Fragment() {
)
}

internal suspend fun getRecentlySavedBookmarks(): List<BookmarkNode>? = withContext(IO) {
val recentBookmarks = bookmarksStorage.getRecentBookmarks(4)
if (recentBookmarks.isNullOrEmpty()) null else recentBookmarks
}

/**
* The [SessionControlView] is forced to update with our current state when we call
* [HomeFragment.onCreateView] in order to be able to draw everything at once with the current
* data in our store. The [View.consumeFrom] coroutine dispatch
* doesn't get run right away which means that we won't draw on the first layout pass.
*/
/**
* The [SessionControlView] is forced to update with our current state when we call
* [HomeFragment.onCreateView] in order to be able to draw everything at once with the current
Expand Down Expand Up @@ -891,6 +904,9 @@ class HomeFragment : Fragment() {
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
}

/**
* This method will find and scroll to the row of the specified collection Id.
* */
/**
* This method will find and scroll to the row of the specified collection Id.
* */
Expand Down Expand Up @@ -932,6 +948,9 @@ class HomeFragment : Fragment() {
}
}

/**
* Returns index of the collection with the specified id.
* */
/**
* Returns index of the collection with the specified id.
* */
Expand All @@ -950,6 +969,9 @@ class HomeFragment : Fragment() {
return result
}

/**
* Will highlight the border of the collection with the specified index.
* */
/**
* Will highlight the border of the collection with the specified index.
* */
Expand Down Expand Up @@ -987,6 +1009,9 @@ class HomeFragment : Fragment() {
}
}

/**
* Will focus the collection with [indexOfCollection] for accessibility services.
* */
/**
* Will focus the collection with [indexOfCollection] for accessibility services.
* */
Expand Down Expand Up @@ -1064,6 +1089,10 @@ class HomeFragment : Fragment() {
private const val FOCUS_ON_ADDRESS_BAR = "focusOnAddressBar"
private const val FOCUS_ON_COLLECTION = "focusOnCollection"

/**
* Represents the number of items in [sessionControlView] that are NOT part of
* the list of collections. At the moment these are topSites pager, collections header.
* */
/**
* Represents the number of items in [sessionControlView] that are NOT part of
* the list of collections. At the moment these are topSites pager, collections header.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/* 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.home.sessioncontrol

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import kotlinx.android.synthetic.main.component_bookmark.view.*
import mozilla.components.concept.storage.BookmarkNode
import org.mozilla.fenix.home.sessioncontrol.viewholders.recentbookmarks.RecentBookmarksViewHolder

class RecentBookmarksAdapter(
private val interactor: SessionControlInteractor
) : ListAdapter<List<BookmarkNode>, RecentBookmarksViewHolder>(RecentBookmarksListDiffCallback) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecentBookmarksViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(RecentBookmarksViewHolder.LAYOUT_ID, parent, false)
return RecentBookmarksViewHolder(view, interactor)
}

override fun onBindViewHolder(
holder: RecentBookmarksViewHolder,
position: Int,
payloads: MutableList<Any>
) {
if (payloads.isNullOrEmpty()) {
onBindViewHolder(holder, position)
} else {
if (payloads[0] is AdapterItem.RecentBookmarksPayload) {
val adapter = holder.itemView.bookmark_list.adapter as RecentBookmarksItemAdapter
val payload = payloads[0] as AdapterItem.RecentBookmarksPayload
for (item in payload.changed) {
adapter.notifyItemChanged(
item.first % RecentBookmarksViewHolder.MAX_BOOKMARKS,
RecentBookmarksItemAdapter.RecentBookmarkItemPayload(item.second)
)
}
}
}
}

override fun onBindViewHolder(holder: RecentBookmarksViewHolder, position: Int) {
val adapter = holder.itemView.bookmark_list.adapter as RecentBookmarksItemAdapter
adapter.submitList(getItem(position))
}

internal object RecentBookmarksListDiffCallback : DiffUtil.ItemCallback<List<BookmarkNode>>() {
override fun areItemsTheSame(
oldItem: List<BookmarkNode>, newItem: List<BookmarkNode>
): Boolean {
return oldItem.size == newItem.size
}

override fun areContentsTheSame(
oldItem: List<BookmarkNode>, newItem: List<BookmarkNode>
): Boolean {
return newItem.zip(oldItem).all { (new, old) -> new == old }
}

override fun getChangePayload(
oldItem: List<BookmarkNode>, newItem: List<BookmarkNode>
): Any? {
val changed = mutableSetOf<Pair<Int, BookmarkNode>>()
for ((index, item) in newItem.withIndex()) {
if (oldItem.getOrNull(index) != item) {
changed.add(Pair(index, item))
}
}
return if (changed.isNotEmpty()) AdapterItem.RecentBookmarksPayload(changed) else null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* 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.home.sessioncontrol

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import mozilla.components.concept.storage.BookmarkNode
import org.mozilla.fenix.home.sessioncontrol.viewholders.recentbookmarks.RecentBookmarkItemViewHolder

class RecentBookmarksItemAdapter(
private val interactor: SessionControlInteractor
) : ListAdapter<BookmarkNode, RecentBookmarkItemViewHolder>(RecentBookmarksDiffCallback) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecentBookmarkItemViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(RecentBookmarkItemViewHolder.LAYOUT_ID, parent, false)
return RecentBookmarkItemViewHolder(view, interactor)
}

override fun onBindViewHolder(holder: RecentBookmarkItemViewHolder, position: Int) {
// StartupTimeline.onTopSitesItemBound(holder)
holder.bind(getItem(position))
}

override fun onBindViewHolder(
holder: RecentBookmarkItemViewHolder,
position: Int,
payloads: MutableList<Any>
) {
if (payloads.isNullOrEmpty()) {
onBindViewHolder(holder, position)
} else {
when (payloads[0]) {
is BookmarkNode -> {
holder.bind((payloads[0] as BookmarkNode))
}
}
}
}


data class RecentBookmarkItemPayload(
val newInstance: BookmarkNode
)

// object RecentBookmarksHeader : AdapterItem(RecentBookmarksHeaderViewHolder.LAYOUT_ID)
// object RecentBookmarkItem : AdapterItem(.LAYOUT_ID)

internal object RecentBookmarksDiffCallback : DiffUtil.ItemCallback<BookmarkNode>() {
override fun areItemsTheSame(oldItem: BookmarkNode, newItem: BookmarkNode) = oldItem.guid == newItem.guid

override fun areContentsTheSame(oldItem: BookmarkNode, newItem: BookmarkNode) =
oldItem.guid == newItem.guid &&
oldItem.parentGuid == newItem.parentGuid &&
oldItem.title == newItem.title &&
oldItem.url == newItem.url &&
oldItem.type == newItem.type
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.concept.storage.BookmarkNode
import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.top.sites.TopSite
import mozilla.components.ui.widgets.WidgetSiteItemView
Expand All @@ -22,7 +23,7 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHol
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.NoCollectionsMessageViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.RecentBookmarksHeaderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.recentbookmarks.RecentBookmarksHeaderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TopSitePagerViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.ExperimentDefaultBrowserCardViewHolder
Expand All @@ -37,6 +38,7 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingTh
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingToolbarPositionPickerViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingTrackingProtectionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingWhatsNewViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.recentbookmarks.RecentBookmarkItemViewHolder
import org.mozilla.fenix.home.tips.ButtonTipViewHolder
import mozilla.components.feature.tab.collections.Tab as ComponentTab

Expand Down Expand Up @@ -132,8 +134,12 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) {

object OnboardingWhatsNew : AdapterItem(OnboardingWhatsNewViewHolder.LAYOUT_ID)

object RecentBookmarksHeader : AdapterItem(CollectionHeaderViewHolder.LAYOUT_ID)
object RecentBookmarkItem : AdapterItem(CollectionViewHolder.LAYOUT_ID)
object RecentBookmarksHeader : AdapterItem(RecentBookmarksHeaderViewHolder.LAYOUT_ID)
object RecentBookmarkItem : AdapterItem(RecentBookmarkItemViewHolder.LAYOUT_ID)

data class RecentBookmarksPayload(
val changed: Set<Pair<Int, BookmarkNode>>
)

/**
* True if this item represents the same value as other. Used by [AdapterItemDiffCallback].
Expand Down Expand Up @@ -215,6 +221,7 @@ class SessionControlAdapter(
view
)
ExperimentDefaultBrowserCardViewHolder.LAYOUT_ID -> ExperimentDefaultBrowserCardViewHolder(view, interactor)
RecentBookmarksHeaderViewHolder.LAYOUT_ID -> RecentBookmarksHeaderViewHolder(view)

else -> throw IllegalStateException()
}
Expand Down Expand Up @@ -267,7 +274,8 @@ class SessionControlAdapter(
is OnboardingAutomaticSignInViewHolder -> holder.bind(
(item as AdapterItem.OnboardingAutomaticSignIn).state.withAccount
)
is RecentBookmarksHeaderViewHolder -> holder.bind()
is RecentBookmarksHeaderViewHolder ->
holder.bind(item as AdapterItem.RecentBookmarksHeader)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ import androidx.navigation.NavController
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.appservices.places.BookmarkRoot
import mozilla.components.browser.state.selector.getNormalOrPrivateTabs
import mozilla.components.browser.state.state.availableSearchEngines
import mozilla.components.browser.state.state.searchEngines
import mozilla.components.browser.state.state.selectedOrDefaultSearchEngine
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.Engine
import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.concept.storage.BookmarkNode
import mozilla.components.feature.session.SessionUseCases
import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.tab.collections.ext.invoke
Expand All @@ -27,6 +29,7 @@ import mozilla.components.feature.top.sites.TopSite
import mozilla.components.support.ktx.android.view.showKeyboard
import mozilla.components.support.ktx.kotlin.isUrl
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.GlobalDirections
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
Expand Down Expand Up @@ -178,6 +181,16 @@ interface SessionControlController {
* @see [ExperimentCardInteractor.onCloseExperimentCardClicked]
*/
fun handleCloseExperimentCard()

/**
* @see [RecentBookmarksInteractor.onRecentBookmarkClicked]
*/
fun handleBookmarkClicked(bookmark: BookmarkNode)

/**
* @see [RecentBookmarksInteractor.onShowAllBookmarksClicked]
*/
fun handleShowAllBookmarksClicked()
}

@Suppress("TooManyFunctions", "LargeClass")
Expand Down Expand Up @@ -576,4 +589,20 @@ class DefaultSessionControlController(
metrics.track(Event.CloseExperimentCardClicked)
fragmentStore.dispatch(HomeFragmentAction.RemoveSetDefaultBrowserCard)
}

override fun handleBookmarkClicked(bookmark: BookmarkNode) {
with(activity) {
browsingModeManager.mode = browsingModeManager.mode
openToBrowserAndLoad(
searchTermOrURL = bookmark.url!!,
newTab = true,
from = BrowserDirection.FromHome
)
}
}

override fun handleShowAllBookmarksClicked() {
val directions = HomeFragmentDirections.actionGlobalBookmarkFragment(BookmarkRoot.Mobile.id)
navController.nav(R.id.homeFragment, directions)
}
}
Loading

0 comments on commit 2b17998

Please sign in to comment.