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() 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() } } } } } } } } }