parent
d7717e295b
commit
bd81e72239
@ -0,0 +1,246 @@
|
||||
/* 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 androidx.recyclerview.widget.RecyclerView
|
||||
import io.reactivex.Observer
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.bookmark_row.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.icons.BrowserIcons
|
||||
import mozilla.components.browser.icons.IconRequest
|
||||
import mozilla.components.browser.menu.BrowserMenu
|
||||
import mozilla.components.concept.storage.BookmarkNode
|
||||
import mozilla.components.concept.storage.BookmarkNodeType
|
||||
import org.mozilla.fenix.R
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class BookmarkAdapter(val actionEmitter: Observer<BookmarkAction>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
private var tree: List<BookmarkNode> = listOf()
|
||||
private var mode: BookmarkState.Mode = BookmarkState.Mode.Normal
|
||||
|
||||
lateinit var job: Job
|
||||
|
||||
fun updateData(tree: BookmarkNode?, mode: BookmarkState.Mode) {
|
||||
this.tree = tree?.children?.filterNotNull() ?: listOf()
|
||||
this.mode = mode
|
||||
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) {
|
||||
BookmarkItemViewHolder.viewType.ordinal -> BookmarkAdapter.BookmarkItemViewHolder(
|
||||
view, actionEmitter, job
|
||||
)
|
||||
BookmarkFolderViewHolder.viewType.ordinal -> BookmarkAdapter.BookmarkFolderViewHolder(
|
||||
view, actionEmitter
|
||||
)
|
||||
BookmarkSeparatorViewHolder.viewType.ordinal -> BookmarkAdapter.BookmarkSeparatorViewHolder(
|
||||
view, actionEmitter
|
||||
)
|
||||
else -> throw IllegalStateException("ViewType $viewType does not match to a ViewHolder")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return when (tree[position].type) {
|
||||
BookmarkNodeType.ITEM -> ViewType.ITEM.ordinal
|
||||
BookmarkNodeType.FOLDER -> ViewType.FOLDER.ordinal
|
||||
BookmarkNodeType.SEPARATOR -> ViewType.SEPARATOR.ordinal
|
||||
else -> throw IllegalStateException("Item $tree[position] does not match to a ViewType")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView)
|
||||
job = Job()
|
||||
}
|
||||
|
||||
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onDetachedFromRecyclerView(recyclerView)
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = tree.size
|
||||
|
||||
@SuppressWarnings("ComplexMethod")
|
||||
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) {
|
||||
is BookmarkAdapter.BookmarkItemViewHolder -> holder.bind(tree[position], bookmarkItemMenu, mode)
|
||||
is BookmarkAdapter.BookmarkFolderViewHolder -> holder.bind(tree[position], bookmarkItemMenu, mode)
|
||||
is BookmarkAdapter.BookmarkSeparatorViewHolder -> holder.bind(bookmarkItemMenu)
|
||||
}
|
||||
}
|
||||
|
||||
class BookmarkItemViewHolder(
|
||||
view: View,
|
||||
val actionEmitter: Observer<BookmarkAction>,
|
||||
private val job: Job,
|
||||
override val containerView: View? = view
|
||||
) :
|
||||
RecyclerView.ViewHolder(view), LayoutContainer, CoroutineScope {
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.Main + job
|
||||
|
||||
private var item: BookmarkNode? = null
|
||||
private var mode: BookmarkState.Mode? = BookmarkState.Mode.Normal
|
||||
|
||||
init {
|
||||
bookmark_favicon.visibility = View.VISIBLE
|
||||
bookmark_title.visibility = View.VISIBLE
|
||||
bookmark_overflow.visibility = View.VISIBLE
|
||||
bookmark_separator.visibility = View.GONE
|
||||
bookmark_layout.isClickable = true
|
||||
}
|
||||
|
||||
fun bind(item: BookmarkNode, bookmarkItemMenu: BookmarkItemMenu, mode: BookmarkState.Mode) {
|
||||
this.item = item
|
||||
this.mode = mode
|
||||
|
||||
bookmark_overflow.setOnClickListener {
|
||||
bookmarkItemMenu.menuBuilder.build(containerView!!.context).show(
|
||||
anchor = it,
|
||||
orientation = BrowserMenu.Orientation.DOWN
|
||||
)
|
||||
}
|
||||
bookmark_title.text = item.title
|
||||
updateUrl(item)
|
||||
}
|
||||
|
||||
private fun updateUrl(item: BookmarkNode) {
|
||||
bookmark_layout.setOnClickListener {
|
||||
if (mode == BookmarkState.Mode.Normal) {
|
||||
actionEmitter.onNext(BookmarkAction.Open(item))
|
||||
} else {
|
||||
actionEmitter.onNext(BookmarkAction.Select(item))
|
||||
}
|
||||
}
|
||||
|
||||
bookmark_layout.setOnLongClickListener {
|
||||
if (mode == BookmarkState.Mode.Normal) {
|
||||
actionEmitter.onNext(BookmarkAction.Select(item))
|
||||
true
|
||||
} else false
|
||||
}
|
||||
|
||||
if (item.url?.startsWith("http") == true) {
|
||||
launch(Dispatchers.IO) {
|
||||
val bitmap = BrowserIcons(bookmark_favicon.context)
|
||||
.loadIcon(IconRequest(item.url!!)).await().bitmap
|
||||
launch(Dispatchers.Main) {
|
||||
bookmark_favicon.setImageBitmap(bitmap)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val viewType = BookmarkAdapter.ViewType.ITEM
|
||||
}
|
||||
}
|
||||
|
||||
class BookmarkFolderViewHolder(
|
||||
view: View,
|
||||
val actionEmitter: Observer<BookmarkAction>,
|
||||
override val containerView: View? = view
|
||||
) :
|
||||
RecyclerView.ViewHolder(view), LayoutContainer {
|
||||
|
||||
init {
|
||||
bookmark_favicon.setImageResource(R.drawable.ic_folder_icon)
|
||||
bookmark_favicon.visibility = View.VISIBLE
|
||||
bookmark_title.visibility = View.VISIBLE
|
||||
bookmark_overflow.visibility = View.VISIBLE
|
||||
bookmark_separator.visibility = View.GONE
|
||||
bookmark_layout.isClickable = true
|
||||
}
|
||||
|
||||
fun bind(folder: BookmarkNode, bookmarkItemMenu: BookmarkItemMenu, mode: BookmarkState.Mode) {
|
||||
bookmark_overflow.setOnClickListener {
|
||||
bookmarkItemMenu.menuBuilder.build(containerView!!.context).show(
|
||||
anchor = it,
|
||||
orientation = BrowserMenu.Orientation.DOWN
|
||||
)
|
||||
}
|
||||
bookmark_title?.text = folder.title
|
||||
bookmark_layout.setOnClickListener {
|
||||
actionEmitter.onNext(BookmarkAction.Expand(folder))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val viewType = BookmarkAdapter.ViewType.FOLDER
|
||||
}
|
||||
}
|
||||
|
||||
class BookmarkSeparatorViewHolder(
|
||||
view: View,
|
||||
val actionEmitter: Observer<BookmarkAction>,
|
||||
override val containerView: View? = view
|
||||
) : RecyclerView.ViewHolder(view), LayoutContainer {
|
||||
|
||||
init {
|
||||
bookmark_favicon.visibility = View.GONE
|
||||
bookmark_title.visibility = View.GONE
|
||||
bookmark_overflow.visibility = View.VISIBLE
|
||||
bookmark_separator.visibility = View.VISIBLE
|
||||
bookmark_layout.isClickable = false
|
||||
}
|
||||
|
||||
fun bind(bookmarkItemMenu: BookmarkItemMenu) {
|
||||
bookmark_overflow.setOnClickListener {
|
||||
bookmarkItemMenu.menuBuilder.build(containerView!!.context).show(
|
||||
anchor = it,
|
||||
orientation = BrowserMenu.Orientation.DOWN
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val viewType = BookmarkAdapter.ViewType.SEPARATOR
|
||||
}
|
||||
}
|
||||
|
||||
enum class ViewType {
|
||||
ITEM, FOLDER, SEPARATOR
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/* 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 mozilla.components.concept.storage.BookmarkNode
|
||||
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 BookmarkComponent(
|
||||
private val container: ViewGroup,
|
||||
bus: ActionBusFactory,
|
||||
override var initialState: BookmarkState =
|
||||
BookmarkState(null, BookmarkState.Mode.Normal)
|
||||
) :
|
||||
UIComponent<BookmarkState, BookmarkAction, BookmarkChange>(
|
||||
bus.getManagedEmitter(BookmarkAction::class.java),
|
||||
bus.getSafeManagedObservable(BookmarkChange::class.java)
|
||||
) {
|
||||
|
||||
override val reducer: Reducer<BookmarkState, BookmarkChange> = { state, change ->
|
||||
when (change) {
|
||||
is BookmarkChange.Change -> {
|
||||
state.copy(tree = change.tree)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun initView(): UIView<BookmarkState, BookmarkAction, BookmarkChange> =
|
||||
BookmarkUIView(container, actionEmitter, changesObservable)
|
||||
|
||||
init {
|
||||
render(reducer)
|
||||
}
|
||||
}
|
||||
|
||||
data class BookmarkState(val tree: BookmarkNode?, val mode: BookmarkState.Mode) : ViewState {
|
||||
sealed class Mode {
|
||||
object Normal : Mode()
|
||||
data class Selecting(val selectedItems: List<BookmarkNode>) : Mode()
|
||||
}
|
||||
}
|
||||
|
||||
sealed class BookmarkAction : Action {
|
||||
data class Open(val item: BookmarkNode) : BookmarkAction()
|
||||
data class Expand(val folder: BookmarkNode) : BookmarkAction()
|
||||
data class Edit(val item: BookmarkNode) : BookmarkAction()
|
||||
data class Copy(val item: BookmarkNode) : BookmarkAction()
|
||||
data class Share(val item: BookmarkNode) : BookmarkAction()
|
||||
data class OpenInNewTab(val item: BookmarkNode) : BookmarkAction()
|
||||
data class OpenInPrivateTab(val item: BookmarkNode) : BookmarkAction()
|
||||
data class Select(val item: BookmarkNode) : BookmarkAction()
|
||||
data class Delete(val item: BookmarkNode) : BookmarkAction()
|
||||
object ExitSelectMode : BookmarkAction()
|
||||
object BackPressed : BookmarkAction()
|
||||
}
|
||||
|
||||
sealed class BookmarkChange : Change {
|
||||
data class Change(val tree: BookmarkNode) : BookmarkChange()
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
/* 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.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.navigation.Navigation
|
||||
import kotlinx.android.synthetic.main.fragment_bookmark.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.storage.BookmarkNodeType
|
||||
import mozilla.components.support.base.feature.BackHandler
|
||||
import org.mozilla.fenix.BrowsingModeManager
|
||||
import org.mozilla.fenix.HomeActivity
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.requireComponents
|
||||
import org.mozilla.fenix.ext.share
|
||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||
import org.mozilla.fenix.mvi.getAutoDisposeObservable
|
||||
import org.mozilla.fenix.mvi.getManagedEmitter
|
||||
import org.mozilla.fenix.utils.ItsNotBrokenSnack
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class BookmarkFragment : Fragment(), CoroutineScope, BackHandler {
|
||||
|
||||
private lateinit var job: Job
|
||||
private lateinit var bookmarkComponent: BookmarkComponent
|
||||
private lateinit var currentRoot: BookmarkNode
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.Main + job
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val view = inflater.inflate(R.layout.fragment_bookmark, container, false)
|
||||
bookmarkComponent = BookmarkComponent(view.bookmark_layout, ActionBusFactory.get(this))
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
job = Job()
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
(activity as AppCompatActivity).supportActionBar?.show()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
job.cancel()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
inflater.inflate(R.menu.library_menu, menu)
|
||||
}
|
||||
|
||||
@SuppressWarnings("ComplexMethod")
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
getAutoDisposeObservable<BookmarkAction>()
|
||||
.subscribe {
|
||||
when (it) {
|
||||
is BookmarkAction.Open -> {
|
||||
if (it.item.type == BookmarkNodeType.ITEM) {
|
||||
it.item.url?.let { url ->
|
||||
val activity = requireActivity() as HomeActivity
|
||||
Navigation.findNavController(activity, R.id.container)
|
||||
.navigate(BookmarkFragmentDirections.actionBookmarkFragmentToBrowserFragment(null))
|
||||
if (activity.browsingModeManager.isPrivate) {
|
||||
requireComponents.useCases.tabsUseCases.addPrivateTab.invoke(url)
|
||||
activity.browsingModeManager.mode =
|
||||
BrowsingModeManager.Mode.Private
|
||||
} else {
|
||||
requireComponents.useCases.sessionUseCases.loadUrl.invoke(url)
|
||||
activity.browsingModeManager.mode =
|
||||
BrowsingModeManager.Mode.Normal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is BookmarkAction.Expand -> {
|
||||
Navigation.findNavController(requireActivity(), R.id.container)
|
||||
.navigate(BookmarkFragmentDirections.actionBookmarkFragmentSelf(it.folder.guid))
|
||||
}
|
||||
is BookmarkAction.BackPressed -> {
|
||||
Navigation.findNavController(requireActivity(), R.id.container).popBackStack()
|
||||
}
|
||||
is BookmarkAction.Edit -> {
|
||||
ItsNotBrokenSnack(context!!).showSnackbar(issueNumber = "1238")
|
||||
}
|
||||
is BookmarkAction.Select -> {
|
||||
ItsNotBrokenSnack(context!!).showSnackbar(issueNumber = "1239")
|
||||
}
|
||||
is BookmarkAction.Copy -> {
|
||||
ItsNotBrokenSnack(context!!).showSnackbar(issueNumber = "1239")
|
||||
}
|
||||
is BookmarkAction.Share -> {
|
||||
it.item.url?.let { url -> requireContext().share(url) }
|
||||
}
|
||||
is BookmarkAction.OpenInNewTab -> {
|
||||
it.item.url?.let { url ->
|
||||
requireComponents.useCases.tabsUseCases.addTab.invoke(url)
|
||||
(activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Normal
|
||||
}
|
||||
}
|
||||
is BookmarkAction.OpenInPrivateTab -> {
|
||||
it.item.url?.let { url ->
|
||||
requireComponents.useCases.tabsUseCases.addPrivateTab.invoke(url)
|
||||
(activity as HomeActivity).browsingModeManager.mode = BrowsingModeManager.Mode.Private
|
||||
}
|
||||
}
|
||||
is BookmarkAction.Delete -> {
|
||||
launch(IO) {
|
||||
requireComponents.core.bookmarksStorage.deleteNode(it.item.guid)
|
||||
requireComponents.core.bookmarksStorage.getTree(currentRoot.guid, false)
|
||||
?.let { node ->
|
||||
getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.Change(node))
|
||||
}
|
||||
}
|
||||
}
|
||||
is BookmarkAction.ExitSelectMode -> {
|
||||
ItsNotBrokenSnack(context!!).showSnackbar(issueNumber = "1239")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.libraryClose -> {
|
||||
Navigation.findNavController(requireActivity(), R.id.container)
|
||||
.popBackStack(R.id.libraryFragment, true)
|
||||
true
|
||||
}
|
||||
R.id.librarySearch -> {
|
||||
// TODO Library Search
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val currentGuid = BookmarkFragmentArgs.fromBundle(arguments!!).currentRoot.ifEmpty { BookmarkRoot.Root.id }
|
||||
|
||||
launch(IO) {
|
||||
currentRoot = requireComponents.core.bookmarksStorage.getTree(currentGuid) as BookmarkNode
|
||||
|
||||
launch(Main) {
|
||||
getManagedEmitter<BookmarkChange>().onNext(BookmarkChange.Change(currentRoot))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean = (bookmarkComponent.uiView as BookmarkUIView).onBackPressed()
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/* 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.content.Context
|
||||
import mozilla.components.browser.menu.BrowserMenuBuilder
|
||||
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
|
||||
import org.mozilla.fenix.R
|
||||
|
||||
class BookmarkItemMenu(
|
||||
private val context: Context,
|
||||
private val onItemTapped: (BookmarkItemMenu.Item) -> Unit = {}
|
||||
) {
|
||||
|
||||
sealed class Item {
|
||||
object Edit : Item()
|
||||
object Select : Item()
|
||||
object Copy : Item()
|
||||
object Share : Item()
|
||||
object OpenInNewTab : Item()
|
||||
object OpenInPrivateTab : Item()
|
||||
object Delete : Item()
|
||||
}
|
||||
|
||||
val menuBuilder by lazy { BrowserMenuBuilder(menuItems) }
|
||||
|
||||
private val menuItems by lazy {
|
||||
listOf(
|
||||
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)
|
||||
},
|
||||
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_copy_button)) {
|
||||
onItemTapped.invoke(BookmarkItemMenu.Item.Copy)
|
||||
},
|
||||
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_share_button)) {
|
||||
onItemTapped.invoke(BookmarkItemMenu.Item.Share)
|
||||
},
|
||||
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_open_in_new_tab_button)) {
|
||||
onItemTapped.invoke(BookmarkItemMenu.Item.OpenInNewTab)
|
||||
},
|
||||
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_open_in_private_tab_button)) {
|
||||
onItemTapped.invoke(BookmarkItemMenu.Item.OpenInPrivateTab)
|
||||
},
|
||||
SimpleBrowserMenuItem(context.getString(R.string.bookmark_menu_delete_button),
|
||||
textColorResource = R.color.photonRed60
|
||||
) {
|
||||
onItemTapped.invoke(BookmarkItemMenu.Item.Delete)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/* 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.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Observer
|
||||
import io.reactivex.functions.Consumer
|
||||
import mozilla.appservices.places.BookmarkRoot
|
||||
import mozilla.components.support.base.feature.BackHandler
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.mvi.UIView
|
||||
|
||||
class BookmarkUIView(
|
||||
container: ViewGroup,
|
||||
actionEmitter: Observer<BookmarkAction>,
|
||||
changesObservable: Observable<BookmarkChange>
|
||||
) :
|
||||
UIView<BookmarkState, BookmarkAction, BookmarkChange>(container, actionEmitter, changesObservable),
|
||||
BackHandler {
|
||||
|
||||
var mode: BookmarkState.Mode = BookmarkState.Mode.Normal
|
||||
private set
|
||||
|
||||
var canGoBack = false
|
||||
|
||||
override val view: RecyclerView = LayoutInflater.from(container.context)
|
||||
.inflate(R.layout.component_bookmark, container, true)
|
||||
.findViewById(R.id.bookmark_list)
|
||||
|
||||
private val bookmarkAdapter = BookmarkAdapter(actionEmitter)
|
||||
|
||||
init {
|
||||
view.apply {
|
||||
adapter = bookmarkAdapter
|
||||
layoutManager = LinearLayoutManager(container.context)
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateView() = Consumer<BookmarkState> {
|
||||
canGoBack = !(listOf(null, BookmarkRoot.Root.id).contains(it.tree?.guid))
|
||||
bookmarkAdapter.updateData(it.tree, it.mode)
|
||||
mode = it.mode
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
return if (canGoBack) {
|
||||
actionEmitter.onNext(BookmarkAction.BackPressed)
|
||||
true
|
||||
} else false
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/* 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.quickactionsheet
|
||||
|
||||
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 QuickActionComponent(
|
||||
private val container: ViewGroup,
|
||||
bus: ActionBusFactory,
|
||||
override var initialState: QuickActionState = QuickActionState(false)
|
||||
) : UIComponent<QuickActionState, QuickActionAction, QuickActionChange>(
|
||||
bus.getManagedEmitter(QuickActionAction::class.java),
|
||||
bus.getSafeManagedObservable(QuickActionChange::class.java)
|
||||
) {
|
||||
|
||||
override val reducer: Reducer<QuickActionState, QuickActionChange> = { state, change ->
|
||||
when (change) {
|
||||
is QuickActionChange.ReadableStateChange -> {
|
||||
state.copy(readable = change.readable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun initView(): UIView<QuickActionState, QuickActionAction, QuickActionChange> =
|
||||
QuickActionUIView(container, actionEmitter, changesObservable)
|
||||
|
||||
init {
|
||||
render(reducer)
|
||||
}
|
||||
}
|
||||
|
||||
data class QuickActionState(val readable: Boolean) : ViewState
|
||||
|
||||
sealed class QuickActionAction : Action {
|
||||
object SharePressed : QuickActionAction()
|
||||
object DownloadsPressed : QuickActionAction()
|
||||
object BookmarkPressed : QuickActionAction()
|
||||
object ReadPressed : QuickActionAction()
|
||||
}
|
||||
|
||||
sealed class QuickActionChange : Change {
|
||||
data class ReadableStateChange(val readable: Boolean) : QuickActionChange()
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.quickactionsheet
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Observer
|
||||
import io.reactivex.functions.Consumer
|
||||
import kotlinx.android.synthetic.main.fragment_browser.*
|
||||
import kotlinx.android.synthetic.main.layout_quick_action_sheet.view.*
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.mvi.UIView
|
||||
|
||||
class QuickActionUIView(
|
||||
container: ViewGroup,
|
||||
actionEmitter: Observer<QuickActionAction>,
|
||||
changesObservable: Observable<QuickActionChange>
|
||||
) : UIView<QuickActionState, QuickActionAction, QuickActionChange>(container, actionEmitter, changesObservable) {
|
||||
|
||||
override val view: NestedScrollView = LayoutInflater.from(container.context)
|
||||
.inflate(R.layout.component_quick_action_sheet, container, true)
|
||||
.findViewById(R.id.nestedScrollQuickAction) as NestedScrollView
|
||||
|
||||
init {
|
||||
val quickActionSheetBehavior =
|
||||
BottomSheetBehavior.from(nestedScrollQuickAction as View) as QuickActionSheetBehavior
|
||||
|
||||
view.quick_action_share.setOnClickListener {
|
||||
actionEmitter.onNext(QuickActionAction.SharePressed)
|
||||
quickActionSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
}
|
||||
view.quick_action_downloads.setOnClickListener {
|
||||
actionEmitter.onNext(QuickActionAction.DownloadsPressed)
|
||||
quickActionSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
}
|
||||
view.quick_action_bookmark.setOnClickListener {
|
||||
actionEmitter.onNext(QuickActionAction.BookmarkPressed)
|
||||
quickActionSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
}
|
||||
view.quick_action_read.setOnClickListener {
|
||||
actionEmitter.onNext(QuickActionAction.ReadPressed)
|
||||
quickActionSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateView() = Consumer<QuickActionState> {
|
||||
view.quick_action_read.visibility = if (it.readable) View.VISIBLE else View.GONE
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?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/. -->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval">
|
||||
<solid android:color="@color/bookmark_favicon_background" />
|
||||
<size android:width="40dp" android:height="40dp"/>
|
||||
</shape>
|
@ -0,0 +1,7 @@
|
||||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:viewportHeight="17" android:viewportWidth="20"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#20123A"
|
||||
android:pathData="M17.5,3L10.719,3L8.23,0.674C7.7673,0.2413 7.1575,0.0004 6.524,0L2.5,0C1.8361,0 1.1994,0.2641 0.7305,0.734C0.2615,1.2039 -0.0013,1.8411 0,2.505L0,14.5C0,15.8807 1.1193,17 2.5,17L17.5,17C18.8807,17 20,15.8807 20,14.5L20,5.505C20.0013,4.8411 19.7385,4.2039 19.2695,3.734C18.8006,3.2641 18.1639,3 17.5,3ZM2.5,2L6.524,2C6.6503,2.0004 6.7718,2.0487 6.864,2.135L8.86,4L2,4L2,2.505C1.9987,2.3715 2.0508,2.2431 2.1447,2.1482C2.2386,2.0534 2.3665,2 2.5,2ZM18,14.5C18,14.7761 17.7761,15 17.5,15L2.5,15C2.2239,15 2,14.7761 2,14.5L2,5L17.5,5C17.6335,5 17.7614,5.0534 17.8553,5.1482C17.9492,5.2431 18.0013,5.3715 18,5.505L18,14.5Z"
|
||||
android:strokeColor="#00000000" android:strokeWidth="1"/>
|
||||
</vector>
|
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/bookmark_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:background="?android:attr/selectableItemBackground">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/bookmark_favicon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
tools:src="@drawable/ic_folder_icon"
|
||||
tools:foregroundTint="@android:color/black"
|
||||
android:padding="10dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:background="@drawable/favicon_background"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bookmark_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/bookmark_favicon"
|
||||
app:layout_constraintEnd_toStartOf="@id/bookmark_overflow"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
tools:text="Internet"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/bookmark_overflow"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@drawable/ic_menu"
|
||||
android:layout_margin="10dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:contentDescription="@string/bookmark_menu_content_description"/>
|
||||
|
||||
<View
|
||||
android:id="@+id/bookmark_separator"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/bookmark_overflow"
|
||||
android:background="@android:color/black"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,10 @@
|
||||
<?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/. -->
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/bookmark_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.mozilla.fenix.quickactionsheet.QuickActionSheet
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/quick_action_sheet"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"/>
|
@ -0,0 +1,12 @@
|
||||
<?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:id="@+id/bookmark_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context="org.mozilla.fenix.library.bookmarks.BookmarkFragment">
|
||||
</LinearLayout>
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/selectionToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
app:titleMarginStart="16dp"
|
||||
app:titleMarginEnd="16dp"
|
||||
app:titleTextAppearance="@style/ToolbarTitleTextStyle"
|
||||
android:background="?attr/toolbarColor"
|
||||
android:elevation="8dp"/>
|
@ -0,0 +1,15 @@
|
||||
<?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/. -->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<item
|
||||
android:id="@+id/confirm_add_folder_button"
|
||||
android:icon="@drawable/ic_new"
|
||||
android:iconTint="?attr/iconColor"
|
||||
android:title="@string/bookmark_add_folder"
|
||||
app:showAsAction="ifRoom"
|
||||
tools:targetApi="o" />
|
||||
</menu>
|
@ -0,0 +1,15 @@
|
||||
<?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/. -->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<item
|
||||
android:id="@+id/delete_bookmark_button"
|
||||
android:icon="@drawable/ic_delete"
|
||||
android:iconTint="?attr/iconColor"
|
||||
android:title="@string/bookmark_edit"
|
||||
app:showAsAction="ifRoom"
|
||||
tools:targetApi="o" />
|
||||
</menu>
|
@ -0,0 +1,15 @@
|
||||
<?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/. -->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<item
|
||||
android:id="@+id/add_folder_button"
|
||||
android:icon="@drawable/ic_new"
|
||||
android:iconTint="?attr/iconColor"
|
||||
android:title="@string/bookmark_select_folder"
|
||||
app:showAsAction="ifRoom"
|
||||
tools:targetApi="o" />
|
||||
</menu>
|
@ -0,0 +1,71 @@
|
||||
/* 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 io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verifySequence
|
||||
import io.reactivex.Observer
|
||||
import io.reactivex.observers.TestObserver
|
||||
import mozilla.components.concept.storage.BookmarkNode
|
||||
import mozilla.components.concept.storage.BookmarkNodeType
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mozilla.fenix.TestUtils.setRxSchedulers
|
||||
|
||||
internal class BookmarkAdapterTest {
|
||||
|
||||
private lateinit var bookmarkAdapter: BookmarkAdapter
|
||||
private lateinit var emitter: Observer<BookmarkAction>
|
||||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
setRxSchedulers()
|
||||
emitter = TestObserver<BookmarkAction>()
|
||||
bookmarkAdapter = spyk(
|
||||
BookmarkAdapter(emitter), recordPrivateCalls = true
|
||||
)
|
||||
every { bookmarkAdapter.notifyDataSetChanged() } just Runs
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `update adapter from tree of bookmark nodes`() {
|
||||
val tree = BookmarkNode(
|
||||
BookmarkNodeType.FOLDER, "123", null, 0, "Mobile", null, listOf(
|
||||
BookmarkNode(BookmarkNodeType.ITEM, "456", "123", 0, "Mozilla", "http://mozilla.org", null),
|
||||
BookmarkNode(BookmarkNodeType.SEPARATOR, "789", "123", 1, null, null, null),
|
||||
BookmarkNode(
|
||||
BookmarkNodeType.ITEM,
|
||||
"987",
|
||||
"123",
|
||||
2,
|
||||
"Firefox",
|
||||
"https://www.mozilla.org/en-US/firefox/",
|
||||
null
|
||||
)
|
||||
)
|
||||
)
|
||||
bookmarkAdapter.updateData(tree, BookmarkState.Mode.Normal)
|
||||
verifySequence {
|
||||
bookmarkAdapter.updateData(tree, BookmarkState.Mode.Normal)
|
||||
bookmarkAdapter setProperty "tree" value tree.children
|
||||
bookmarkAdapter setProperty "mode" value BookmarkState.Mode.Normal
|
||||
bookmarkAdapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `passing null tree returns empty list`() {
|
||||
bookmarkAdapter.updateData(null, BookmarkState.Mode.Normal)
|
||||
verifySequence {
|
||||
bookmarkAdapter.updateData(null, BookmarkState.Mode.Normal)
|
||||
bookmarkAdapter setProperty "tree" value listOf<BookmarkNode?>()
|
||||
bookmarkAdapter setProperty "mode" value BookmarkState.Mode.Normal
|
||||
bookmarkAdapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +1,36 @@
|
||||
include ':app', ':architecture'
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Local Development overrides
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Properties localProperties = null;
|
||||
String settingAppServicesPath = "substitutions.application-services.dir";
|
||||
|
||||
if (file('local.properties').canRead()) {
|
||||
localProperties = new Properties()
|
||||
localProperties.load(file('local.properties').newDataInputStream())
|
||||
logger.lifecycle('Local configuration: loaded local.properties')
|
||||
} else {
|
||||
logger.lifecycle('Local configuration: absent local.properties; proceeding as normal.')
|
||||
}
|
||||
|
||||
if (localProperties != null) {
|
||||
String appServicesLocalPath = localProperties.getProperty(settingAppServicesPath);
|
||||
|
||||
if (appServicesLocalPath != null) {
|
||||
logger.lifecycle("Local configuration: substituting application-services modules from path: $appServicesLocalPath")
|
||||
|
||||
includeBuild(appServicesLocalPath) {
|
||||
dependencySubstitution {
|
||||
substitute module('org.mozilla.appservices:fxaclient') with project(':fxa-client-library')
|
||||
substitute module('org.mozilla.appservices:logins') with project(':logins-library')
|
||||
substitute module('org.mozilla.appservices:places') with project(':places-library')
|
||||
substitute module('org.mozilla.appservices:rustlog') with project(':rustlog-library')
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
logger.lifecycle("Local configuration: application-services substitution path missing. Specify it via '$settingAppServicesPath' setting.")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue