Buran/app/src/main/java/corewala/buran/ui/bookmarks/BookmarksDialog.kt

250 lines
9.3 KiB
Kotlin

package corewala.buran.ui.bookmarks
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Handler
import android.os.Looper
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatDialog
import androidx.appcompat.widget.PopupMenu
import androidx.core.view.forEach
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.dialog_bookmarks.view.*
import corewala.buran.R
import corewala.buran.io.database.bookmarks.BookmarkEntry
import corewala.buran.io.database.bookmarks.BookmarksDatasource
import corewala.buran.ui.CREATE_BOOKMARK_EXPORT_FILE_REQ
import corewala.buran.ui.CREATE_BOOKMARK_IMPORT_FILE_REQ
import corewala.visible
import org.json.JSONObject
import java.io.BufferedReader
import java.io.InputStreamReader
import java.lang.StringBuilder
import java.net.URI
class BookmarksDialog(
context: Activity,
private val bookmarkDatasource: BookmarksDatasource,
onBookmark: (bookmarkEntry: BookmarkEntry) -> Unit
): AppCompatDialog(context, R.style.FSDialog) {
var bookmarksAdapter: BookmarksAdapter
var view: View = View.inflate(context, R.layout.dialog_bookmarks, null)
init {
setContentView(view)
view.bookmarks_toolbar.setNavigationIcon(R.drawable.vector_close)
view.bookmarks_toolbar.setNavigationOnClickListener {
dismiss()
}
view.bookmarks_toolbar.menu.forEach { menu ->
menu.setOnMenuItemClickListener { item ->
when(item.itemId){
R.id.menu_action_import_bookmarks -> {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.type = "application/json"
context.startActivityForResult(intent, CREATE_BOOKMARK_IMPORT_FILE_REQ)
}
R.id.menu_action_export_bookmarks -> {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "application/json"
intent.putExtra(Intent.EXTRA_TITLE, "buran_bookmarks.json")
context.startActivityForResult(intent, CREATE_BOOKMARK_EXPORT_FILE_REQ)
}
else -> {
}
}
true
}
}
//None as yet
view.bookmarks_toolbar.inflateMenu(R.menu.add_bookmarks)
view.bookmarks_toolbar.setOnMenuItemClickListener { _ ->
true
}
view.bookmarks_recycler.layoutManager = LinearLayoutManager(context)
bookmarksAdapter = BookmarksAdapter({ bookmark ->
//onBookmark
onBookmark(bookmark)
dismiss()
}){ view, bookmark, isFirst, isLast ->
//onOverflow
val bookmarkOverflow = PopupMenu(context, view)
bookmarkOverflow.inflate(R.menu.menu_bookmark)
if(isFirst) bookmarkOverflow.menu.removeItem(R.id.menu_bookmark_move_up)
if(isLast) bookmarkOverflow.menu.removeItem(R.id.menu_bookmark_move_down)
bookmarkOverflow.setOnMenuItemClickListener { menuItem ->
when(menuItem.itemId){
R.id.menu_bookmark_edit -> edit(bookmark)
R.id.menu_bookmark_delete -> delete(bookmark)
R.id.menu_bookmark_move_up -> moveUp(bookmark)
R.id.menu_bookmark_move_down -> moveDown(bookmark)
}
true
}
bookmarkOverflow.show()
}
view.bookmarks_recycler.adapter = bookmarksAdapter
bookmarkDatasource.get { bookmarks ->
Handler(Looper.getMainLooper()).post {
when {
bookmarks.isEmpty() -> view.bookmarks_empty_layout.visible(true)
else -> bookmarksAdapter.update(bookmarks)
}
}
}
}
private fun edit(bookmarkEntry: BookmarkEntry){
BookmarkDialog(
context,
BookmarkDialog.mode_edit,
null,
bookmarkEntry.uri.toString(),
bookmarkEntry.label
){ label, uri ->
bookmarkDatasource.update(bookmarkEntry, label, uri){
bookmarkDatasource.get { bookmarks ->
Handler(Looper.getMainLooper()).post {
bookmarksAdapter.update(bookmarks)
}
}
}
}.show()
}
/**
*
* Bookmark isn't actually deleted from the DB until the Snackbar disappears. Which is nice.
*
*/
private fun delete(bookmarkEntry: BookmarkEntry){
//OnDelete
bookmarksAdapter.hide(bookmarkEntry)
Snackbar.make(view, "Deleted ${bookmarkEntry.label}", Snackbar.LENGTH_SHORT).addCallback(
object : Snackbar.Callback() {
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) = when (event) {
BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_ACTION -> bookmarksAdapter.show(
bookmarkEntry
)
else -> bookmarkDatasource.delete(bookmarkEntry) {
Handler(Looper.getMainLooper()).post {
bookmarksAdapter.remove(bookmarkEntry)
}
}
}
}).setAction("Undo"){
//Action listener unused
}.show()
}
private fun moveUp(bookmarkEntry: BookmarkEntry){
bookmarkDatasource.moveUp(bookmarkEntry){
bookmarkDatasource.get { bookmarks ->
Handler(Looper.getMainLooper()).post {
bookmarksAdapter.update(bookmarks)
}
}
}
}
private fun moveDown(bookmarkEntry: BookmarkEntry){
bookmarkDatasource.moveDown(bookmarkEntry){
bookmarkDatasource.get { bookmarks ->
Handler(Looper.getMainLooper()).post {
bookmarksAdapter.update(bookmarks)
}
}
}
}
fun bookmarksExportFileReady(uri: Uri){
val model = BookmarksViewModel()
model.initialise(bookmarkDatasource){
Handler(Looper.getMainLooper()).post {
Toast.makeText(context, "Bookmarks Exported", Toast.LENGTH_SHORT).show()
}
}
model.exportBookmarks(context.contentResolver, uri)
}
fun bookmarksImportFileReady(uri: Uri){
context.contentResolver.openInputStream(uri).use{ inputStream ->
InputStreamReader(inputStream).use { streamReader ->
BufferedReader(streamReader).use { bufferedReader ->
val sb = StringBuilder()
var line: String?
while (bufferedReader.readLine().also { line = it } != null) {
sb.append(line).append('\n')
}
val bookmarksRawJson = sb.toString()
val bookmarksJson = JSONObject(bookmarksRawJson)
val bookmarks = bookmarksJson.getJSONArray("bookmarks")
val bookmarkEntries = arrayListOf<BookmarkEntry>()
var skipped = 0
var added = 0
repeat(bookmarks.length()){ index ->
val bookmark = bookmarks.getJSONObject(index)
val bookmarkLabel = bookmark.getString("label")
val bookmarkUri = bookmark.getString("uri")
println("Importing bookmark: $bookmarkLabel : $uri")
val existing = bookmarksAdapter.bookmarks.filter { entry ->
entry.uri.toString() == bookmarkUri
}
when {
existing.isNotEmpty() -> skipped++
else -> {
added++
bookmarkEntries.add(BookmarkEntry(-1, bookmarkLabel, URI.create(bookmarkUri), index))
}
}
}
bookmarkDatasource.add(bookmarkEntries.toTypedArray()){
bookmarkDatasource.get { bookmarks ->
Handler(Looper.getMainLooper()).post {
view.bookmarks_empty_layout.visible(false)
bookmarksAdapter.update(bookmarks)
when {
skipped > 0 -> {
Toast.makeText(context, "$added bookmarks imported ($skipped duplicates)", Toast.LENGTH_SHORT).show()
}
else -> Toast.makeText(context, "$added bookmarks imported", Toast.LENGTH_SHORT).show()
}
}
}
}
}
}
}
}
}