mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Custom Toolbar action
This commit is contained in:
@@ -61,8 +61,7 @@ import com.kunzisoft.keepass.settings.PreferencesUtil
|
|||||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||||
import com.kunzisoft.keepass.utils.MenuUtil
|
import com.kunzisoft.keepass.utils.MenuUtil
|
||||||
import com.kunzisoft.keepass.view.AddNodeButtonView
|
import com.kunzisoft.keepass.view.AddNodeButtonView
|
||||||
import com.kunzisoft.keepass.view.collapse
|
import com.kunzisoft.keepass.view.ToolbarAction
|
||||||
import com.kunzisoft.keepass.view.expand
|
|
||||||
|
|
||||||
class GroupActivity : LockingActivity(),
|
class GroupActivity : LockingActivity(),
|
||||||
GroupEditDialogFragment.EditGroupListener,
|
GroupEditDialogFragment.EditGroupListener,
|
||||||
@@ -75,7 +74,7 @@ class GroupActivity : LockingActivity(),
|
|||||||
// Views
|
// Views
|
||||||
private var toolbar: Toolbar? = null
|
private var toolbar: Toolbar? = null
|
||||||
private var searchTitleView: View? = null
|
private var searchTitleView: View? = null
|
||||||
private var toolbarPaste: Toolbar? = null
|
private var toolbarAction: ToolbarAction? = null
|
||||||
private var iconView: ImageView? = null
|
private var iconView: ImageView? = null
|
||||||
private var numberChildrenView: TextView? = null
|
private var numberChildrenView: TextView? = null
|
||||||
private var modeTitleView: TextView? = null
|
private var modeTitleView: TextView? = null
|
||||||
@@ -116,20 +115,19 @@ class GroupActivity : LockingActivity(),
|
|||||||
toolbar = findViewById(R.id.toolbar)
|
toolbar = findViewById(R.id.toolbar)
|
||||||
searchTitleView = findViewById(R.id.search_title)
|
searchTitleView = findViewById(R.id.search_title)
|
||||||
groupNameView = findViewById(R.id.group_name)
|
groupNameView = findViewById(R.id.group_name)
|
||||||
toolbarPaste = findViewById(R.id.toolbar_paste)
|
toolbarAction = findViewById(R.id.toolbar_action)
|
||||||
modeTitleView = findViewById(R.id.mode_title_view)
|
modeTitleView = findViewById(R.id.mode_title_view)
|
||||||
|
|
||||||
toolbar?.title = ""
|
toolbar?.title = ""
|
||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
|
|
||||||
toolbarPaste?.inflateMenu(R.menu.node_paste_menu)
|
/*
|
||||||
toolbarPaste?.setNavigationIcon(R.drawable.ic_arrow_left_white_24dp)
|
toolbarAction?.setNavigationOnClickListener {
|
||||||
toolbarPaste?.collapse(false)
|
toolbarAction?.collapse()
|
||||||
toolbarPaste?.setNavigationOnClickListener {
|
|
||||||
toolbarPaste?.collapse()
|
|
||||||
mNodeToCopy = null
|
mNodeToCopy = null
|
||||||
mNodeToMove = null
|
mNodeToMove = null
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Focus view to reinitialize timeout
|
// Focus view to reinitialize timeout
|
||||||
resetAppTimeoutWhenViewFocusedOrChanged(addNodeButtonView)
|
resetAppTimeoutWhenViewFocusedOrChanged(addNodeButtonView)
|
||||||
@@ -139,13 +137,13 @@ class GroupActivity : LockingActivity(),
|
|||||||
if (savedInstanceState.containsKey(OLD_GROUP_TO_UPDATE_KEY))
|
if (savedInstanceState.containsKey(OLD_GROUP_TO_UPDATE_KEY))
|
||||||
mOldGroupToUpdate = savedInstanceState.getParcelable(OLD_GROUP_TO_UPDATE_KEY)
|
mOldGroupToUpdate = savedInstanceState.getParcelable(OLD_GROUP_TO_UPDATE_KEY)
|
||||||
if (savedInstanceState.containsKey(NODE_TO_COPY_KEY)) {
|
if (savedInstanceState.containsKey(NODE_TO_COPY_KEY)) {
|
||||||
mNodeToCopy = savedInstanceState.getParcelable(NODE_TO_COPY_KEY)
|
// mNodeToCopy = savedInstanceState.getParcelable(NODE_TO_COPY_KEY)
|
||||||
toolbarPaste?.setOnMenuItemClickListener(OnCopyMenuItemClickListener())
|
// toolbarAction?.setOnMenuItemClickListener(OnCopyMenuItemClickListener())
|
||||||
toolbarPaste?.expand(false)
|
// toolbarAction?.expand(false)
|
||||||
} else if (savedInstanceState.containsKey(NODE_TO_MOVE_KEY)) {
|
} else if (savedInstanceState.containsKey(NODE_TO_MOVE_KEY)) {
|
||||||
mNodeToMove = savedInstanceState.getParcelable(NODE_TO_MOVE_KEY)
|
// mNodeToMove = savedInstanceState.getParcelable(NODE_TO_MOVE_KEY)
|
||||||
toolbarPaste?.setOnMenuItemClickListener(OnMoveMenuItemClickListener())
|
// toolbarAction?.setOnMenuItemClickListener(OnMoveMenuItemClickListener())
|
||||||
toolbarPaste?.expand(false)
|
// toolbarAction?.expand(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,34 +443,29 @@ class GroupActivity : LockingActivity(),
|
|||||||
|
|
||||||
private var actionNodeMode: ActionMode? = null
|
private var actionNodeMode: ActionMode? = null
|
||||||
|
|
||||||
private fun closeNodeActionBar() {
|
|
||||||
actionNodeMode?.finish()
|
|
||||||
actionNodeMode = null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNodeSelected(nodes: List<NodeVersioned>): Boolean {
|
override fun onNodeSelected(nodes: List<NodeVersioned>): Boolean {
|
||||||
if (nodes.isNotEmpty()) {
|
if (nodes.isNotEmpty()) {
|
||||||
if (actionNodeMode == null) {
|
if (actionNodeMode == null) {
|
||||||
mListNodesFragment?.actionNodesCallback(nodes, this)?.let {
|
mListNodesFragment?.actionNodesCallback(nodes, this)?.let {
|
||||||
actionNodeMode = startSupportActionMode(it)
|
actionNodeMode = toolbarAction?.startSupportActionMode(it)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
actionNodeMode?.invalidate()
|
actionNodeMode?.invalidate()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
closeNodeActionBar()
|
actionNodeMode?.finish()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOpenMenuClick(node: NodeVersioned): Boolean {
|
override fun onOpenMenuClick(node: NodeVersioned): Boolean {
|
||||||
closeNodeActionBar()
|
actionNodeMode?.finish()
|
||||||
onNodeClick(node)
|
onNodeClick(node)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onEditMenuClick(node: NodeVersioned): Boolean {
|
override fun onEditMenuClick(node: NodeVersioned): Boolean {
|
||||||
closeNodeActionBar()
|
actionNodeMode?.finish()
|
||||||
when (node.type) {
|
when (node.type) {
|
||||||
Type.GROUP -> {
|
Type.GROUP -> {
|
||||||
mOldGroupToUpdate = node as GroupVersioned
|
mOldGroupToUpdate = node as GroupVersioned
|
||||||
@@ -486,35 +479,12 @@ class GroupActivity : LockingActivity(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCopyMenuClick(nodes: List<NodeVersioned>): Boolean {
|
override fun onCopyMenuClick(nodes: List<NodeVersioned>): Boolean {
|
||||||
|
actionNodeMode?.invalidate()
|
||||||
|
|
||||||
val node = nodes[0]
|
val node = nodes[0]
|
||||||
closeNodeActionBar()
|
|
||||||
// TODO Multiple copy
|
// TODO Multiple copy
|
||||||
toolbarPaste?.expand()
|
|
||||||
mNodeToCopy = node
|
mNodeToCopy = node
|
||||||
toolbarPaste?.setOnMenuItemClickListener(OnCopyMenuItemClickListener())
|
return true
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class OnCopyMenuItemClickListener : Toolbar.OnMenuItemClickListener {
|
|
||||||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
|
||||||
toolbarPaste?.collapse()
|
|
||||||
|
|
||||||
when (item.itemId) {
|
|
||||||
R.id.menu_paste -> {
|
|
||||||
when (mNodeToCopy?.type) {
|
|
||||||
Type.GROUP -> Log.e(TAG, "Copy not allowed for group")
|
|
||||||
Type.ENTRY -> {
|
|
||||||
mCurrentGroup?.let { currentGroup ->
|
|
||||||
copyEntry(mNodeToCopy as EntryVersioned, currentGroup)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mNodeToCopy = null
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun copyEntry(entryToCopy: EntryVersioned, newParent: GroupVersioned) {
|
private fun copyEntry(entryToCopy: EntryVersioned, newParent: GroupVersioned) {
|
||||||
@@ -529,39 +499,12 @@ class GroupActivity : LockingActivity(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onMoveMenuClick(nodes: List<NodeVersioned>): Boolean {
|
override fun onMoveMenuClick(nodes: List<NodeVersioned>): Boolean {
|
||||||
|
actionNodeMode?.invalidate()
|
||||||
|
|
||||||
val node = nodes[0]
|
val node = nodes[0]
|
||||||
closeNodeActionBar()
|
|
||||||
// TODO multiple move
|
// TODO multiple move
|
||||||
toolbarPaste?.expand()
|
|
||||||
mNodeToMove = node
|
mNodeToMove = node
|
||||||
toolbarPaste?.setOnMenuItemClickListener(OnMoveMenuItemClickListener())
|
return true
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class OnMoveMenuItemClickListener : Toolbar.OnMenuItemClickListener {
|
|
||||||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
|
||||||
toolbarPaste?.collapse()
|
|
||||||
|
|
||||||
when (item.itemId) {
|
|
||||||
R.id.menu_paste -> {
|
|
||||||
when (mNodeToMove?.type) {
|
|
||||||
Type.GROUP -> {
|
|
||||||
mCurrentGroup?.let { currentGroup ->
|
|
||||||
moveGroup(mNodeToMove as GroupVersioned, currentGroup)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type.ENTRY -> {
|
|
||||||
mCurrentGroup?.let { currentGroup ->
|
|
||||||
moveEntry(mNodeToMove as EntryVersioned, currentGroup)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mNodeToMove = null
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun moveGroup(groupToMove: GroupVersioned, newParent: GroupVersioned) {
|
private fun moveGroup(groupToMove: GroupVersioned, newParent: GroupVersioned) {
|
||||||
@@ -622,6 +565,42 @@ class GroupActivity : LockingActivity(),
|
|||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPasteMenuClick(pasteMode: ListNodesFragment.PasteMode?,
|
||||||
|
nodes: List<NodeVersioned>): Boolean {
|
||||||
|
when (pasteMode) {
|
||||||
|
ListNodesFragment.PasteMode.PASTE_FROM_COPY -> {
|
||||||
|
// COPY
|
||||||
|
when (mNodeToCopy?.type) {
|
||||||
|
Type.GROUP -> Log.e(TAG, "Copy not allowed for group")
|
||||||
|
Type.ENTRY -> {
|
||||||
|
mCurrentGroup?.let { currentGroup ->
|
||||||
|
copyEntry(mNodeToCopy as EntryVersioned, currentGroup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mNodeToCopy = null
|
||||||
|
}
|
||||||
|
|
||||||
|
ListNodesFragment.PasteMode.PASTE_FROM_MOVE -> {
|
||||||
|
// Move
|
||||||
|
when (mNodeToMove?.type) {
|
||||||
|
Type.GROUP -> {
|
||||||
|
mCurrentGroup?.let { currentGroup ->
|
||||||
|
moveGroup(mNodeToMove as GroupVersioned, currentGroup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Type.ENTRY -> {
|
||||||
|
mCurrentGroup?.let { currentGroup ->
|
||||||
|
moveEntry(mNodeToMove as EntryVersioned, currentGroup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mNodeToMove = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
// Refresh the elements
|
// Refresh the elements
|
||||||
@@ -845,7 +824,7 @@ class GroupActivity : LockingActivity(),
|
|||||||
&& positionNode != null) {
|
&& positionNode != null) {
|
||||||
mListNodesFragment?.removeNodeAt(positionNode)
|
mListNodesFragment?.removeNodeAt(positionNode)
|
||||||
} else {
|
} else {
|
||||||
// else use the old Node that was the entry unchanged with the old parent
|
// Use the old Node that was the entry unchanged with the old parent
|
||||||
actionNodeValues.oldNode?.let { oldNode ->
|
actionNodeValues.oldNode?.let { oldNode ->
|
||||||
mListNodesFragment?.removeNode(oldNode)
|
mListNodesFragment?.removeNode(oldNode)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
|
|||||||
private set
|
private set
|
||||||
private var mAdapter: NodeAdapter? = null
|
private var mAdapter: NodeAdapter? = null
|
||||||
|
|
||||||
private var nodeActionMode = false
|
private var nodeActionSelectionMode = false
|
||||||
private val listNodesSelected = LinkedList<NodeVersioned>()
|
private val listActionNodes = LinkedList<NodeVersioned>()
|
||||||
|
|
||||||
private var notFoundView: View? = null
|
private var notFoundView: View? = null
|
||||||
private var isASearchResult: Boolean = false
|
private var isASearchResult: Boolean = false
|
||||||
@@ -100,38 +100,30 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
|
|||||||
mAdapter?.apply {
|
mAdapter?.apply {
|
||||||
setOnNodeClickListener(object : NodeAdapter.NodeClickCallback {
|
setOnNodeClickListener(object : NodeAdapter.NodeClickCallback {
|
||||||
override fun onNodeClick(node: NodeVersioned, position: Int) {
|
override fun onNodeClick(node: NodeVersioned, position: Int) {
|
||||||
if (nodeActionMode) {
|
if (nodeActionSelectionMode) {
|
||||||
if (listNodesSelected.contains(node)) {
|
if (listActionNodes.contains(node)) {
|
||||||
// Remove selected item if already selected
|
// Remove selected item if already selected
|
||||||
listNodesSelected.remove(node)
|
listActionNodes.remove(node)
|
||||||
} else {
|
} else {
|
||||||
// TODO multiple selection
|
|
||||||
if (listNodesSelected.size == 0) {
|
|
||||||
// Add selected item if not already selected
|
// Add selected item if not already selected
|
||||||
listNodesSelected.add(node)
|
listActionNodes.add(node)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
nodeClickListener?.onNodeSelected(listNodesSelected)
|
nodeClickListener?.onNodeSelected(listActionNodes)
|
||||||
setActionNodes(listNodesSelected)
|
setActionNodes(listActionNodes)
|
||||||
notifyItemChanged(position)
|
notifyItemChanged(position)
|
||||||
} else {
|
} else {
|
||||||
nodeClickListener?.onNodeClick(node)
|
nodeClickListener?.onNodeClick(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
// End the selected mode if no more item selected
|
|
||||||
if (listNodesSelected.isEmpty())
|
|
||||||
nodeActionMode = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNodeLongClick(node: NodeVersioned, position: Int): Boolean {
|
override fun onNodeLongClick(node: NodeVersioned, position: Int): Boolean {
|
||||||
// Select the first item after a long click
|
// Select the first item after a long click
|
||||||
nodeActionMode = true
|
if (!listActionNodes.contains(node))
|
||||||
if (!listNodesSelected.contains(node))
|
listActionNodes.add(node)
|
||||||
listNodesSelected.add(node)
|
|
||||||
|
|
||||||
nodeClickListener?.onNodeSelected(listNodesSelected)
|
nodeClickListener?.onNodeSelected(listActionNodes)
|
||||||
|
|
||||||
setActionNodes(listNodesSelected)
|
setActionNodes(listActionNodes)
|
||||||
notifyItemChanged(position)
|
notifyItemChanged(position)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -257,40 +249,50 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
|
|||||||
menuListener: NodesActionMenuListener?) : ActionMode.Callback {
|
menuListener: NodesActionMenuListener?) : ActionMode.Callback {
|
||||||
|
|
||||||
return object : ActionMode.Callback {
|
return object : ActionMode.Callback {
|
||||||
|
|
||||||
|
private var pasteMode: PasteMode? = null
|
||||||
|
|
||||||
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||||
|
nodeActionSelectionMode = false
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
|
||||||
menu?.clear()
|
menu?.clear()
|
||||||
activity?.menuInflater?.inflate(R.menu.node_menu, menu)
|
|
||||||
|
|
||||||
val database = Database.getInstance()
|
if (pasteMode != null) {
|
||||||
|
mode?.menuInflater?.inflate(R.menu.node_paste_menu, menu)
|
||||||
|
} else {
|
||||||
|
nodeActionSelectionMode = true
|
||||||
|
mode?.menuInflater?.inflate(R.menu.node_menu, menu)
|
||||||
|
|
||||||
// Open and Edit for a single item
|
val database = Database.getInstance()
|
||||||
if (nodes.size == 1) {
|
|
||||||
// Edition
|
// Open and Edit for a single item
|
||||||
if (readOnly || nodes[0] == database.recycleBin) {
|
if (nodes.size == 1) {
|
||||||
|
// Edition
|
||||||
|
if (readOnly || nodes[0] == database.recycleBin) {
|
||||||
|
menu?.removeItem(R.id.menu_edit)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
menu?.removeItem(R.id.menu_open)
|
||||||
menu?.removeItem(R.id.menu_edit)
|
menu?.removeItem(R.id.menu_edit)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
menu?.removeItem(R.id.menu_open)
|
|
||||||
menu?.removeItem(R.id.menu_edit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy and Move (not for groups)
|
// Copy and Move (not for groups)
|
||||||
if (readOnly
|
if (readOnly
|
||||||
|| isASearchResult
|
|| isASearchResult
|
||||||
|| nodes.any { it == database.recycleBin }
|
|| nodes.any { it == database.recycleBin }
|
||||||
|| nodes.any { it.type == Type.GROUP }) {
|
|| nodes.any { it.type == Type.GROUP }) {
|
||||||
// TODO COPY For Group
|
// TODO COPY For Group
|
||||||
menu?.removeItem(R.id.menu_copy)
|
menu?.removeItem(R.id.menu_copy)
|
||||||
menu?.removeItem(R.id.menu_move)
|
menu?.removeItem(R.id.menu_move)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletion
|
// Deletion
|
||||||
if (readOnly || nodes.any { it == database.recycleBin }) {
|
if (readOnly || nodes.any { it == database.recycleBin }) {
|
||||||
menu?.removeItem(R.id.menu_delete)
|
menu?.removeItem(R.id.menu_delete)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@@ -302,16 +304,35 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
|
|||||||
return when (item?.itemId) {
|
return when (item?.itemId) {
|
||||||
R.id.menu_open -> menuListener.onOpenMenuClick(nodes[0])
|
R.id.menu_open -> menuListener.onOpenMenuClick(nodes[0])
|
||||||
R.id.menu_edit -> menuListener.onEditMenuClick(nodes[0])
|
R.id.menu_edit -> menuListener.onEditMenuClick(nodes[0])
|
||||||
R.id.menu_copy -> menuListener.onCopyMenuClick(nodes)
|
R.id.menu_copy -> {
|
||||||
R.id.menu_move -> menuListener.onMoveMenuClick(nodes)
|
pasteMode = PasteMode.PASTE_FROM_COPY
|
||||||
|
mAdapter?.unselectActionNodes()
|
||||||
|
val returnValue = menuListener.onCopyMenuClick(nodes)
|
||||||
|
nodeActionSelectionMode = false
|
||||||
|
returnValue
|
||||||
|
}
|
||||||
|
R.id.menu_move -> {
|
||||||
|
pasteMode = PasteMode.PASTE_FROM_MOVE
|
||||||
|
mAdapter?.unselectActionNodes()
|
||||||
|
val returnValue = menuListener.onMoveMenuClick(nodes)
|
||||||
|
nodeActionSelectionMode = false
|
||||||
|
returnValue
|
||||||
|
}
|
||||||
R.id.menu_delete -> menuListener.onDeleteMenuClick(nodes)
|
R.id.menu_delete -> menuListener.onDeleteMenuClick(nodes)
|
||||||
|
R.id.menu_paste -> {
|
||||||
|
val returnValue = menuListener.onPasteMenuClick(pasteMode, nodes)
|
||||||
|
mode?.finish()
|
||||||
|
pasteMode = null
|
||||||
|
returnValue
|
||||||
|
}
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyActionMode(mode: ActionMode?) {
|
override fun onDestroyActionMode(mode: ActionMode?) {
|
||||||
listNodesSelected.clear()
|
listActionNodes.clear()
|
||||||
mAdapter?.removeActionNodes()
|
mAdapter?.unselectActionNodes()
|
||||||
|
nodeActionSelectionMode = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -375,6 +396,11 @@ class ListNodesFragment : StylishFragment(), SortDialogFragment.SortSelectionLis
|
|||||||
fun onCopyMenuClick(nodes: List<NodeVersioned>): Boolean
|
fun onCopyMenuClick(nodes: List<NodeVersioned>): Boolean
|
||||||
fun onMoveMenuClick(nodes: List<NodeVersioned>): Boolean
|
fun onMoveMenuClick(nodes: List<NodeVersioned>): Boolean
|
||||||
fun onDeleteMenuClick(nodes: List<NodeVersioned>): Boolean
|
fun onDeleteMenuClick(nodes: List<NodeVersioned>): Boolean
|
||||||
|
fun onPasteMenuClick(pasteMode: PasteMode?, nodes: List<NodeVersioned>): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class PasteMode {
|
||||||
|
PASTE_FROM_COPY, PASTE_FROM_MOVE
|
||||||
}
|
}
|
||||||
|
|
||||||
interface OnScrollListener {
|
interface OnScrollListener {
|
||||||
|
|||||||
@@ -169,6 +169,8 @@ class NodeAdapter
|
|||||||
*/
|
*/
|
||||||
fun removeNodeAt(position: Int) {
|
fun removeNodeAt(position: Int) {
|
||||||
nodeSortedList.removeItemAt(position)
|
nodeSortedList.removeItemAt(position)
|
||||||
|
// Refresh all the next items
|
||||||
|
notifyItemRangeChanged(position, nodeSortedList.size() - position)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -190,7 +192,7 @@ class NodeAdapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeActionNodes() {
|
fun unselectActionNodes() {
|
||||||
actionNodesList.forEach {
|
actionNodesList.forEach {
|
||||||
notifyItemChanged(nodeSortedList.indexOf(it))
|
notifyItemChanged(nodeSortedList.indexOf(it))
|
||||||
}
|
}
|
||||||
|
|||||||
110
app/src/main/java/com/kunzisoft/keepass/view/ToolbarAction.kt
Normal file
110
app/src/main/java/com/kunzisoft/keepass/view/ToolbarAction.kt
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package com.kunzisoft.keepass.view
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.View
|
||||||
|
import androidx.appcompat.view.ActionMode
|
||||||
|
import androidx.appcompat.view.SupportMenuInflater
|
||||||
|
import androidx.appcompat.widget.Toolbar
|
||||||
|
import com.kunzisoft.keepass.R
|
||||||
|
|
||||||
|
class ToolbarAction @JvmOverloads constructor(context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
defStyle: Int = androidx.appcompat.R.attr.toolbarStyle)
|
||||||
|
: Toolbar(context, attrs, defStyle) {
|
||||||
|
|
||||||
|
private var mActionModeCallback: ActionMode.Callback? = null
|
||||||
|
private val actionMode = NodeActionMode(this)
|
||||||
|
|
||||||
|
init {
|
||||||
|
visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startSupportActionMode(actionModeCallback: ActionMode.Callback): ActionMode {
|
||||||
|
mActionModeCallback?.onDestroyActionMode(actionMode)
|
||||||
|
mActionModeCallback = actionModeCallback
|
||||||
|
mActionModeCallback?.onCreateActionMode(actionMode, menu)
|
||||||
|
mActionModeCallback?.onPrepareActionMode(actionMode, menu)
|
||||||
|
|
||||||
|
setOnMenuItemClickListener {
|
||||||
|
mActionModeCallback?.onActionItemClicked(actionMode, it) ?: false
|
||||||
|
}
|
||||||
|
setNavigationOnClickListener{
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
setNavigationIcon(R.drawable.ic_close_white_24dp)
|
||||||
|
|
||||||
|
open()
|
||||||
|
|
||||||
|
return actionMode
|
||||||
|
}
|
||||||
|
|
||||||
|
fun invalidateMenu() {
|
||||||
|
open()
|
||||||
|
mActionModeCallback?.onPrepareActionMode(actionMode, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun open() {
|
||||||
|
visibility = View.VISIBLE
|
||||||
|
//expand()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun close() {
|
||||||
|
//collapse()
|
||||||
|
visibility = View.GONE
|
||||||
|
mActionModeCallback?.onDestroyActionMode(actionMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NodeActionMode(var toolbarAction: ToolbarAction): ActionMode() {
|
||||||
|
|
||||||
|
override fun finish() {
|
||||||
|
menu.clear()
|
||||||
|
toolbarAction.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMenu(): Menu {
|
||||||
|
return toolbarAction.menu
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCustomView(): View {
|
||||||
|
return toolbarAction
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setCustomView(view: View?) {}
|
||||||
|
|
||||||
|
override fun getMenuInflater(): MenuInflater {
|
||||||
|
return SupportMenuInflater(toolbarAction.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invalidate() {
|
||||||
|
toolbarAction.invalidateMenu()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSubtitle(): CharSequence {
|
||||||
|
return toolbarAction.subtitle
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setTitle(title: CharSequence?) {
|
||||||
|
toolbarAction.title = title
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setTitle(resId: Int) {
|
||||||
|
toolbarAction.setTitle(resId)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTitle(): CharSequence {
|
||||||
|
return toolbarAction.title
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setSubtitle(subtitle: CharSequence?) {
|
||||||
|
toolbarAction.subtitle = subtitle
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setSubtitle(resId: Int) {
|
||||||
|
toolbarAction.setSubtitle(resId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.view
|
package com.kunzisoft.keepass.view
|
||||||
|
|
||||||
|
import android.animation.Animator
|
||||||
import android.animation.AnimatorSet
|
import android.animation.AnimatorSet
|
||||||
import android.animation.ValueAnimator
|
import android.animation.ValueAnimator
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
@@ -63,7 +64,7 @@ fun Activity.unlockScreenOrientation() {
|
|||||||
|
|
||||||
private var actionBarHeight: Int = 0
|
private var actionBarHeight: Int = 0
|
||||||
|
|
||||||
fun Toolbar.collapse(animate: Boolean = true) {
|
fun Toolbar.collapse(animate: Boolean = true, listener: Animator.AnimatorListener? = null) {
|
||||||
|
|
||||||
if (layoutParams.height > 5)
|
if (layoutParams.height > 5)
|
||||||
actionBarHeight = layoutParams.height
|
actionBarHeight = layoutParams.height
|
||||||
@@ -72,6 +73,9 @@ fun Toolbar.collapse(animate: Boolean = true) {
|
|||||||
.ofInt(height, 0)
|
.ofInt(height, 0)
|
||||||
if (animate)
|
if (animate)
|
||||||
slideAnimator.duration = 300L
|
slideAnimator.duration = 300L
|
||||||
|
listener?.let {
|
||||||
|
slideAnimator.addListener(it)
|
||||||
|
}
|
||||||
slideAnimator.addUpdateListener { animation ->
|
slideAnimator.addUpdateListener { animation ->
|
||||||
layoutParams.height = animation.animatedValue as Int
|
layoutParams.height = animation.animatedValue as Int
|
||||||
requestLayout()
|
requestLayout()
|
||||||
@@ -82,12 +86,15 @@ fun Toolbar.collapse(animate: Boolean = true) {
|
|||||||
}.start()
|
}.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Toolbar.expand(animate: Boolean = true) {
|
fun Toolbar.expand(animate: Boolean = true, listener: Animator.AnimatorListener? = null) {
|
||||||
|
|
||||||
val slideAnimator = ValueAnimator
|
val slideAnimator = ValueAnimator
|
||||||
.ofInt(0, actionBarHeight)
|
.ofInt(0, actionBarHeight)
|
||||||
if (animate)
|
if (animate)
|
||||||
slideAnimator.duration = 300L
|
slideAnimator.duration = 300L
|
||||||
|
listener?.let {
|
||||||
|
slideAnimator.addListener(it)
|
||||||
|
}
|
||||||
slideAnimator.addUpdateListener { animation ->
|
slideAnimator.addUpdateListener { animation ->
|
||||||
layoutParams.height = animation.animatedValue as Int
|
layoutParams.height = animation.animatedValue as Int
|
||||||
requestLayout()
|
requestLayout()
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_above="@+id/toolbar_paste">
|
android:layout_above="@+id/toolbar_action">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/app_bar"
|
android:id="@+id/app_bar"
|
||||||
@@ -147,8 +147,8 @@
|
|||||||
app:layout_anchorGravity="right|bottom" />
|
app:layout_anchorGravity="right|bottom" />
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
<com.kunzisoft.keepass.view.ToolbarAction
|
||||||
android:id="@+id/toolbar_paste"
|
android:id="@+id/toolbar_action"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
|
|||||||
@@ -48,6 +48,6 @@
|
|||||||
</style>
|
</style>
|
||||||
<!-- Contextual Action Bar Purple -->
|
<!-- Contextual Action Bar Purple -->
|
||||||
<style name="KeepassDXStyle.ActionMode.Purple" parent="@style/Widget.AppCompat.ActionMode">
|
<style name="KeepassDXStyle.ActionMode.Purple" parent="@style/Widget.AppCompat.ActionMode">
|
||||||
<item name="background">@color/purple_dark</item>
|
<item name="background">@color/red</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -43,6 +43,6 @@
|
|||||||
</style>
|
</style>
|
||||||
<!-- Contextual Action Bar Red -->
|
<!-- Contextual Action Bar Red -->
|
||||||
<style name="KeepassDXStyle.ActionMode.Red" parent="@style/Widget.AppCompat.ActionMode">
|
<style name="KeepassDXStyle.ActionMode.Red" parent="@style/Widget.AppCompat.ActionMode">
|
||||||
<item name="background">@color/red_dark</item>
|
<item name="background">@color/orange</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -180,7 +180,7 @@
|
|||||||
|
|
||||||
<!-- Contextual Action Bar -->
|
<!-- Contextual Action Bar -->
|
||||||
<style name="KeepassDXStyle.ActionMode" parent="@style/Widget.AppCompat.ActionMode">
|
<style name="KeepassDXStyle.ActionMode" parent="@style/Widget.AppCompat.ActionMode">
|
||||||
<item name="background">@color/green_dark</item>
|
<item name="background">@color/orange</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- CollapsingToolbarLayout -->
|
<!-- CollapsingToolbarLayout -->
|
||||||
|
|||||||
Reference in New Issue
Block a user