Closes #1312, #1236, #1237, #1238, #1239: Creating, Editing, and Deleting Bookmarks and Bookmark Folders
parent
8f6dca99dc
commit
b54d4d1d58
|
@ -17,6 +17,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- #1195 - Adds telemetry for quick action sheet
|
- #1195 - Adds telemetry for quick action sheet
|
||||||
- #627 - Sets engine preferred color scheme based on light/dark theme
|
- #627 - Sets engine preferred color scheme based on light/dark theme
|
||||||
- #904 - Added tab counter in browser toolbar
|
- #904 - Added tab counter in browser toolbar
|
||||||
|
- #1312 - Added the ability to edit bookmarks
|
||||||
|
- #1236 - Added the ability to create bookmark folders
|
||||||
|
- #1237 - Added the ability to delete bookmark folders
|
||||||
|
- #1238 - Added the ability to edit bookmark folders
|
||||||
|
- #1239 - Added the ability to move bookmark folders
|
||||||
### Changed
|
### Changed
|
||||||
- #1429 - Updated site permissions ui for MVP
|
- #1429 - Updated site permissions ui for MVP
|
||||||
### Removed
|
### Removed
|
|
@ -251,6 +251,11 @@ dependencies {
|
||||||
|
|
||||||
implementation Deps.rxAndroid
|
implementation Deps.rxAndroid
|
||||||
implementation Deps.rxKotlin
|
implementation Deps.rxKotlin
|
||||||
|
implementation Deps.rxBindings
|
||||||
|
implementation Deps.autodispose
|
||||||
|
implementation Deps.autodispose_android
|
||||||
|
implementation Deps.autodispose_android_aac
|
||||||
|
|
||||||
implementation Deps.anko_commons
|
implementation Deps.anko_commons
|
||||||
implementation Deps.anko_sdk
|
implementation Deps.anko_sdk
|
||||||
implementation Deps.anko_constraintlayout
|
implementation Deps.anko_constraintlayout
|
||||||
|
@ -316,6 +321,7 @@ dependencies {
|
||||||
implementation Deps.androidx_navigation_fragment
|
implementation Deps.androidx_navigation_fragment
|
||||||
implementation Deps.androidx_navigation_ui
|
implementation Deps.androidx_navigation_ui
|
||||||
implementation Deps.androidx_recyclerview
|
implementation Deps.androidx_recyclerview
|
||||||
|
implementation Deps.androidx_lifecycle_viewmodel_ktx
|
||||||
|
|
||||||
implementation Deps.autodispose
|
implementation Deps.autodispose
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.home.HomeFragmentDirections
|
import org.mozilla.fenix.home.HomeFragmentDirections
|
||||||
import org.mozilla.fenix.library.bookmarks.BookmarkFragmentDirections
|
import org.mozilla.fenix.library.bookmarks.BookmarkFragmentDirections
|
||||||
|
import org.mozilla.fenix.library.bookmarks.selectfolder.SelectBookmarkFolderFragmentDirections
|
||||||
import org.mozilla.fenix.library.history.HistoryFragmentDirections
|
import org.mozilla.fenix.library.history.HistoryFragmentDirections
|
||||||
import org.mozilla.fenix.search.SearchFragmentDirections
|
import org.mozilla.fenix.search.SearchFragmentDirections
|
||||||
import org.mozilla.fenix.settings.SettingsFragmentDirections
|
import org.mozilla.fenix.settings.SettingsFragmentDirections
|
||||||
|
@ -155,6 +156,8 @@ open class HomeActivity : AppCompatActivity() {
|
||||||
SettingsFragmentDirections.actionSettingsFragmentToBrowserFragment(sessionId)
|
SettingsFragmentDirections.actionSettingsFragmentToBrowserFragment(sessionId)
|
||||||
BrowserDirection.FromBookmarks ->
|
BrowserDirection.FromBookmarks ->
|
||||||
BookmarkFragmentDirections.actionBookmarkFragmentToBrowserFragment(sessionId)
|
BookmarkFragmentDirections.actionBookmarkFragmentToBrowserFragment(sessionId)
|
||||||
|
BrowserDirection.FromBookmarksFolderSelect ->
|
||||||
|
SelectBookmarkFolderFragmentDirections.actionBookmarkSelectFolderFragmentToBrowserFragment(sessionId)
|
||||||
BrowserDirection.FromHistory ->
|
BrowserDirection.FromHistory ->
|
||||||
HistoryFragmentDirections.actionHistoryFragmentToBrowserFragment(sessionId)
|
HistoryFragmentDirections.actionHistoryFragmentToBrowserFragment(sessionId)
|
||||||
}
|
}
|
||||||
|
@ -193,5 +196,5 @@ open class HomeActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class BrowserDirection {
|
enum class BrowserDirection {
|
||||||
FromGlobal, FromHome, FromSearch, FromSettings, FromBookmarks, FromHistory
|
FromGlobal, FromHome, FromSearch, FromSettings, FromBookmarks, FromBookmarksFolderSelect, FromHistory
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ import org.mozilla.fenix.DefaultThemeManager
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.IntentReceiverActivity
|
import org.mozilla.fenix.IntentReceiverActivity
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
import org.mozilla.fenix.components.FindInPageIntegration
|
import org.mozilla.fenix.components.FindInPageIntegration
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.components.metrics.Event.BrowserMenuItemTapped.Item
|
import org.mozilla.fenix.components.metrics.Event.BrowserMenuItemTapped.Item
|
||||||
|
@ -67,9 +68,9 @@ import org.mozilla.fenix.mvi.ActionBusFactory
|
||||||
import org.mozilla.fenix.mvi.getAutoDisposeObservable
|
import org.mozilla.fenix.mvi.getAutoDisposeObservable
|
||||||
import org.mozilla.fenix.quickactionsheet.QuickActionAction
|
import org.mozilla.fenix.quickactionsheet.QuickActionAction
|
||||||
import org.mozilla.fenix.quickactionsheet.QuickActionComponent
|
import org.mozilla.fenix.quickactionsheet.QuickActionComponent
|
||||||
|
import org.mozilla.fenix.settings.quicksettings.QuickSettingsSheetDialogFragment
|
||||||
import org.mozilla.fenix.utils.ItsNotBrokenSnack
|
import org.mozilla.fenix.utils.ItsNotBrokenSnack
|
||||||
import org.mozilla.fenix.utils.Settings
|
import org.mozilla.fenix.utils.Settings
|
||||||
import org.mozilla.fenix.settings.quicksettings.QuickSettingsSheetDialogFragment
|
|
||||||
|
|
||||||
@SuppressWarnings("TooManyFunctions", "LargeClass")
|
@SuppressWarnings("TooManyFunctions", "LargeClass")
|
||||||
class BrowserFragment : Fragment(), BackHandler {
|
class BrowserFragment : Fragment(), BackHandler {
|
||||||
|
@ -323,24 +324,26 @@ class BrowserFragment : Fragment(), BackHandler {
|
||||||
requireComponents.analytics.metrics.track(Event.QuickActionSheetBookmarkTapped)
|
requireComponents.analytics.metrics.track(Event.QuickActionSheetBookmarkTapped)
|
||||||
val session = requireComponents.core.sessionManager.selectedSession
|
val session = requireComponents.core.sessionManager.selectedSession
|
||||||
CoroutineScope(IO).launch {
|
CoroutineScope(IO).launch {
|
||||||
requireComponents.core.bookmarksStorage
|
val guid = requireComponents.core.bookmarksStorage
|
||||||
.addItem(BookmarkRoot.Mobile.id, session!!.url, session.title, null)
|
.addItem(BookmarkRoot.Mobile.id, session!!.url, session.title, null)
|
||||||
launch(Main) {
|
launch(Main) {
|
||||||
val rootView =
|
context?.asActivity()?.window?.decorView
|
||||||
context?.asActivity()?.window?.decorView?.findViewById<View>(android.R.id.content)
|
?.findViewById<View>(android.R.id.content)?.let { view ->
|
||||||
rootView?.let { view ->
|
FenixSnackbar.make(
|
||||||
Snackbar.make(
|
view as ViewGroup,
|
||||||
view,
|
Snackbar.LENGTH_LONG
|
||||||
getString(R.string.bookmark_created_snackbar),
|
)
|
||||||
Snackbar.LENGTH_LONG
|
.setAction(getString(R.string.edit_bookmark_snackbar_action)) {
|
||||||
)
|
Navigation.findNavController(requireActivity(), R.id.container)
|
||||||
.setAction(getString(R.string.edit_bookmark_snackbar_action)) {
|
.navigate(
|
||||||
ItsNotBrokenSnack(
|
BrowserFragmentDirections
|
||||||
context!!
|
.actionBrowserFragmentToBookmarkEditFragment(
|
||||||
).showSnackbar(issueNumber = "90")
|
guid
|
||||||
}
|
)
|
||||||
.show()
|
)
|
||||||
}
|
}
|
||||||
|
.setText(getString(R.string.bookmark_created_snackbar))
|
||||||
|
}!!.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* 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.ext
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.TypedValue
|
||||||
|
|
||||||
|
fun Int.getColorFromAttr(context: Context): Int {
|
||||||
|
val typedValue = TypedValue()
|
||||||
|
val typedArray = context.obtainStyledAttributes(typedValue.data, intArrayOf(this))
|
||||||
|
val color = typedArray.getColor(0, 0)
|
||||||
|
typedArray.recycle()
|
||||||
|
return color
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import mozilla.appservices.places.BookmarkRoot
|
||||||
import mozilla.components.browser.icons.BrowserIcons
|
import mozilla.components.browser.icons.BrowserIcons
|
||||||
import mozilla.components.browser.icons.IconRequest
|
import mozilla.components.browser.icons.IconRequest
|
||||||
import mozilla.components.browser.menu.BrowserMenu
|
import mozilla.components.browser.menu.BrowserMenu
|
||||||
|
@ -22,17 +23,24 @@ import mozilla.components.concept.storage.BookmarkNode
|
||||||
import mozilla.components.concept.storage.BookmarkNodeType
|
import mozilla.components.concept.storage.BookmarkNodeType
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
|
import org.mozilla.fenix.ext.increaseTapArea
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class BookmarkAdapter(val actionEmitter: Observer<BookmarkAction>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
class BookmarkAdapter(val emptyView: View, val actionEmitter: Observer<BookmarkAction>) :
|
||||||
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
private var tree: List<BookmarkNode> = listOf()
|
private var tree: List<BookmarkNode> = listOf()
|
||||||
private var mode: BookmarkState.Mode = BookmarkState.Mode.Normal
|
private var mode: BookmarkState.Mode = BookmarkState.Mode.Normal
|
||||||
|
private var isFirstRun = true
|
||||||
|
|
||||||
lateinit var job: Job
|
lateinit var job: Job
|
||||||
|
|
||||||
fun updateData(tree: BookmarkNode?, mode: BookmarkState.Mode) {
|
fun updateData(tree: BookmarkNode?, mode: BookmarkState.Mode) {
|
||||||
this.tree = tree?.children?.filterNotNull() ?: listOf()
|
this.tree = tree?.children?.filterNotNull() ?: listOf()
|
||||||
|
isFirstRun = if (isFirstRun) false else {
|
||||||
|
emptyView.visibility = if (this.tree.isEmpty()) View.VISIBLE else View.GONE
|
||||||
|
false
|
||||||
|
}
|
||||||
this.mode = mode
|
this.mode = mode
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
@ -78,36 +86,10 @@ class BookmarkAdapter(val actionEmitter: Observer<BookmarkAction>) : RecyclerVie
|
||||||
@SuppressWarnings("ComplexMethod")
|
@SuppressWarnings("ComplexMethod")
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
|
||||||
val bookmarkItemMenu = BookmarkItemMenu(holder.itemView.context) {
|
|
||||||
when (it) {
|
|
||||||
is BookmarkItemMenu.Item.Edit -> {
|
|
||||||
actionEmitter.onNext(BookmarkAction.Edit(tree[position]))
|
|
||||||
}
|
|
||||||
is BookmarkItemMenu.Item.Select -> {
|
|
||||||
actionEmitter.onNext(BookmarkAction.Select(tree[position]))
|
|
||||||
}
|
|
||||||
is BookmarkItemMenu.Item.Copy -> {
|
|
||||||
actionEmitter.onNext(BookmarkAction.Copy(tree[position]))
|
|
||||||
}
|
|
||||||
is BookmarkItemMenu.Item.Share -> {
|
|
||||||
actionEmitter.onNext(BookmarkAction.Share(tree[position]))
|
|
||||||
}
|
|
||||||
is BookmarkItemMenu.Item.OpenInNewTab -> {
|
|
||||||
actionEmitter.onNext(BookmarkAction.OpenInNewTab(tree[position]))
|
|
||||||
}
|
|
||||||
is BookmarkItemMenu.Item.OpenInPrivateTab -> {
|
|
||||||
actionEmitter.onNext(BookmarkAction.OpenInPrivateTab(tree[position]))
|
|
||||||
}
|
|
||||||
is BookmarkItemMenu.Item.Delete -> {
|
|
||||||
actionEmitter.onNext(BookmarkAction.Delete(tree[position]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
when (holder) {
|
when (holder) {
|
||||||
is BookmarkAdapter.BookmarkItemViewHolder -> holder.bind(tree[position], bookmarkItemMenu, mode)
|
is BookmarkAdapter.BookmarkItemViewHolder -> holder.bind(tree[position], mode)
|
||||||
is BookmarkAdapter.BookmarkFolderViewHolder -> holder.bind(tree[position], bookmarkItemMenu, mode)
|
is BookmarkAdapter.BookmarkFolderViewHolder -> holder.bind(tree[position], mode)
|
||||||
is BookmarkAdapter.BookmarkSeparatorViewHolder -> holder.bind(bookmarkItemMenu)
|
is BookmarkAdapter.BookmarkSeparatorViewHolder -> holder.bind(tree[position])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,12 +115,39 @@ class BookmarkAdapter(val actionEmitter: Observer<BookmarkAction>) : RecyclerVie
|
||||||
bookmark_layout.isClickable = true
|
bookmark_layout.isClickable = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bind(item: BookmarkNode, bookmarkItemMenu: BookmarkItemMenu, mode: BookmarkState.Mode) {
|
fun bind(item: BookmarkNode, mode: BookmarkState.Mode) {
|
||||||
this.item = item
|
this.item = item
|
||||||
this.mode = mode
|
this.mode = mode
|
||||||
|
|
||||||
|
val bookmarkItemMenu = BookmarkItemMenu(containerView!!.context, item) {
|
||||||
|
when (it) {
|
||||||
|
is BookmarkItemMenu.Item.Edit -> {
|
||||||
|
actionEmitter.onNext(BookmarkAction.Edit(item))
|
||||||
|
}
|
||||||
|
is BookmarkItemMenu.Item.Select -> {
|
||||||
|
actionEmitter.onNext(BookmarkAction.Select(item))
|
||||||
|
}
|
||||||
|
is BookmarkItemMenu.Item.Copy -> {
|
||||||
|
actionEmitter.onNext(BookmarkAction.Copy(item))
|
||||||
|
}
|
||||||
|
is BookmarkItemMenu.Item.Share -> {
|
||||||
|
actionEmitter.onNext(BookmarkAction.Share(item))
|
||||||
|
}
|
||||||
|
is BookmarkItemMenu.Item.OpenInNewTab -> {
|
||||||
|
actionEmitter.onNext(BookmarkAction.OpenInNewTab(item))
|
||||||
|
}
|
||||||
|
is BookmarkItemMenu.Item.OpenInPrivateTab -> {
|
||||||
|
actionEmitter.onNext(BookmarkAction.OpenInPrivateTab(item))
|
||||||
|
}
|
||||||
|
is BookmarkItemMenu.Item.Delete -> {
|
||||||
|
actionEmitter.onNext(BookmarkAction.Delete(item))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmark_overflow.increaseTapArea(bookmarkOverflowExtraDips)
|
||||||
bookmark_overflow.setOnClickListener {
|
bookmark_overflow.setOnClickListener {
|
||||||
bookmarkItemMenu.menuBuilder.build(containerView!!.context).show(
|
bookmarkItemMenu.menuBuilder.build(containerView.context).show(
|
||||||
anchor = it,
|
anchor = it,
|
||||||
orientation = BrowserMenu.Orientation.DOWN
|
orientation = BrowserMenu.Orientation.DOWN
|
||||||
)
|
)
|
||||||
|
@ -195,12 +204,34 @@ class BookmarkAdapter(val actionEmitter: Observer<BookmarkAction>) : RecyclerVie
|
||||||
bookmark_layout.isClickable = true
|
bookmark_layout.isClickable = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bind(folder: BookmarkNode, bookmarkItemMenu: BookmarkItemMenu, mode: BookmarkState.Mode) {
|
fun bind(folder: BookmarkNode, mode: BookmarkState.Mode) {
|
||||||
bookmark_overflow.setOnClickListener {
|
val bookmarkItemMenu = BookmarkItemMenu(containerView!!.context, folder) {
|
||||||
bookmarkItemMenu.menuBuilder.build(containerView!!.context).show(
|
when (it) {
|
||||||
anchor = it,
|
is BookmarkItemMenu.Item.Edit -> {
|
||||||
orientation = BrowserMenu.Orientation.DOWN
|
actionEmitter.onNext(BookmarkAction.Edit(folder))
|
||||||
)
|
}
|
||||||
|
is BookmarkItemMenu.Item.Select -> {
|
||||||
|
actionEmitter.onNext(BookmarkAction.Select(folder))
|
||||||
|
}
|
||||||
|
is BookmarkItemMenu.Item.Copy -> {
|
||||||
|
actionEmitter.onNext(BookmarkAction.Copy(folder))
|
||||||
|
}
|
||||||
|
is BookmarkItemMenu.Item.Delete -> {
|
||||||
|
actionEmitter.onNext(BookmarkAction.Delete(folder))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enumValues<BookmarkRoot>().all { it.id != folder.guid }) {
|
||||||
|
bookmark_overflow.increaseTapArea(bookmarkOverflowExtraDips)
|
||||||
|
bookmark_overflow.setOnClickListener {
|
||||||
|
bookmarkItemMenu.menuBuilder.build(containerView.context).show(
|
||||||
|
anchor = it,
|
||||||
|
orientation = BrowserMenu.Orientation.DOWN
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bookmark_overflow.visibility = View.GONE
|
||||||
}
|
}
|
||||||
bookmark_title?.text = folder.title
|
bookmark_title?.text = folder.title
|
||||||
bookmark_layout.setOnClickListener {
|
bookmark_layout.setOnClickListener {
|
||||||
|
@ -222,14 +253,23 @@ class BookmarkAdapter(val actionEmitter: Observer<BookmarkAction>) : RecyclerVie
|
||||||
init {
|
init {
|
||||||
bookmark_favicon.visibility = View.GONE
|
bookmark_favicon.visibility = View.GONE
|
||||||
bookmark_title.visibility = View.GONE
|
bookmark_title.visibility = View.GONE
|
||||||
|
bookmark_overflow.increaseTapArea(bookmarkOverflowExtraDips)
|
||||||
bookmark_overflow.visibility = View.VISIBLE
|
bookmark_overflow.visibility = View.VISIBLE
|
||||||
bookmark_separator.visibility = View.VISIBLE
|
bookmark_separator.visibility = View.VISIBLE
|
||||||
bookmark_layout.isClickable = false
|
bookmark_layout.isClickable = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bind(bookmarkItemMenu: BookmarkItemMenu) {
|
fun bind(separator: BookmarkNode) {
|
||||||
|
val bookmarkItemMenu = BookmarkItemMenu(containerView!!.context, separator) {
|
||||||
|
when (it) {
|
||||||
|
is BookmarkItemMenu.Item.Delete -> {
|
||||||
|
actionEmitter.onNext(BookmarkAction.Delete(separator))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bookmark_overflow.setOnClickListener {
|
bookmark_overflow.setOnClickListener {
|
||||||
bookmarkItemMenu.menuBuilder.build(containerView!!.context).show(
|
bookmarkItemMenu.menuBuilder.build(containerView.context).show(
|
||||||
anchor = it,
|
anchor = it,
|
||||||
orientation = BrowserMenu.Orientation.DOWN
|
orientation = BrowserMenu.Orientation.DOWN
|
||||||
)
|
)
|
||||||
|
@ -241,6 +281,10 @@ class BookmarkAdapter(val actionEmitter: Observer<BookmarkAction>) : RecyclerVie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val bookmarkOverflowExtraDips = 8
|
||||||
|
}
|
||||||
|
|
||||||
enum class ViewType {
|
enum class ViewType {
|
||||||
ITEM, FOLDER, SEPARATOR
|
ITEM, FOLDER, SEPARATOR
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,9 @@ import kotlinx.coroutines.launch
|
||||||
import mozilla.appservices.places.BookmarkRoot
|
import mozilla.appservices.places.BookmarkRoot
|
||||||
import mozilla.components.concept.storage.BookmarkNode
|
import mozilla.components.concept.storage.BookmarkNode
|
||||||
import mozilla.components.concept.storage.BookmarkNodeType
|
import mozilla.components.concept.storage.BookmarkNodeType
|
||||||
|
import mozilla.components.concept.sync.AccountObserver
|
||||||
|
import mozilla.components.concept.sync.OAuthAccount
|
||||||
|
import mozilla.components.concept.sync.Profile
|
||||||
import mozilla.components.support.base.feature.BackHandler
|
import mozilla.components.support.base.feature.BackHandler
|
||||||
import org.mozilla.fenix.BrowserDirection
|
import org.mozilla.fenix.BrowserDirection
|
||||||
import org.mozilla.fenix.BrowsingModeManager
|
import org.mozilla.fenix.BrowsingModeManager
|
||||||
|
@ -37,10 +40,12 @@ import org.mozilla.fenix.mvi.getManagedEmitter
|
||||||
import org.mozilla.fenix.utils.ItsNotBrokenSnack
|
import org.mozilla.fenix.utils.ItsNotBrokenSnack
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class BookmarkFragment : Fragment(), CoroutineScope, BackHandler {
|
@SuppressWarnings("TooManyFunctions")
|
||||||
|
class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserver {
|
||||||
|
|
||||||
private lateinit var job: Job
|
private lateinit var job: Job
|
||||||
private lateinit var bookmarkComponent: BookmarkComponent
|
private lateinit var bookmarkComponent: BookmarkComponent
|
||||||
|
private lateinit var signInComponent: SignInComponent
|
||||||
private lateinit var currentRoot: BookmarkNode
|
private lateinit var currentRoot: BookmarkNode
|
||||||
|
|
||||||
override val coroutineContext: CoroutineContext
|
override val coroutineContext: CoroutineContext
|
||||||
|
@ -49,6 +54,7 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler {
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
val view = inflater.inflate(R.layout.fragment_bookmark, container, false)
|
val view = inflater.inflate(R.layout.fragment_bookmark, container, false)
|
||||||
bookmarkComponent = BookmarkComponent(view.bookmark_layout, ActionBusFactory.get(this))
|
bookmarkComponent = BookmarkComponent(view.bookmark_layout, ActionBusFactory.get(this))
|
||||||
|
signInComponent = SignInComponent(view.bookmark_layout, ActionBusFactory.get(this))
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,6 +67,14 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler {
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
(activity as AppCompatActivity).supportActionBar?.show()
|
(activity as AppCompatActivity).supportActionBar?.show()
|
||||||
|
checkIfSignedIn()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkIfSignedIn() {
|
||||||
|
val accountManager = requireComponents.backgroundServices.accountManager
|
||||||
|
accountManager.register(this, owner = this)
|
||||||
|
accountManager.authenticatedAccount()?.let { getManagedEmitter<SignInChange>().onNext(SignInChange.SignedIn) }
|
||||||
|
?: getManagedEmitter<SignInChange>().onNext(SignInChange.SignedOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
@ -94,7 +108,11 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler {
|
||||||
Navigation.findNavController(requireActivity(), R.id.container).popBackStack()
|
Navigation.findNavController(requireActivity(), R.id.container).popBackStack()
|
||||||
}
|
}
|
||||||
is BookmarkAction.Edit -> {
|
is BookmarkAction.Edit -> {
|
||||||
ItsNotBrokenSnack(context!!).showSnackbar(issueNumber = "1238")
|
Navigation.findNavController(requireActivity(), R.id.container)
|
||||||
|
.navigate(
|
||||||
|
BookmarkFragmentDirections
|
||||||
|
.actionBookmarkFragmentToBookmarkEditFragment(it.item.guid)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is BookmarkAction.Select -> {
|
is BookmarkAction.Select -> {
|
||||||
ItsNotBrokenSnack(context!!).showSnackbar(issueNumber = "1239")
|
ItsNotBrokenSnack(context!!).showSnackbar(issueNumber = "1239")
|
||||||
|
@ -131,6 +149,16 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getAutoDisposeObservable<SignInAction>()
|
||||||
|
.subscribe {
|
||||||
|
when (it) {
|
||||||
|
is SignInAction.ClickedSignIn -> {
|
||||||
|
requireComponents.services.accountsAuthFeature.beginAuthentication()
|
||||||
|
(activity as HomeActivity).openToBrowser(null, from = BrowserDirection.FromBookmarks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
@ -157,10 +185,25 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler {
|
||||||
currentRoot = requireComponents.core.bookmarksStorage.getTree(currentGuid) as BookmarkNode
|
currentRoot = requireComponents.core.bookmarksStorage.getTree(currentGuid) as BookmarkNode
|
||||||
|
|
||||||
launch(Main) {
|
launch(Main) {
|
||||||
|
if (currentGuid != BookmarkRoot.Root.id) (activity as HomeActivity).title = currentRoot.title
|
||||||
getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.Change(currentRoot))
|
getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.Change(currentRoot))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBackPressed(): Boolean = (bookmarkComponent.uiView as BookmarkUIView).onBackPressed()
|
override fun onBackPressed(): Boolean = (bookmarkComponent.uiView as BookmarkUIView).onBackPressed()
|
||||||
|
|
||||||
|
override fun onAuthenticated(account: OAuthAccount) {
|
||||||
|
getManagedEmitter<SignInChange>().onNext(SignInChange.SignedIn)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(error: Exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLoggedOut() {
|
||||||
|
getManagedEmitter<SignInChange>().onNext(SignInChange.SignedOut)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onProfileUpdated(profile: Profile) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,14 @@ package org.mozilla.fenix.library.bookmarks
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import mozilla.components.browser.menu.BrowserMenuBuilder
|
import mozilla.components.browser.menu.BrowserMenuBuilder
|
||||||
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
|
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
|
||||||
|
import mozilla.components.concept.storage.BookmarkNode
|
||||||
|
import mozilla.components.concept.storage.BookmarkNodeType
|
||||||
import org.mozilla.fenix.DefaultThemeManager
|
import org.mozilla.fenix.DefaultThemeManager
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
class BookmarkItemMenu(
|
class BookmarkItemMenu(
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
|
private val item: BookmarkNode,
|
||||||
private val onItemTapped: (BookmarkItemMenu.Item) -> Unit = {}
|
private val onItemTapped: (BookmarkItemMenu.Item) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -29,24 +32,36 @@ class BookmarkItemMenu(
|
||||||
|
|
||||||
private val menuItems by lazy {
|
private val menuItems by lazy {
|
||||||
listOf(
|
listOf(
|
||||||
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_edit_button)) {
|
if (item.type in listOf(BookmarkNodeType.ITEM, BookmarkNodeType.FOLDER)) {
|
||||||
onItemTapped.invoke(BookmarkItemMenu.Item.Edit)
|
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_edit_button)) {
|
||||||
},
|
onItemTapped.invoke(BookmarkItemMenu.Item.Edit)
|
||||||
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_select_button)) {
|
}
|
||||||
onItemTapped.invoke(BookmarkItemMenu.Item.Select)
|
} else null,
|
||||||
},
|
if (item.type in listOf(BookmarkNodeType.ITEM, BookmarkNodeType.FOLDER)) {
|
||||||
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_copy_button)) {
|
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_select_button)) {
|
||||||
onItemTapped.invoke(BookmarkItemMenu.Item.Copy)
|
onItemTapped.invoke(BookmarkItemMenu.Item.Select)
|
||||||
},
|
}
|
||||||
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_share_button)) {
|
} else null,
|
||||||
onItemTapped.invoke(BookmarkItemMenu.Item.Share)
|
if (item.type in listOf(BookmarkNodeType.ITEM, BookmarkNodeType.FOLDER)) {
|
||||||
},
|
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_copy_button)) {
|
||||||
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_open_in_new_tab_button)) {
|
onItemTapped.invoke(BookmarkItemMenu.Item.Copy)
|
||||||
onItemTapped.invoke(BookmarkItemMenu.Item.OpenInNewTab)
|
}
|
||||||
},
|
} else null,
|
||||||
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_open_in_private_tab_button)) {
|
if (item.type == BookmarkNodeType.ITEM) {
|
||||||
onItemTapped.invoke(BookmarkItemMenu.Item.OpenInPrivateTab)
|
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_share_button)) {
|
||||||
},
|
onItemTapped.invoke(BookmarkItemMenu.Item.Share)
|
||||||
|
}
|
||||||
|
} else null,
|
||||||
|
if (item.type == BookmarkNodeType.ITEM) {
|
||||||
|
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_open_in_new_tab_button)) {
|
||||||
|
onItemTapped.invoke(BookmarkItemMenu.Item.OpenInNewTab)
|
||||||
|
}
|
||||||
|
} else null,
|
||||||
|
if (item.type == BookmarkNodeType.ITEM) {
|
||||||
|
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_open_in_private_tab_button)) {
|
||||||
|
onItemTapped.invoke(BookmarkItemMenu.Item.OpenInPrivateTab)
|
||||||
|
}
|
||||||
|
} else null,
|
||||||
SimpleBrowserMenuItem(
|
SimpleBrowserMenuItem(
|
||||||
context.getString(R.string.bookmark_menu_delete_button),
|
context.getString(R.string.bookmark_menu_delete_button),
|
||||||
textColorResource = DefaultThemeManager.resolveAttribute(
|
textColorResource = DefaultThemeManager.resolveAttribute(
|
||||||
|
@ -56,6 +71,6 @@ class BookmarkItemMenu(
|
||||||
) {
|
) {
|
||||||
onItemTapped.invoke(BookmarkItemMenu.Item.Delete)
|
onItemTapped.invoke(BookmarkItemMenu.Item.Delete)
|
||||||
}
|
}
|
||||||
)
|
).filterNotNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,11 @@ package org.mozilla.fenix.library.bookmarks
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import android.widget.LinearLayout
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.Observer
|
import io.reactivex.Observer
|
||||||
import io.reactivex.functions.Consumer
|
import io.reactivex.functions.Consumer
|
||||||
|
import kotlinx.android.synthetic.main.component_bookmark.view.*
|
||||||
import mozilla.appservices.places.BookmarkRoot
|
import mozilla.appservices.places.BookmarkRoot
|
||||||
import mozilla.components.support.base.feature.BackHandler
|
import mozilla.components.support.base.feature.BackHandler
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
@ -29,16 +29,15 @@ class BookmarkUIView(
|
||||||
|
|
||||||
var canGoBack = false
|
var canGoBack = false
|
||||||
|
|
||||||
override val view: RecyclerView = LayoutInflater.from(container.context)
|
override val view: LinearLayout = LayoutInflater.from(container.context)
|
||||||
.inflate(R.layout.component_bookmark, container, true)
|
.inflate(R.layout.component_bookmark, container, true) as LinearLayout
|
||||||
.findViewById(R.id.bookmark_list)
|
|
||||||
|
|
||||||
private val bookmarkAdapter = BookmarkAdapter(actionEmitter)
|
private val bookmarkAdapter: BookmarkAdapter
|
||||||
|
|
||||||
init {
|
init {
|
||||||
view.apply {
|
view.bookmark_list.apply {
|
||||||
|
bookmarkAdapter = BookmarkAdapter(view.bookmarks_empty_view, actionEmitter)
|
||||||
adapter = bookmarkAdapter
|
adapter = bookmarkAdapter
|
||||||
layoutManager = LinearLayoutManager(container.context)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* 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.library.bookmarks
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import mozilla.components.concept.storage.BookmarkNode
|
||||||
|
|
||||||
|
class BookmarksSharedViewModel : ViewModel() {
|
||||||
|
var selectedFolder: BookmarkNode? = null
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/* 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.library.bookmarks
|
||||||
|
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import org.mozilla.fenix.mvi.Action
|
||||||
|
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||||
|
import org.mozilla.fenix.mvi.Change
|
||||||
|
import org.mozilla.fenix.mvi.Reducer
|
||||||
|
import org.mozilla.fenix.mvi.UIComponent
|
||||||
|
import org.mozilla.fenix.mvi.UIView
|
||||||
|
import org.mozilla.fenix.mvi.ViewState
|
||||||
|
|
||||||
|
class SignInComponent(
|
||||||
|
private val container: ViewGroup,
|
||||||
|
bus: ActionBusFactory,
|
||||||
|
override var initialState: SignInState =
|
||||||
|
SignInState(false)
|
||||||
|
) : UIComponent<SignInState, SignInAction, SignInChange>(
|
||||||
|
bus.getManagedEmitter(SignInAction::class.java),
|
||||||
|
bus.getSafeManagedObservable(SignInChange::class.java)
|
||||||
|
) {
|
||||||
|
|
||||||
|
override val reducer: Reducer<SignInState, SignInChange> = { state, change ->
|
||||||
|
when (change) {
|
||||||
|
SignInChange.SignedIn -> state.copy(signedIn = true)
|
||||||
|
SignInChange.SignedOut -> state.copy(signedIn = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun initView(): UIView<SignInState, SignInAction, SignInChange> =
|
||||||
|
SignInUIView(container, actionEmitter, changesObservable)
|
||||||
|
|
||||||
|
init {
|
||||||
|
render(reducer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class SignInState(val signedIn: Boolean) : ViewState
|
||||||
|
|
||||||
|
sealed class SignInAction : Action {
|
||||||
|
object ClickedSignIn : SignInAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class SignInChange : Change {
|
||||||
|
object SignedIn : SignInChange()
|
||||||
|
object SignedOut : SignInChange()
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* 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.library.bookmarks
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Button
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.Observer
|
||||||
|
import io.reactivex.functions.Consumer
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.mvi.UIView
|
||||||
|
|
||||||
|
class SignInUIView(
|
||||||
|
container: ViewGroup,
|
||||||
|
actionEmitter: Observer<SignInAction>,
|
||||||
|
changesObservable: Observable<SignInChange>
|
||||||
|
) : UIView<SignInState, SignInAction, SignInChange>(container, actionEmitter, changesObservable) {
|
||||||
|
|
||||||
|
override val view: Button = LayoutInflater.from(container.context)
|
||||||
|
.inflate(R.layout.component_sign_in, container, true)
|
||||||
|
.findViewById(R.id.bookmark_folders_sign_in)
|
||||||
|
|
||||||
|
init {
|
||||||
|
view.setOnClickListener {
|
||||||
|
actionEmitter.onNext(SignInAction.ClickedSignIn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateView() = Consumer<SignInState> {
|
||||||
|
view.visibility = if (it.signedIn) View.GONE else View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,104 @@
|
||||||
|
/* 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.library.bookmarks.addfolder
|
||||||
|
|
||||||
|
import android.graphics.PorterDuff
|
||||||
|
import android.graphics.PorterDuffColorFilter
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.ViewModelProviders
|
||||||
|
import androidx.navigation.Navigation
|
||||||
|
import kotlinx.android.synthetic.main.fragment_add_bookmark_folder.*
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import mozilla.appservices.places.BookmarkRoot
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.ext.getColorFromAttr
|
||||||
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
|
import org.mozilla.fenix.library.bookmarks.BookmarksSharedViewModel
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
class AddBookmarkFolderFragment : Fragment(), CoroutineScope {
|
||||||
|
|
||||||
|
private lateinit var sharedViewModel: BookmarksSharedViewModel
|
||||||
|
private lateinit var job: Job
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = Dispatchers.Main + job
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
job = Job()
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
sharedViewModel = activity?.run {
|
||||||
|
ViewModelProviders.of(this).get(BookmarksSharedViewModel::class.java)
|
||||||
|
}!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
return inflater.inflate(R.layout.fragment_add_bookmark_folder, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
(activity as AppCompatActivity).supportActionBar?.show()
|
||||||
|
|
||||||
|
launch(IO) {
|
||||||
|
sharedViewModel.selectedFolder = sharedViewModel.selectedFolder
|
||||||
|
?: requireComponents.core.bookmarksStorage.getTree(BookmarkRoot.Mobile.id)
|
||||||
|
bookmark_add_folder_parent_selector.text = sharedViewModel.selectedFolder!!.title
|
||||||
|
bookmark_add_folder_parent_selector.setOnClickListener {
|
||||||
|
Navigation.findNavController(requireActivity(), R.id.container)
|
||||||
|
.navigate(
|
||||||
|
AddBookmarkFolderFragmentDirections
|
||||||
|
.actionBookmarkAddFolderFragmentToBookmarkSelectFolderFragment(BookmarkRoot.Root.id, true)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
inflater.inflate(R.menu.bookmarks_add_folder, menu)
|
||||||
|
menu.findItem(R.id.confirm_add_folder_button).icon.colorFilter =
|
||||||
|
PorterDuffColorFilter(R.attr.iconColor.getColorFromAttr(context!!), PorterDuff.Mode.SRC_IN)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
return when (item.itemId) {
|
||||||
|
R.id.confirm_add_folder_button -> {
|
||||||
|
if (bookmark_add_folder_title_edit.text.isEmpty()) {
|
||||||
|
bookmark_add_folder_title_edit.error = getString(R.string.bookmark_empty_title_error)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
launch(IO) {
|
||||||
|
requireComponents.core.bookmarksStorage.addFolder(
|
||||||
|
sharedViewModel.selectedFolder!!.guid, bookmark_add_folder_title_edit.text.toString(), null
|
||||||
|
)
|
||||||
|
launch(Main) {
|
||||||
|
Navigation.findNavController(requireActivity(), R.id.container).popBackStack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,181 @@
|
||||||
|
/* 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.library.bookmarks.edit
|
||||||
|
|
||||||
|
import android.graphics.PorterDuff
|
||||||
|
import android.graphics.PorterDuffColorFilter
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.ViewModelProviders
|
||||||
|
import androidx.navigation.Navigation
|
||||||
|
import com.jakewharton.rxbinding3.widget.textChanges
|
||||||
|
import com.uber.autodispose.AutoDispose
|
||||||
|
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.functions.BiFunction
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import kotlinx.android.synthetic.main.fragment_edit_bookmark.*
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import mozilla.appservices.places.UrlParseFailed
|
||||||
|
import mozilla.components.concept.storage.BookmarkInfo
|
||||||
|
import mozilla.components.concept.storage.BookmarkNode
|
||||||
|
import mozilla.components.concept.storage.BookmarkNodeType
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.ext.getColorFromAttr
|
||||||
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
|
import org.mozilla.fenix.library.bookmarks.BookmarksSharedViewModel
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
class EditBookmarkFragment : Fragment(), CoroutineScope {
|
||||||
|
|
||||||
|
private lateinit var sharedViewModel: BookmarksSharedViewModel
|
||||||
|
private lateinit var job: Job
|
||||||
|
private lateinit var guidToEdit: String
|
||||||
|
private var bookmarkNode: BookmarkNode? = null
|
||||||
|
private var bookmarkParent: BookmarkNode? = null
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = Dispatchers.Main + job
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
job = Job()
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
sharedViewModel = activity?.run {
|
||||||
|
ViewModelProviders.of(this).get(BookmarksSharedViewModel::class.java)
|
||||||
|
}!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
return inflater.inflate(R.layout.fragment_edit_bookmark, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
(activity as? AppCompatActivity)?.supportActionBar?.show()
|
||||||
|
|
||||||
|
guidToEdit = EditBookmarkFragmentArgs.fromBundle(arguments!!).guidToEdit
|
||||||
|
launch(IO) {
|
||||||
|
bookmarkNode = requireComponents.core.bookmarksStorage.getTree(guidToEdit)
|
||||||
|
bookmarkParent = sharedViewModel.selectedFolder
|
||||||
|
?: bookmarkNode?.parentGuid?.let { requireComponents.core.bookmarksStorage.getTree(it) }
|
||||||
|
|
||||||
|
launch(Main) {
|
||||||
|
when (bookmarkNode?.type) {
|
||||||
|
BookmarkNodeType.FOLDER -> {
|
||||||
|
bookmark_url_edit.visibility = View.GONE
|
||||||
|
bookmark_url_label.visibility = View.GONE
|
||||||
|
}
|
||||||
|
BookmarkNodeType.ITEM -> {}
|
||||||
|
BookmarkNodeType.SEPARATOR -> {}
|
||||||
|
else -> throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
bookmark_name_edit.setText(bookmarkNode!!.title)
|
||||||
|
bookmark_url_edit.setText(bookmarkNode!!.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmarkParent?.let { node ->
|
||||||
|
launch(Main) {
|
||||||
|
bookmark_folder_selector.text = node.title
|
||||||
|
bookmark_folder_selector.setOnClickListener {
|
||||||
|
sharedViewModel.selectedFolder = null
|
||||||
|
Navigation.findNavController(requireActivity(), R.id.container).navigate(
|
||||||
|
EditBookmarkFragmentDirections
|
||||||
|
.actionBookmarkEditFragmentToBookmarkSelectFolderFragment(null)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateBookmarkFromObservableInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
updateBookmarkNode(Pair(bookmark_name_edit.text, bookmark_url_edit.text))
|
||||||
|
super.onPause()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateBookmarkFromObservableInput() {
|
||||||
|
Observable.combineLatest(
|
||||||
|
bookmark_name_edit.textChanges().skipInitialValue(),
|
||||||
|
bookmark_url_edit.textChanges().skipInitialValue(),
|
||||||
|
BiFunction { name: CharSequence, url: CharSequence ->
|
||||||
|
Pair(name, url)
|
||||||
|
})
|
||||||
|
.filter { it.first.isNotBlank() && it.second.isNotBlank() }
|
||||||
|
.debounce(debouncePeriodInMs, TimeUnit.MILLISECONDS)
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.`as`(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(this@EditBookmarkFragment)))
|
||||||
|
.subscribe {
|
||||||
|
try {
|
||||||
|
bookmark_url_edit.error = null
|
||||||
|
updateBookmarkNode(it)
|
||||||
|
} catch (e: UrlParseFailed) {
|
||||||
|
bookmark_url_edit.error = getString(R.string.bookmark_invalid_url_error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
inflater.inflate(R.menu.bookmarks_edit, menu)
|
||||||
|
menu.findItem(R.id.delete_bookmark_button).icon.colorFilter =
|
||||||
|
PorterDuffColorFilter(R.attr.iconColor.getColorFromAttr(context!!), PorterDuff.Mode.SRC_IN)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
return when (item.itemId) {
|
||||||
|
R.id.delete_bookmark_button -> {
|
||||||
|
launch(IO) {
|
||||||
|
requireComponents.core.bookmarksStorage.deleteNode(guidToEdit)
|
||||||
|
launch(Main) {
|
||||||
|
Navigation.findNavController(requireActivity(), R.id.container).popBackStack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateBookmarkNode(pair: Pair<CharSequence, CharSequence>) {
|
||||||
|
launch(IO) {
|
||||||
|
requireComponents.core.bookmarksStorage.updateNode(
|
||||||
|
guidToEdit,
|
||||||
|
BookmarkInfo(
|
||||||
|
sharedViewModel.selectedFolder?.guid ?: bookmarkNode!!.parentGuid,
|
||||||
|
bookmarkNode!!.position,
|
||||||
|
pair.first.toString(),
|
||||||
|
if (bookmarkNode?.type == BookmarkNodeType.ITEM) pair.second.toString() else null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val debouncePeriodInMs = 500L
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
/* 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.library.bookmarks.selectfolder
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.bookmark_row.*
|
||||||
|
import mozilla.components.concept.storage.BookmarkNode
|
||||||
|
import mozilla.components.concept.storage.BookmarkNodeType
|
||||||
|
import mozilla.components.support.ktx.android.content.res.pxToDp
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.library.bookmarks.BookmarksSharedViewModel
|
||||||
|
|
||||||
|
class SelectBookmarkFolderAdapter(private val sharedViewModel: BookmarksSharedViewModel) :
|
||||||
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
|
private var tree: List<BookmarkNodeWithDepth> = listOf()
|
||||||
|
|
||||||
|
fun updateData(tree: BookmarkNode?) {
|
||||||
|
this.tree = tree!!.convertToFolderDepthTree().drop(1)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
|
val view = LayoutInflater.from(parent.context).inflate(R.layout.bookmark_row, parent, false)
|
||||||
|
|
||||||
|
return when (viewType) {
|
||||||
|
BookmarkFolderViewHolder.viewType -> SelectBookmarkFolderAdapter.BookmarkFolderViewHolder(
|
||||||
|
view
|
||||||
|
)
|
||||||
|
else -> throw IllegalStateException("ViewType $viewType does not match to a ViewHolder")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
return when (tree[position].node.type) {
|
||||||
|
BookmarkNodeType.FOLDER -> BookmarkFolderViewHolder.viewType
|
||||||
|
else -> throw IllegalStateException("Item $tree[position] does not match to a ViewType")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = tree.size
|
||||||
|
|
||||||
|
@SuppressWarnings("ComplexMethod")
|
||||||
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
|
||||||
|
when (holder) {
|
||||||
|
is SelectBookmarkFolderAdapter.BookmarkFolderViewHolder -> holder.bind(
|
||||||
|
tree[position],
|
||||||
|
tree[position].node == sharedViewModel.selectedFolder,
|
||||||
|
object : SelectionInterface {
|
||||||
|
override fun itemSelected(node: BookmarkNode) {
|
||||||
|
sharedViewModel.selectedFolder = node
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
else -> {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SelectionInterface {
|
||||||
|
fun itemSelected(node: BookmarkNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
class BookmarkFolderViewHolder(
|
||||||
|
view: View,
|
||||||
|
override val containerView: View? = view
|
||||||
|
) :
|
||||||
|
RecyclerView.ViewHolder(view), LayoutContainer {
|
||||||
|
|
||||||
|
init {
|
||||||
|
bookmark_favicon.visibility = View.VISIBLE
|
||||||
|
bookmark_title.visibility = View.VISIBLE
|
||||||
|
bookmark_separator.visibility = View.GONE
|
||||||
|
bookmark_layout.isClickable = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bind(folder: BookmarkNodeWithDepth, selected: Boolean, selectionInterface: SelectionInterface) {
|
||||||
|
val backgroundTint =
|
||||||
|
if (selected) R.color.bookmark_selection_appbar_background else R.color.bookmark_favicon_background
|
||||||
|
val backgroundTintList = ContextCompat.getColorStateList(containerView!!.context, backgroundTint)
|
||||||
|
bookmark_favicon.backgroundTintList = backgroundTintList
|
||||||
|
val res = if (selected) R.drawable.mozac_ic_check else R.drawable.ic_folder_icon
|
||||||
|
bookmark_favicon.setImageResource(res)
|
||||||
|
bookmark_overflow.visibility = View.GONE
|
||||||
|
bookmark_title?.text = folder.node.title
|
||||||
|
bookmark_layout.setOnClickListener {
|
||||||
|
selectionInterface.itemSelected(folder.node)
|
||||||
|
}
|
||||||
|
val padding =
|
||||||
|
containerView.resources.pxToDp(dpsToIndent) * (if (folder.depth > maxDepth) maxDepth else folder.depth)
|
||||||
|
bookmark_layout.setPadding(padding, 0, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val viewType = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class BookmarkNodeWithDepth(val depth: Int, val node: BookmarkNode, val parent: String?)
|
||||||
|
|
||||||
|
private fun BookmarkNode?.convertToFolderDepthTree(
|
||||||
|
depth: Int = 0,
|
||||||
|
list: List<BookmarkNodeWithDepth> = listOf()
|
||||||
|
): List<BookmarkNodeWithDepth> {
|
||||||
|
return if (this != null) {
|
||||||
|
val newList = list.plus(listOf(BookmarkNodeWithDepth(depth, this, this.parentGuid)))
|
||||||
|
newList.plus(
|
||||||
|
children?.filter { it?.type == BookmarkNodeType.FOLDER }
|
||||||
|
?.flatMap { it.convertToFolderDepthTree(depth + 1) }
|
||||||
|
?: listOf())
|
||||||
|
} else listOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val maxDepth = 10
|
||||||
|
private const val dpsToIndent = 10
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
/* 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.library.bookmarks.selectfolder
|
||||||
|
|
||||||
|
import android.graphics.PorterDuff
|
||||||
|
import android.graphics.PorterDuffColorFilter
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.lifecycle.ViewModelProviders
|
||||||
|
import androidx.navigation.Navigation
|
||||||
|
import kotlinx.android.synthetic.main.fragment_select_bookmark_folder.*
|
||||||
|
import kotlinx.android.synthetic.main.fragment_select_bookmark_folder.view.*
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import mozilla.appservices.places.BookmarkRoot
|
||||||
|
import mozilla.components.concept.storage.BookmarkNode
|
||||||
|
import mozilla.components.concept.sync.AccountObserver
|
||||||
|
import mozilla.components.concept.sync.OAuthAccount
|
||||||
|
import mozilla.components.concept.sync.Profile
|
||||||
|
import org.mozilla.fenix.BrowserDirection
|
||||||
|
import org.mozilla.fenix.HomeActivity
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.ext.getColorFromAttr
|
||||||
|
import org.mozilla.fenix.ext.requireComponents
|
||||||
|
import org.mozilla.fenix.library.bookmarks.BookmarksSharedViewModel
|
||||||
|
import org.mozilla.fenix.library.bookmarks.SignInAction
|
||||||
|
import org.mozilla.fenix.library.bookmarks.SignInChange
|
||||||
|
import org.mozilla.fenix.library.bookmarks.SignInComponent
|
||||||
|
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||||
|
import org.mozilla.fenix.mvi.getAutoDisposeObservable
|
||||||
|
import org.mozilla.fenix.mvi.getManagedEmitter
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
@SuppressWarnings("TooManyFunctions")
|
||||||
|
class SelectBookmarkFolderFragment : Fragment(), CoroutineScope, AccountObserver {
|
||||||
|
|
||||||
|
private lateinit var sharedViewModel: BookmarksSharedViewModel
|
||||||
|
private lateinit var job: Job
|
||||||
|
private var folderGuid: String? = null
|
||||||
|
private var bookmarkNode: BookmarkNode? = null
|
||||||
|
|
||||||
|
private lateinit var signInComponent: SignInComponent
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = Dispatchers.Main + job
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
job = Job()
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
sharedViewModel = activity?.run {
|
||||||
|
ViewModelProviders.of(this).get(BookmarksSharedViewModel::class.java)
|
||||||
|
}!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
|
val view = inflater.inflate(R.layout.fragment_select_bookmark_folder, container, false)
|
||||||
|
signInComponent = SignInComponent(view.select_bookmark_layout, ActionBusFactory.get(this))
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
getAutoDisposeObservable<SignInAction>()
|
||||||
|
.subscribe {
|
||||||
|
when (it) {
|
||||||
|
is SignInAction.ClickedSignIn -> {
|
||||||
|
requireComponents.services.accountsAuthFeature.beginAuthentication()
|
||||||
|
view?.let {
|
||||||
|
(activity as HomeActivity).openToBrowser(null, BrowserDirection.FromBookmarksFolderSelect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
(activity as AppCompatActivity).supportActionBar?.show()
|
||||||
|
|
||||||
|
folderGuid = SelectBookmarkFolderFragmentArgs.fromBundle(arguments!!).folderGuid ?: BookmarkRoot.Root.id
|
||||||
|
checkIfSignedIn()
|
||||||
|
|
||||||
|
launch(IO) {
|
||||||
|
bookmarkNode = requireComponents.core.bookmarksStorage.getTree(folderGuid!!, true)
|
||||||
|
launch(Main) {
|
||||||
|
(activity as HomeActivity).title = bookmarkNode?.title ?: getString(R.string.library_bookmarks)
|
||||||
|
val adapter = SelectBookmarkFolderAdapter(sharedViewModel)
|
||||||
|
recylerView_bookmark_folders.adapter = adapter
|
||||||
|
adapter.updateData(bookmarkNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkIfSignedIn() {
|
||||||
|
val accountManager = requireComponents.backgroundServices.accountManager
|
||||||
|
accountManager.register(this, owner = this)
|
||||||
|
accountManager.authenticatedAccount()?.let { getManagedEmitter<SignInChange>().onNext(SignInChange.SignedIn) }
|
||||||
|
?: getManagedEmitter<SignInChange>().onNext(SignInChange.SignedOut)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
val visitedAddBookmark = SelectBookmarkFolderFragmentArgs.fromBundle(arguments!!).visitedAddBookmark
|
||||||
|
if (!visitedAddBookmark) {
|
||||||
|
inflater.inflate(R.menu.bookmarks_select_folder, menu)
|
||||||
|
menu.findItem(R.id.add_folder_button).icon.colorFilter =
|
||||||
|
PorterDuffColorFilter(R.attr.iconColor.getColorFromAttr(context!!), PorterDuff.Mode.SRC_IN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
return when (item.itemId) {
|
||||||
|
R.id.add_folder_button -> {
|
||||||
|
launch(Main) {
|
||||||
|
Navigation.findNavController(requireActivity(), R.id.container).navigate(
|
||||||
|
SelectBookmarkFolderFragmentDirections
|
||||||
|
.actionBookmarkSelectFolderFragmentToBookmarkAddFolderFragment()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAuthenticated(account: OAuthAccount) {
|
||||||
|
getManagedEmitter<SignInChange>().onNext(SignInChange.SignedIn)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(error: Exception) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLoggedOut() {
|
||||||
|
getManagedEmitter<SignInChange>().onNext(SignInChange.SignedOut)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onProfileUpdated(profile: Profile) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<!-- 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"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/bookmark_layout"
|
android:id="@+id/bookmark_layout"
|
||||||
|
@ -23,7 +27,7 @@
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintDimensionRatio="1:1"
|
app:layout_constraintDimensionRatio="1:1"
|
||||||
tools:foregroundTint="@android:color/black"
|
android:foregroundTint="?attr/iconColor"
|
||||||
tools:src="@drawable/ic_folder_icon" />
|
tools:src="@drawable/ic_folder_icon" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -34,6 +38,7 @@
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:textSize="16sp"
|
android:textSize="16sp"
|
||||||
|
android:textColor="?attr/bookmarksEditTextColor"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/bookmark_overflow"
|
app:layout_constraintEnd_toStartOf="@id/bookmark_overflow"
|
||||||
app:layout_constraintHorizontal_bias="0"
|
app:layout_constraintHorizontal_bias="0"
|
||||||
|
@ -57,6 +62,7 @@
|
||||||
android:id="@+id/bookmark_separator"
|
android:id="@+id/bookmark_separator"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginStart="68dp"
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:layout_marginBottom="10dp"
|
android:layout_marginBottom="10dp"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
|
@ -64,7 +70,7 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/bookmark_overflow"
|
app:layout_constraintEnd_toStartOf="@id/bookmark_overflow"
|
||||||
android:background="@android:color/black"
|
android:background="?attr/bookmarksEditTextColor"
|
||||||
android:visibility="gone"/>
|
android:visibility="gone"/>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -2,9 +2,27 @@
|
||||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
<!-- 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
|
- 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/. -->
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/bookmark_list"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/bookmark_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bookmarks_empty_view"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="@string/bookmarks_empty_message"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:textColor="?attr/bookmarksLabelColor"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?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/. -->
|
||||||
|
<Button
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/bookmark_folders_sign_in"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/sign_in_button"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:layout_marginTop="32dp"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent" />
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?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/. -->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_margin="16dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bookmark_add_folder_title_label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/bookmark_name_label"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="?attr/bookmarksLabelColor"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/bookmark_add_folder_title_edit"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:inputType="textAutoComplete"
|
||||||
|
android:textColor="?attr/bookmarksEditTextColor"
|
||||||
|
android:textSize="15sp"
|
||||||
|
tools:text="News" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bookmark_add_folder_parent_label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/bookmark_folder_label"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="?attr/bookmarksLabelColor"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bookmark_add_folder_parent_selector"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:drawableStart="@drawable/ic_folder_icon"
|
||||||
|
android:drawablePadding="10dp"
|
||||||
|
android:drawableTint="?attr/iconColor"
|
||||||
|
android:textColor="?attr/bookmarksEditTextColor"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:targetApi="m"
|
||||||
|
tools:text="Mobile Bookmarks" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -8,5 +8,4 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
tools:context="org.mozilla.fenix.library.bookmarks.BookmarkFragment">
|
tools:context="org.mozilla.fenix.library.bookmarks.BookmarkFragment" />
|
||||||
</LinearLayout>
|
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?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/. -->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_margin="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bookmark_name_label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/bookmark_name_label"
|
||||||
|
android:textColor="?attr/bookmarksLabelColor"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textAllCaps="true"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/bookmark_name_edit"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textColor="?attr/bookmarksEditTextColor"
|
||||||
|
tools:text="Internet for people, not profit -- Mozilla"
|
||||||
|
android:inputType="textAutoComplete"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bookmark_url_label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/bookmark_url_label"
|
||||||
|
android:textColor="?attr/bookmarksLabelColor"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textAllCaps="true"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/bookmark_url_edit"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textColor="?attr/bookmarksEditTextColor"
|
||||||
|
tools:text="https://www.mozilla.org/en-US/"
|
||||||
|
android:inputType="textUri"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bookmark_folder_label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/bookmark_folder_label"
|
||||||
|
android:textColor="?attr/bookmarksLabelColor"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textAllCaps="true"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bookmark_folder_selector"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textColor="?attr/bookmarksEditTextColor"
|
||||||
|
android:drawableStart="@drawable/ic_folder_icon"
|
||||||
|
android:drawablePadding="10dp"
|
||||||
|
android:drawableTint="?attr/iconColor"
|
||||||
|
tools:text="Mobile Bookmarks"
|
||||||
|
tools:targetApi="m" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?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/. -->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/select_bookmark_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recylerView_bookmark_folders"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -7,7 +7,7 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/confirm_add_folder_button"
|
android:id="@+id/confirm_add_folder_button"
|
||||||
android:icon="@drawable/ic_new"
|
android:icon="@drawable/mozac_ic_check"
|
||||||
android:iconTint="?attr/iconColor"
|
android:iconTint="?attr/iconColor"
|
||||||
android:title="@string/bookmark_add_folder"
|
android:title="@string/bookmark_add_folder"
|
||||||
app:showAsAction="ifRoom"
|
app:showAsAction="ifRoom"
|
||||||
|
|
|
@ -79,6 +79,9 @@
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_browserFragment_to_libraryFragment"
|
android:id="@+id/action_browserFragment_to_libraryFragment"
|
||||||
app:destination="@id/libraryFragment" />
|
app:destination="@id/libraryFragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_browserFragment_to_bookmarkEditFragment"
|
||||||
|
app:destination="@id/bookmarkEditFragment" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
|
@ -115,6 +118,56 @@
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_bookmarkFragment_self"
|
android:id="@+id/action_bookmarkFragment_self"
|
||||||
app:destination="@id/bookmarkFragment" />
|
app:destination="@id/bookmarkFragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_bookmarkFragment_to_bookmarkEditFragment"
|
||||||
|
app:destination="@id/bookmarkEditFragment" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/bookmarkEditFragment"
|
||||||
|
android:name="org.mozilla.fenix.library.bookmarks.edit.EditBookmarkFragment"
|
||||||
|
android:label="@string/edit_bookmark_fragment_title"
|
||||||
|
tools:layout="@layout/fragment_edit_bookmark">
|
||||||
|
<argument
|
||||||
|
android:name="guidToEdit"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="false"/>
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_bookmarkEditFragment_to_bookmarkSelectFolderFragment"
|
||||||
|
app:destination="@id/bookmarkSelectFolderFragment" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/bookmarkSelectFolderFragment"
|
||||||
|
android:name="org.mozilla.fenix.library.bookmarks.selectfolder.SelectBookmarkFolderFragment"
|
||||||
|
android:label="@string/bookmark_select_folder_fragment_label"
|
||||||
|
tools:layout="@layout/fragment_select_bookmark_folder">
|
||||||
|
<argument
|
||||||
|
android:name="folderGuid"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="true"/>
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_bookmarkSelectFolderFragment_self"
|
||||||
|
app:destination="@id/bookmarkSelectFolderFragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_bookmarkSelectFolderFragment_to_bookmarkAddFolderFragment"
|
||||||
|
app:destination="@id/bookmarkAddFolderFragment" />
|
||||||
|
<argument
|
||||||
|
android:name="visitedAddBookmark"
|
||||||
|
app:argType="boolean"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_bookmarkSelectFolderFragment_to_browserFragment"
|
||||||
|
app:destination="@id/browserFragment" />
|
||||||
|
</fragment>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/bookmarkAddFolderFragment"
|
||||||
|
android:name="org.mozilla.fenix.library.bookmarks.addfolder.AddBookmarkFolderFragment"
|
||||||
|
android:label="@string/bookmark_add_folder_fragment_label">
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_bookmarkAddFolderFragment_to_bookmarkSelectFolderFragment"
|
||||||
|
app:destination="@id/bookmarkSelectFolderFragment" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
<fragment
|
<fragment
|
||||||
|
|
|
@ -59,6 +59,13 @@
|
||||||
<!-- Library -->
|
<!-- Library -->
|
||||||
<color name="library_list_item_text_color_light_mode">@color/off_white</color>
|
<color name="library_list_item_text_color_light_mode">@color/off_white</color>
|
||||||
|
|
||||||
|
<!-- Bookmarks -->
|
||||||
|
<color name="bookmark_favicon_background">#DFDFE3</color>
|
||||||
|
<color name="bookmark_snackbar_background">#2E0EC1</color>
|
||||||
|
<color name="bookmark_selection_appbar_background">#2E0EC1</color>
|
||||||
|
<color name="bookmarks_label_normal_theme">#AFAD9C</color>
|
||||||
|
<color name="bookmarks_edit_normal_theme">@color/off_white</color>
|
||||||
|
|
||||||
<!-- Search Fragment -->
|
<!-- Search Fragment -->
|
||||||
<color name="suggestionBackground_normal_theme">@color/accent_bright_dark_theme</color>
|
<color name="suggestionBackground_normal_theme">@color/accent_bright_dark_theme</color>
|
||||||
<color name="search_text">@color/off_white</color>
|
<color name="search_text">@color/off_white</color>
|
||||||
|
|
|
@ -55,6 +55,10 @@
|
||||||
<attr name="historyTitleColor" format="reference" />
|
<attr name="historyTitleColor" format="reference" />
|
||||||
<attr name="historyHeader" format="reference" />
|
<attr name="historyHeader" format="reference" />
|
||||||
|
|
||||||
|
<!-- Bookmarks Fragment -->
|
||||||
|
<attr name="bookmarksLabelColor" format="reference" />
|
||||||
|
<attr name="bookmarksEditTextColor" format="reference" />
|
||||||
|
|
||||||
<!-- Library Fragment -->
|
<!-- Library Fragment -->
|
||||||
<attr name="libraryListItemTextColor" format="reference" />
|
<attr name="libraryListItemTextColor" format="reference" />
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
<!-- Bookmarks -->
|
<!-- Bookmarks -->
|
||||||
<color name="bookmark_favicon_background">#DFDFE3</color>
|
<color name="bookmark_favicon_background">#DFDFE3</color>
|
||||||
|
<color name="bookmark_snackbar_background">#2E0EC1</color>
|
||||||
|
<color name="bookmark_selection_appbar_background">#2E0EC1</color>
|
||||||
|
|
||||||
<!-- Specific colors for dark theme -->
|
<!-- Specific colors for dark theme -->
|
||||||
<color name="background_dark_theme">#1C1B22</color>
|
<color name="background_dark_theme">#1C1B22</color>
|
||||||
|
@ -30,6 +32,8 @@
|
||||||
<color name="session_placeholder_purple">@color/accent_bright_dark_theme</color>
|
<color name="session_placeholder_purple">@color/accent_bright_dark_theme</color>
|
||||||
<color name="session_placeholder_pink">#FF4AA2</color>
|
<color name="session_placeholder_pink">#FF4AA2</color>
|
||||||
<!-- Normal Theme -->
|
<!-- Normal Theme -->
|
||||||
|
<color name="bookmarks_label_normal_theme">#505263</color>
|
||||||
|
<color name="bookmarks_edit_normal_theme">@color/text_color_normal_theme</color>
|
||||||
<color name="history_header_normal_theme">#696A6A</color>
|
<color name="history_header_normal_theme">#696A6A</color>
|
||||||
<color name="history_title_normal_theme">@color/text_color_normal_theme</color>
|
<color name="history_title_normal_theme">@color/text_color_normal_theme</color>
|
||||||
<color name="history_url_normal_theme">#696A6A</color>
|
<color name="history_url_normal_theme">#696A6A</color>
|
||||||
|
@ -94,6 +98,8 @@
|
||||||
<color name="private_browsing_top_gradient">#242251</color>
|
<color name="private_browsing_top_gradient">#242251</color>
|
||||||
<color name="private_browsing_bottom_gradient">#393862</color>
|
<color name="private_browsing_bottom_gradient">#393862</color>
|
||||||
<color name="search_pill_private_selected_background">#080639</color>
|
<color name="search_pill_private_selected_background">#080639</color>
|
||||||
|
<color name="bookmarks_label_private_theme">@color/photonGrey40</color>
|
||||||
|
<color name="bookmarks_edit_private_theme">@color/off_white</color>
|
||||||
<color name="history_header_private_theme">@color/photonGrey40</color>
|
<color name="history_header_private_theme">@color/photonGrey40</color>
|
||||||
<color name="history_title_private_theme">@color/off_white</color>
|
<color name="history_title_private_theme">@color/off_white</color>
|
||||||
<color name="history_url_private_theme">@color/photonGrey40</color>
|
<color name="history_url_private_theme">@color/photonGrey40</color>
|
||||||
|
|
|
@ -285,7 +285,7 @@
|
||||||
<!-- Screen title for adding a bookmarks folder -->
|
<!-- Screen title for adding a bookmarks folder -->
|
||||||
<string name="bookmark_add_folder">Add folder</string>
|
<string name="bookmark_add_folder">Add folder</string>
|
||||||
<!-- Snackbar title shown after a bookmark has been created. -->
|
<!-- Snackbar title shown after a bookmark has been created. -->
|
||||||
<string name="bookmark_created_snackbar">Bookmark created.</string>
|
<string name="bookmark_created_snackbar">Bookmark saved!</string>
|
||||||
<!-- Snackbar edit button shown after a bookmark has been created. -->
|
<!-- Snackbar edit button shown after a bookmark has been created. -->
|
||||||
<string name="edit_bookmark_snackbar_action">EDIT</string>
|
<string name="edit_bookmark_snackbar_action">EDIT</string>
|
||||||
|
|
||||||
|
@ -303,4 +303,15 @@
|
||||||
<string name="bookmark_menu_open_in_private_tab_button">Open in private tab</string>
|
<string name="bookmark_menu_open_in_private_tab_button">Open in private tab</string>
|
||||||
<!-- Bookmark overflow menu delete button -->
|
<!-- Bookmark overflow menu delete button -->
|
||||||
<string name="bookmark_menu_delete_button">Delete</string>
|
<string name="bookmark_menu_delete_button">Delete</string>
|
||||||
|
|
||||||
|
<string name="edit_bookmark_fragment_title">Edit bookmark</string>
|
||||||
|
<string name="sign_in_button">Sign in to see synced bookmarks</string>
|
||||||
|
<string name="bookmark_url_label">URL</string>
|
||||||
|
<string name="bookmark_folder_label">FOLDER</string>
|
||||||
|
<string name="bookmark_name_label">NAME</string>
|
||||||
|
<string name="bookmark_add_folder_fragment_label">Add folder</string>
|
||||||
|
<string name="bookmark_select_folder_fragment_label">Select folder</string>
|
||||||
|
<string name="bookmark_empty_title_error">Must have a title</string>
|
||||||
|
<string name="bookmark_invalid_url_error">Invalid URL</string>
|
||||||
|
<string name="bookmarks_empty_message">No bookmarks here</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -73,6 +73,10 @@
|
||||||
<item name="historyURLColor">@color/history_url_normal_theme</item>
|
<item name="historyURLColor">@color/history_url_normal_theme</item>
|
||||||
<item name="historyHeader">@color/history_header_normal_theme</item>
|
<item name="historyHeader">@color/history_header_normal_theme</item>
|
||||||
|
|
||||||
|
<!-- Bookmark fragment colors -->
|
||||||
|
<item name="bookmarksLabelColor">@color/bookmarks_label_normal_theme</item>
|
||||||
|
<item name="bookmarksEditTextColor">@color/bookmarks_edit_normal_theme</item>
|
||||||
|
|
||||||
<!-- Library Fragment -->
|
<!-- Library Fragment -->
|
||||||
<item name="libraryListItemTextColor">@color/library_list_item_text_color_light_mode</item>
|
<item name="libraryListItemTextColor">@color/library_list_item_text_color_light_mode</item>
|
||||||
</style>
|
</style>
|
||||||
|
@ -138,6 +142,10 @@
|
||||||
<item name="historyURLColor">@color/history_url_private_theme</item>
|
<item name="historyURLColor">@color/history_url_private_theme</item>
|
||||||
<item name="historyHeader">@color/history_header_private_theme</item>
|
<item name="historyHeader">@color/history_header_private_theme</item>
|
||||||
|
|
||||||
|
<!-- Bookmark fragment colors -->
|
||||||
|
<item name="bookmarksLabelColor">@color/bookmarks_label_private_theme</item>
|
||||||
|
<item name="bookmarksEditTextColor">@color/bookmarks_edit_private_theme</item>
|
||||||
|
|
||||||
<!-- Library Fragment -->
|
<!-- Library Fragment -->
|
||||||
<item name="libraryListItemTextColor">@color/off_white</item>
|
<item name="libraryListItemTextColor">@color/off_white</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.mozilla.fenix.library.bookmarks
|
||||||
import io.mockk.Runs
|
import io.mockk.Runs
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
import io.mockk.spyk
|
import io.mockk.spyk
|
||||||
import io.mockk.verifySequence
|
import io.mockk.verifySequence
|
||||||
import io.reactivex.Observer
|
import io.reactivex.Observer
|
||||||
|
@ -27,7 +28,7 @@ internal class BookmarkAdapterTest {
|
||||||
setRxSchedulers()
|
setRxSchedulers()
|
||||||
emitter = TestObserver<BookmarkAction>()
|
emitter = TestObserver<BookmarkAction>()
|
||||||
bookmarkAdapter = spyk(
|
bookmarkAdapter = spyk(
|
||||||
BookmarkAdapter(emitter), recordPrivateCalls = true
|
BookmarkAdapter(mockk(), emitter), recordPrivateCalls = true
|
||||||
)
|
)
|
||||||
every { bookmarkAdapter.notifyDataSetChanged() } just Runs
|
every { bookmarkAdapter.notifyDataSetChanged() } just Runs
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ private object Versions {
|
||||||
const val android_gradle_plugin = "3.3.2"
|
const val android_gradle_plugin = "3.3.2"
|
||||||
const val rxAndroid = "2.1.0"
|
const val rxAndroid = "2.1.0"
|
||||||
const val rxKotlin = "2.3.0"
|
const val rxKotlin = "2.3.0"
|
||||||
|
const val rxBindings = "3.0.0-alpha2"
|
||||||
const val anko = "0.10.8"
|
const val anko = "0.10.8"
|
||||||
const val sentry = "1.7.10"
|
const val sentry = "1.7.10"
|
||||||
const val leakcanary = "1.6.3"
|
const val leakcanary = "1.6.3"
|
||||||
|
@ -52,6 +53,7 @@ object Deps {
|
||||||
|
|
||||||
const val rxKotlin = "io.reactivex.rxjava2:rxkotlin:${Versions.rxKotlin}"
|
const val rxKotlin = "io.reactivex.rxjava2:rxkotlin:${Versions.rxKotlin}"
|
||||||
const val rxAndroid = "io.reactivex.rxjava2:rxandroid:${Versions.rxAndroid}"
|
const val rxAndroid = "io.reactivex.rxjava2:rxandroid:${Versions.rxAndroid}"
|
||||||
|
const val rxBindings = "com.jakewharton.rxbinding3:rxbinding:${Versions.rxBindings}"
|
||||||
|
|
||||||
const val anko_commons = "org.jetbrains.anko:anko-commons:${Versions.anko}"
|
const val anko_commons = "org.jetbrains.anko:anko-commons:${Versions.anko}"
|
||||||
const val anko_sdk = "org.jetbrains.anko:anko-sdk25:${Versions.anko}"
|
const val anko_sdk = "org.jetbrains.anko:anko-sdk25:${Versions.anko}"
|
||||||
|
@ -123,6 +125,7 @@ object Deps {
|
||||||
const val androidx_appcompat = "androidx.appcompat:appcompat:${Versions.androidx_appcompat}"
|
const val androidx_appcompat = "androidx.appcompat:appcompat:${Versions.androidx_appcompat}"
|
||||||
const val androidx_constraintlayout = "androidx.constraintlayout:constraintlayout:${Versions.androidx_constraint_layout}"
|
const val androidx_constraintlayout = "androidx.constraintlayout:constraintlayout:${Versions.androidx_constraint_layout}"
|
||||||
const val androidx_legacy = "androidx.legacy:legacy-support-v4:${Versions.androidx_legacy}"
|
const val androidx_legacy = "androidx.legacy:legacy-support-v4:${Versions.androidx_legacy}"
|
||||||
|
const val androidx_lifecycle_viewmodel_ktx = "androidx.lifecycle:lifecycle-viewmodel-ktx:${Versions.androidx_lifecycle}"
|
||||||
const val androidx_lifecycle_runtime = "androidx.lifecycle:lifecycle-runtime:${Versions.androidx_lifecycle}"
|
const val androidx_lifecycle_runtime = "androidx.lifecycle:lifecycle-runtime:${Versions.androidx_lifecycle}"
|
||||||
const val androidx_preference = "androidx.preference:preference-ktx:${Versions.androidx_preference}"
|
const val androidx_preference = "androidx.preference:preference-ktx:${Versions.androidx_preference}"
|
||||||
const val androidx_safeargs = "androidx.navigation:navigation-safe-args-gradle-plugin:${Versions.androidx_navigation}"
|
const val androidx_safeargs = "androidx.navigation:navigation-safe-args-gradle-plugin:${Versions.androidx_navigation}"
|
||||||
|
|
Loading…
Reference in New Issue