For #3813 - Create a save button for bookmark editing
parent
db875ac929
commit
e291c6905c
|
@ -10,34 +10,23 @@ import android.view.Menu
|
||||||
import android.view.MenuInflater
|
import android.view.MenuInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.EditText
|
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.core.widget.doOnTextChanged
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.Navigation
|
import androidx.navigation.Navigation
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
import kotlinx.android.synthetic.main.fragment_edit_bookmark.bookmarkNameEdit
|
import kotlinx.android.synthetic.main.fragment_edit_bookmark.bookmarkNameEdit
|
||||||
import kotlinx.android.synthetic.main.fragment_edit_bookmark.bookmarkParentFolderSelector
|
import kotlinx.android.synthetic.main.fragment_edit_bookmark.bookmarkParentFolderSelector
|
||||||
import kotlinx.android.synthetic.main.fragment_edit_bookmark.bookmarkUrlEdit
|
import kotlinx.android.synthetic.main.fragment_edit_bookmark.bookmarkUrlEdit
|
||||||
import kotlinx.android.synthetic.main.fragment_edit_bookmark.bookmarkUrlLabel
|
import kotlinx.android.synthetic.main.fragment_edit_bookmark.bookmarkUrlLabel
|
||||||
|
import kotlinx.android.synthetic.main.fragment_edit_bookmark.progress_bar_bookmark
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.FlowPreview
|
|
||||||
import kotlinx.coroutines.InternalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.channels.awaitClose
|
|
||||||
import kotlinx.coroutines.flow.FlowCollector
|
|
||||||
import kotlinx.coroutines.flow.channelFlow
|
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.debounce
|
|
||||||
import kotlinx.coroutines.flow.drop
|
|
||||||
import kotlinx.coroutines.flow.filter
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import mozilla.appservices.places.UrlParseFailed
|
import mozilla.appservices.places.UrlParseFailed
|
||||||
import mozilla.components.concept.storage.BookmarkInfo
|
import mozilla.components.concept.storage.BookmarkInfo
|
||||||
|
@ -45,7 +34,6 @@ import mozilla.components.concept.storage.BookmarkNode
|
||||||
import mozilla.components.concept.storage.BookmarkNodeType
|
import mozilla.components.concept.storage.BookmarkNodeType
|
||||||
import mozilla.components.support.ktx.android.content.getColorFromAttr
|
import mozilla.components.support.ktx.android.content.getColorFromAttr
|
||||||
import mozilla.components.support.ktx.android.view.hideKeyboard
|
import mozilla.components.support.ktx.android.view.hideKeyboard
|
||||||
import mozilla.components.support.ktx.android.view.toScope
|
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.components.FenixSnackbar
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
@ -61,9 +49,6 @@ import org.mozilla.fenix.library.bookmarks.DesktopFolders
|
||||||
/**
|
/**
|
||||||
* Menu to edit the name, URL, and location of a bookmark item.
|
* Menu to edit the name, URL, and location of a bookmark item.
|
||||||
*/
|
*/
|
||||||
@FlowPreview
|
|
||||||
@ExperimentalCoroutinesApi
|
|
||||||
@InternalCoroutinesApi // Cannot use collect as a lambda due to Kotlin SAM conversion issue
|
|
||||||
class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
|
class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
|
||||||
|
|
||||||
private lateinit var guidToEdit: String
|
private lateinit var guidToEdit: String
|
||||||
|
@ -78,9 +63,8 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onResume()
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
initToolbar()
|
initToolbar()
|
||||||
|
|
||||||
guidToEdit = EditBookmarkFragmentArgs.fromBundle(arguments!!).guidToEdit
|
guidToEdit = EditBookmarkFragmentArgs.fromBundle(arguments!!).guidToEdit
|
||||||
|
@ -111,26 +95,20 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
|
||||||
bookmarkNode?.let { bookmarkNode ->
|
bookmarkNode?.let { bookmarkNode ->
|
||||||
bookmarkNameEdit.setText(bookmarkNode.title)
|
bookmarkNameEdit.setText(bookmarkNode.title)
|
||||||
bookmarkUrlEdit.setText(bookmarkNode.url)
|
bookmarkUrlEdit.setText(bookmarkNode.url)
|
||||||
|
|
||||||
if (sharedViewModel.selectedFolder != null && bookmarkNode.title != null) {
|
|
||||||
updateBookmarkNode(bookmarkNode.title, bookmarkNode.url)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bookmarkParent?.let { node ->
|
bookmarkParent?.let { node ->
|
||||||
bookmarkParentFolderSelector.text = node.title
|
bookmarkParentFolderSelector.text = node.title
|
||||||
bookmarkParentFolderSelector.setOnClickListener {
|
bookmarkParentFolderSelector.setOnClickListener {
|
||||||
sharedViewModel.selectedFolder = null
|
sharedViewModel.selectedFolder = null
|
||||||
nav(
|
nav(
|
||||||
R.id.bookmarkEditFragment,
|
R.id.bookmarkEditFragment,
|
||||||
EditBookmarkFragmentDirections
|
EditBookmarkFragmentDirections
|
||||||
.actionBookmarkEditFragmentToBookmarkSelectFolderFragment(null)
|
.actionBookmarkEditFragmentToBookmarkSelectFolderFragment(null)
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
updateBookmarkFromTextChanges()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initToolbar() {
|
private fun initToolbar() {
|
||||||
|
@ -149,31 +127,7 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
bookmarkNameEdit.hideKeyboard()
|
bookmarkNameEdit.hideKeyboard()
|
||||||
bookmarkUrlEdit.hideKeyboard()
|
bookmarkUrlEdit.hideKeyboard()
|
||||||
}
|
progress_bar_bookmark.visibility = View.GONE
|
||||||
|
|
||||||
private fun updateBookmarkFromTextChanges() {
|
|
||||||
fun EditText.observe() = channelFlow {
|
|
||||||
this@observe.doOnTextChanged { text, _, _, _ ->
|
|
||||||
runBlocking { send(text.toString()) }
|
|
||||||
}
|
|
||||||
awaitClose()
|
|
||||||
}
|
|
||||||
|
|
||||||
val nameText = bookmarkNameEdit.observe()
|
|
||||||
val urlText = bookmarkUrlEdit.observe()
|
|
||||||
|
|
||||||
bookmarkNameEdit.toScope().launch {
|
|
||||||
nameText.combine(urlText) { name, url -> name to url }
|
|
||||||
.drop(1)
|
|
||||||
.filter { (name) -> name.isNotBlank() }
|
|
||||||
.debounce(timeoutMillis = debouncePeriodInMs)
|
|
||||||
// TODO convert collect to lambda when Kotlin SAM conversions are supported
|
|
||||||
.collect(object : FlowCollector<Pair<String, String>> {
|
|
||||||
override suspend fun emit(value: Pair<String, String>) {
|
|
||||||
updateBookmarkNode(value.first, value.second)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
@ -186,6 +140,11 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
|
||||||
displayDeleteBookmarkDialog()
|
displayDeleteBookmarkDialog()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
R.id.save_bookmark_button -> {
|
||||||
|
updateBookmarkFromTextChanges()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
else -> super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,7 +168,8 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
|
||||||
bookmarkNode?.let { bookmark ->
|
bookmarkNode?.let { bookmark ->
|
||||||
FenixSnackbar.makeWithToolbarPadding(activity.getRootView()!!)
|
FenixSnackbar.makeWithToolbarPadding(activity.getRootView()!!)
|
||||||
.setText(
|
.setText(
|
||||||
getString(R.string.bookmark_deletion_snackbar_message,
|
getString(
|
||||||
|
R.string.bookmark_deletion_snackbar_message,
|
||||||
bookmark.url?.toShortUrl(context.components.publicSuffixList)
|
bookmark.url?.toShortUrl(context.components.publicSuffixList)
|
||||||
?: bookmark.title
|
?: bookmark.title
|
||||||
)
|
)
|
||||||
|
@ -225,6 +185,13 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateBookmarkFromTextChanges() {
|
||||||
|
progress_bar_bookmark.visibility = View.VISIBLE
|
||||||
|
val nameText = bookmarkNameEdit.text.toString()
|
||||||
|
val urlText = bookmarkUrlEdit.text.toString()
|
||||||
|
updateBookmarkNode(nameText, urlText)
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateBookmarkNode(title: String?, url: String?) {
|
private fun updateBookmarkNode(title: String?, url: String?) {
|
||||||
lifecycleScope.launch(IO) {
|
lifecycleScope.launch(IO) {
|
||||||
try {
|
try {
|
||||||
|
@ -251,9 +218,7 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
progress_bar_bookmark.visibility = View.INVISIBLE
|
||||||
|
findNavController().popBackStack()
|
||||||
companion object {
|
|
||||||
private const val debouncePeriodInMs = 500L
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,17 @@
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progress_bar_bookmark"
|
||||||
|
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
|
||||||
|
android:indeterminate="true"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="8dp"
|
||||||
|
android:translationY="-3dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/bookmark_name_label"
|
android:id="@+id/bookmark_name_label"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -4,6 +4,15 @@
|
||||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu 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">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/save_bookmark_button"
|
||||||
|
android:icon= "@drawable/mozac_ic_check"
|
||||||
|
app:iconTint="?primaryText"
|
||||||
|
android:title="@string/bookmark_menu_save_button"
|
||||||
|
android:contentDescription="@string/bookmark_menu_save_button"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/delete_bookmark_button"
|
android:id="@+id/delete_bookmark_button"
|
||||||
android:icon="@drawable/ic_delete"
|
android:icon="@drawable/ic_delete"
|
||||||
|
|
|
@ -498,6 +498,8 @@
|
||||||
<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>
|
||||||
|
<!--Bookmark overflow menu save button -->
|
||||||
|
<string name="bookmark_menu_save_button">Save</string>
|
||||||
<!-- Bookmark multi select title in app bar
|
<!-- Bookmark multi select title in app bar
|
||||||
The first parameter is the number of bookmarks selected -->
|
The first parameter is the number of bookmarks selected -->
|
||||||
<string name="bookmarks_multi_select_title">%1$d selected</string>
|
<string name="bookmarks_multi_select_title">%1$d selected</string>
|
||||||
|
|
260
docs/metrics.md
260
docs/metrics.md
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue