diff --git a/app/src/main/java/com/ztftrue/music/utils/TextActionModeCallback.kt b/app/src/main/java/com/ztftrue/music/utils/TextActionModeCallback.kt new file mode 100644 index 0000000..6a86274 --- /dev/null +++ b/app/src/main/java/com/ztftrue/music/utils/TextActionModeCallback.kt @@ -0,0 +1,103 @@ +package com.ztftrue.music.utils; + +import android.view.ActionMode +import android.view.Menu +import android.view.MenuItem +import androidx.annotation.VisibleForTesting +import androidx.compose.ui.geometry.Rect + +internal class TextActionModeCallback( + val onActionModeDestroy: (() -> Unit)? = null, + var rect: Rect = Rect.Zero, + var onCopyRequested: (() -> Unit)? = null, + var onPasteRequested: (() -> Unit)? = null, + var onCutRequested: (() -> Unit)? = null, + var onSelectAllRequested: (() -> Unit)? = null +) { + fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean { + requireNotNull(menu) + requireNotNull(mode) + + onCopyRequested?.let { + addMenuItem(menu, MenuItemOption.Copy) + } + onPasteRequested?.let { + addMenuItem(menu, MenuItemOption.Paste) + } + onCutRequested?.let { + addMenuItem(menu, MenuItemOption.Cut) + } + onSelectAllRequested?.let { + addMenuItem(menu, MenuItemOption.SelectAll) + } + return true + } + + // this method is called to populate new menu items when the actionMode was invalidated + fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean { + if (mode == null || menu == null) return false + updateMenuItems(menu) + // should return true so that new menu items are populated + return true + } + + fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean { + when (item!!.itemId) { + MenuItemOption.Copy.id -> onCopyRequested?.invoke() + MenuItemOption.Paste.id -> onPasteRequested?.invoke() + MenuItemOption.Cut.id -> onCutRequested?.invoke() + MenuItemOption.SelectAll.id -> onSelectAllRequested?.invoke() + else -> return false + } + mode?.finish() + return true + } + + fun onDestroyActionMode() { + onActionModeDestroy?.invoke() + } + + @VisibleForTesting + internal fun updateMenuItems(menu: Menu) { + addOrRemoveMenuItem(menu, MenuItemOption.Copy, onCopyRequested) + addOrRemoveMenuItem(menu, MenuItemOption.Paste, onPasteRequested) + addOrRemoveMenuItem(menu, MenuItemOption.Cut, onCutRequested) + addOrRemoveMenuItem(menu, MenuItemOption.SelectAll, onSelectAllRequested) + } + + internal fun addMenuItem(menu: Menu, item: MenuItemOption) { + menu.add(0, item.id, item.order, item.titleResource) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) + } + + private fun addOrRemoveMenuItem( + menu: Menu, + item: MenuItemOption, + callback: (() -> Unit)? + ) { + when { + callback != null && menu.findItem(item.id) == null -> addMenuItem(menu, item) + callback == null && menu.findItem(item.id) != null -> menu.removeItem(item.id) + } + } +} + +internal enum class MenuItemOption(val id: Int) { + Copy(0), + Paste(1), + Cut(2), + SelectAll(3); + + val titleResource: Int + get() = when (this) { + Copy -> android.R.string.copy + Paste -> android.R.string.paste + Cut -> android.R.string.cut + SelectAll -> android.R.string.selectAll + } + + /** + * This item will be shown before all items that have order greater than this value. + */ + val order = id +} \ No newline at end of file