1
0
Fork 0
fenix/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt

182 lines
7.0 KiB
Kotlin

/* 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
}
}