Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Support batch deletion in Memo app #56

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/src/main/java/dev/arkbuilders/arkmemo/graphics/SVG.kt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ class SVG {

pathData.split(COMMA).forEach {
val command = it.trim()
if (command.isEmpty()) return@forEach
when (command.first()) {
SVGCommand.MoveTo.CODE -> {
commands.addLast(SVGCommand.MoveTo.fromString(command))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ data class GraphicNote(
@IgnoredOnParcel
val svg: SVG? = null,
@IgnoredOnParcel
override var resource: Resource? = null
override var resource: Resource? = null,
override var selected: Boolean = false
) : Note, Parcelable
1 change: 1 addition & 0 deletions app/src/main/java/dev/arkbuilders/arkmemo/models/Note.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ interface Note {
val title: String
val description: String
var resource: Resource?
var selected: Boolean
}
3 changes: 2 additions & 1 deletion app/src/main/java/dev/arkbuilders/arkmemo/models/TextNote.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ data class TextNote (
override val description: String = "",
val text: String = "",
@IgnoredOnParcel
override var resource: Resource? = null
override var resource: Resource? = null,
override var selected: Boolean = false
): Note, Parcelable
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ class VoiceNote(
@IgnoredOnParcel
var path: Path = createTempFile(),
@IgnoredOnParcel
override var resource: Resource? = null
override var resource: Resource? = null,
override var selected: Boolean = false
): Note, Parcelable
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ interface NotesRepo<Note> {

suspend fun read(): List<Note>

suspend fun delete(note: Note)
suspend fun delete(notes: List<Note>)
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,14 @@ class NotesRepoHelper @Inject constructor(
return UserNoteProperties(title, description)
}

suspend fun deleteNote(note: Note): Unit = withContext(Dispatchers.IO) {
val path = root.resolve("${note.resource?.name}")
path.deleteIfExists()
propertiesStorage.remove(note.resource?.id!!)
propertiesStorage.persist()
Log.d("repo", "${note.resource?.name!!} has been deleted")
suspend fun deleteNote(notes: List<Note>): Unit = withContext(Dispatchers.IO) {
notes.forEach { note ->
val path = root.resolve("${note.resource?.name}")
path.deleteIfExists()
propertiesStorage.remove(note.resource?.id!!)
propertiesStorage.persist()
Log.d("repo", "${note.resource?.name!!} has been deleted")
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ class GraphicNotesRepo @Inject constructor(
write(note) { callback(it) }
}

override suspend fun delete(note: GraphicNote) = withContext(iODispatcher) {
helper.deleteNote(note)
override suspend fun delete(notes: GraphicNote) = withContext(iODispatcher) {
helper.deleteNote(notes)
}

override suspend fun read(): List<GraphicNote> = withContext(iODispatcher) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ class TextNotesRepo @Inject constructor(
write(note) { callback(it) }
}

override suspend fun delete(note: TextNote) {
helper.deleteNote(note)
override suspend fun delete(notes: List<TextNote>) {
helper.deleteNote(notes)
}

override suspend fun read(): List<TextNote> = withContext(iODispatcher) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ class VoiceNotesRepo @Inject constructor(
readStorage()
}

override suspend fun delete(note: VoiceNote) {
helper.deleteNote(note)
override suspend fun delete(notes: List<VoiceNote>) {
helper.deleteNote(notes)
}

override suspend fun save(note: VoiceNote, callback: (SaveNoteResult) -> Unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import android.content.Context
import android.content.Context.CLIPBOARD_SERVICE
import android.Manifest
import android.content.Intent
import android.content.res.ColorStateList
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.IdRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import by.kirich1409.viewbindingdelegate.viewBinding
Expand All @@ -21,6 +24,7 @@ import dev.arkbuilders.arkmemo.contracts.PermissionContract
import dev.arkbuilders.arkmemo.databinding.ActivityMainBinding
import dev.arkbuilders.arkmemo.ui.dialogs.FilePickerDialog
import dev.arkbuilders.arkmemo.preferences.MemoPreferences
import dev.arkbuilders.arkmemo.ui.dialogs.NoteDeleteDialog
import dev.arkbuilders.arkmemo.ui.fragments.EditTextNotesFragment
import dev.arkbuilders.arkmemo.ui.fragments.NotesFragment
import dev.arkbuilders.arkmemo.ui.fragments.SettingsFragment
Expand All @@ -42,6 +46,7 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
var fragment: Fragment = NotesFragment()

private var shouldRecord = false
private var mIsActionMode = false
private val audioRecordingPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
shouldRecord = isGranted
Expand Down Expand Up @@ -108,9 +113,32 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {

override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.main_menu, menu)
Log.d("tuancoltech", "onCreateOptionsMenu")
this.menu = menu
if(fragment.tag != NotesFragment.TAG)
if(fragment.tag != NotesFragment.TAG) {
showSettingsButton(false)
toggleBatchDeleteOption(false)
}
else {
toggleBatchDeleteOption(show = true)
}

if (mIsActionMode) {
menu.findItem(R.id.settings).setVisible(false)
menu.findItem(R.id.cancel).setVisible(true)
menu.findItem(R.id.delete).setIcon(R.drawable.ic_confirm_delete)
} else {
menu.findItem(R.id.settings).setVisible(true)
menu.findItem(R.id.cancel).setVisible(false)
menu.findItem(R.id.delete)
.setIcon(ContextCompat.getDrawable(this@MainActivity, R.drawable.delete)
.apply {
this?.setTintList(ColorStateList.valueOf(
ContextCompat.getColor(this@MainActivity, R.color.white))
)
})
}

return true
}

Expand All @@ -125,17 +153,54 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
fragment = SettingsFragment()
replaceFragment(fragment, SettingsFragment.TAG)
}

R.id.delete -> {
if (mIsActionMode) {
Log.d("tuancoltech", "Confirm delete item clicked!")
NoteDeleteDialog(
mCustomMessage = getString(R.string.ark_memo_delete_all_warn),
mPositiveAction = {
Log.d("tuancoltech", "on OK clicked")
}).show(supportFragmentManager, NoteDeleteDialog.TAG)

} else {
Log.d("tuancoltech", "delete item clicked!")
showBatchDeleteMode()
}
}

R.id.cancel -> {
// toggleBatchDeleteOption()
Log.d("tuancoltech", "Cancel action mode item clicked! mIsActionMode: " + mIsActionMode)
showBatchDeleteMode()
}
}
return true
}

private fun showBatchDeleteMode() {
if (fragment.tag == NotesFragment.TAG) {
(fragment as? NotesFragment)?.toggleActionMode()
mIsActionMode = !mIsActionMode
invalidateOptionsMenu()
}
}

fun showSettingsButton(show: Boolean = true) {
if(menu != null) {
val settingsItem = menu?.findItem(R.id.settings)
settingsItem?.isVisible = show
}
}

fun toggleBatchDeleteOption(show: Boolean = false) {
Log.d("tuancoltech", "showBatchDeleteOption show: " + show + ". menu: " + menu)
if(menu != null) {
val deleteItem = menu?.findItem(R.id.delete)
deleteItem?.isVisible = show
}
}

fun showProgressBar(show: Boolean) {
binding.progressBar.isVisible = show
}
Expand All @@ -144,6 +209,7 @@ class MainActivity : AppCompatActivity(R.layout.activity_main) {
title = getString(R.string.edit_note)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
showSettingsButton(false)
toggleBatchDeleteOption(false)
}

companion object{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package dev.arkbuilders.arkmemo.ui.adapters

import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CompoundButton
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.isVisible
Expand All @@ -23,7 +25,9 @@ import dev.arkbuilders.arkmemo.ui.fragments.EditTextNotesFragment
import dev.arkbuilders.arkmemo.ui.viewmodels.ArkMediaPlayerSideEffect
import dev.arkbuilders.arkmemo.ui.viewmodels.ArkMediaPlayerState
import dev.arkbuilders.arkmemo.utils.getAutoTitle
import dev.arkbuilders.arkmemo.utils.gone
import dev.arkbuilders.arkmemo.utils.replaceFragment
import dev.arkbuilders.arkmemo.utils.visible

class NotesListAdapter(
private val notes: List<Note>,
Expand All @@ -32,6 +36,7 @@ class NotesListAdapter(

private lateinit var activity: MainActivity
private lateinit var fragmentManager: FragmentManager
private var mActionMode = false

lateinit var observeItemSideEffect: () -> ArkMediaPlayerSideEffect
lateinit var observeItemState: () -> ArkMediaPlayerState
Expand Down Expand Up @@ -62,6 +67,16 @@ class NotesListAdapter(
handleMediaPlayerSideEffect(observeItemSideEffect(), holder)
}
}

holder.cbDelete.isChecked = note.selected
Log.i("tuancoltech", "onBindViewHolder pos: " + position + ". mActionMode: " + mActionMode)
if (mActionMode) {
holder.btnDeleteNote.gone()
holder.cbDelete.visible()
} else {
holder.btnDeleteNote.visible()
holder.cbDelete.gone()
}
}

override fun getItemCount() = notes.size
Expand Down Expand Up @@ -104,14 +119,24 @@ class NotesListAdapter(
holder.btnPlayPause.setImageDrawable(playIcon)
}

inner class NoteViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
fun toggleActionMode() {
mActionMode = !mActionMode
Log.v("tuancoltech", "toggleActionMode mActionMode: " + mActionMode)
notes.forEach { it.selected = false }
notifyDataSetChanged()
}

inner class NoteViewHolder(itemView: View)
: RecyclerView.ViewHolder(itemView) {
private val binding by viewBinding {
NoteBinding.bind(itemView)
}

val title = binding.noteTitle
val date = binding.noteDate
val btnPlayPause = binding.btnPlayPause
val btnDeleteNote = binding.deleteNote
val cbDelete = binding.cbDelete

private val clickNoteToEditListener = View.OnClickListener {
var tag = EditTextNotesFragment.TAG
Expand All @@ -135,9 +160,18 @@ class NotesListAdapter(
.show(fragmentManager, NoteDeleteDialog.TAG)
}

private val noteCheckedListener = CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
notes[bindingAdapterPosition].selected = isChecked
Log.d("tuancoltech", "noteCheckedListener pos: " + bindingAdapterPosition + ". isChecked: " + isChecked)
// notifyItemChanged(bindingAdapterPosition)
// onCheckedForDelete?.invoke(bindingAdapterPosition)
// onSelectForDelete.invoke(bindingAdapterPosition)
}

init {
binding.theNote.setOnClickListener(clickNoteToEditListener)
binding.deleteNote.setOnClickListener(deleteNoteClickListener)
binding.cbDelete.setOnCheckedChangeListener(noteCheckedListener)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import dev.arkbuilders.arkmemo.models.Note
import dev.arkbuilders.arkmemo.ui.fragments.deleteNote
import dev.arkbuilders.arkmemo.ui.views.toast

class NoteDeleteDialog: DialogFragment() {
class NoteDeleteDialog(private val mCustomMessage: String? = null,
private val mPositiveAction: (() -> Unit)? = null): DialogFragment() {

private var note: Note? = null
private var notes: List<Note>? = null

fun setNoteToBeDeleted(note: Note): NoteDeleteDialog {
this.note = note
fun setNoteToBeDeleted(notes: List<Note>): NoteDeleteDialog {
this.notes = notes
return this
}

Expand All @@ -26,11 +27,13 @@ class NoteDeleteDialog: DialogFragment() {
dialog.cancel()
}
.setPositiveButton(R.string.ark_memo_ok){ dialog, _ ->
if(note != null) {
parentFragment?.deleteNote(note!!)
if(notes != null) {
parentFragment?.deleteNote(notes!!)
toast(requireContext(), getString(R.string.note_deleted))
dialog.cancel()
}

mPositiveAction?.invoke()
}
return builder.create()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class ArkRecorderFragment: Fragment(R.layout.fragment_edit_notes) {
}

private fun initUI() {
activity.toggleBatchDeleteOption(false)
val defaultTitle = getString(
R.string.ark_memo_voice_note,
LocalDate.now().format(DateTimeFormatter.ISO_DATE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class EditGraphicNotesFragment: BaseEditNoteFragment() {
activity.title = getString(R.string.edit_note)
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
activity.showSettingsButton(false)
activity.toggleBatchDeleteOption(false)

noteTitle.hint = getString(R.string.hint_new_graphical_note)
noteTitle.setText(title)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class EditTextNotesFragment: BaseEditNoteFragment() {
activity.title = getString(R.string.edit_note)
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
activity.showSettingsButton(false)
activity.toggleBatchDeleteOption(false)

noteTitle.setText(this.note.title)
noteTitle.addTextChangedListener(noteTitleChangeListener)
Expand Down
Loading
Loading