mirror of
https://github.com/ankidroid/Anki-Android.git
synced 2024-09-19 19:42:17 +02:00
Implement Right-Click Support for Long Click Listeners
-Added right-click support for all existing long click listeners. -Created an OnContextAndLongClickListener interface to handle both context click and long click events consistently. -This interface includes an onAction method to define the common action (context and long click). -The interface ensures that both listeners are set without duplicating code. -Applied the OnContextAndLongClickListener interface to handle right-click and long-click events uniformly.
This commit is contained in:
parent
87e2a79b67
commit
76eea74a2b
@ -43,7 +43,6 @@ import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.View.OnLongClickListener
|
||||
import android.view.ViewPropertyAnimator
|
||||
import android.widget.Filterable
|
||||
import android.widget.ImageButton
|
||||
@ -442,9 +441,13 @@ open class DeckPicker :
|
||||
}
|
||||
}
|
||||
|
||||
private val deckLongClickListener = OnLongClickListener { v ->
|
||||
private val deckContextAndLongClickListener = OnContextAndLongClickListener { v ->
|
||||
val deckId = v.tag as DeckId
|
||||
Timber.i("DeckPicker:: Long tapped on deck with id %d", deckId)
|
||||
showDeckPickerContextMenu(deckId)
|
||||
true
|
||||
}
|
||||
|
||||
private fun showDeckPickerContextMenu(deckId: DeckId) {
|
||||
launchCatchingTask {
|
||||
val (deckName, isDynamic, hasBuriedInDeck) = withCol {
|
||||
decks.select(deckId)
|
||||
@ -464,7 +467,6 @@ open class DeckPicker :
|
||||
)
|
||||
)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
private val notificationPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {
|
||||
@ -558,7 +560,7 @@ open class DeckPicker :
|
||||
setDeckClickListener(deckClickListener)
|
||||
setCountsClickListener(countsClickListener)
|
||||
setDeckExpanderClickListener(deckExpanderClickListener)
|
||||
setDeckLongClickListener(deckLongClickListener)
|
||||
setDeckContextAndLongClickListener(deckContextAndLongClickListener)
|
||||
enablePartialTransparencyForBackground(hasDeckPickerBackground)
|
||||
}
|
||||
recyclerView.adapter = deckListAdapter
|
||||
|
@ -78,6 +78,7 @@ import com.google.android.material.snackbar.Snackbar
|
||||
import com.ichi2.anim.ActivityTransitionAnimation
|
||||
import com.ichi2.anki.CollectionManager.TR
|
||||
import com.ichi2.anki.CollectionManager.withCol
|
||||
import com.ichi2.anki.OnContextAndLongClickListener.Companion.setOnContextAndLongClickListener
|
||||
import com.ichi2.anki.bottomsheet.ImageOcclusionBottomSheetFragment
|
||||
import com.ichi2.anki.dialogs.ConfirmationDialog
|
||||
import com.ichi2.anki.dialogs.DeckSelectionDialog.DeckSelectionListener
|
||||
@ -2232,7 +2233,7 @@ class NoteEditor : AnkiFragment(R.layout.note_editor), DeckSelectionListener, Su
|
||||
|
||||
// Allow Ctrl + 1...Ctrl + 0 for item 10.
|
||||
v.tag = (visualIndex % 10).toString()
|
||||
v.setOnLongClickListener {
|
||||
v.setOnContextAndLongClickListener {
|
||||
displayEditToolbarDialog(b)
|
||||
true
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
/***************************************************************************************
|
||||
* *
|
||||
* Copyright (c) 2024 Sanjay Sargam <sargamsanjaykumar@gmail.com> *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify it under *
|
||||
* the terms of the GNU General Public License as published by the Free Software *
|
||||
* Foundation; either version 3 of the License, or (at your option) any later *
|
||||
* version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License along with *
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
****************************************************************************************/
|
||||
|
||||
package com.ichi2.anki
|
||||
|
||||
import android.view.View
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
* A listener that has the same action for both "context click" (i.e., mostly right-click) and "long click" (i.e., holding the finger on the view).
|
||||
*
|
||||
* * Note: In some contexts, a long press (long click) is expected to be informational, whereas a right-click (context click) is expected to be functional.
|
||||
* * Ensure that using the same action for both is appropriate for your use case.
|
||||
*/
|
||||
fun interface OnContextAndLongClickListener : View.OnContextClickListener, View.OnLongClickListener {
|
||||
/**
|
||||
* The action to do for both contextClick and long click
|
||||
* @returns whether the operation was successful
|
||||
*/
|
||||
fun onAction(v: View): Boolean
|
||||
|
||||
override fun onContextClick(v: View): Boolean {
|
||||
Timber.i("${this.javaClass}: user context clicked")
|
||||
return onAction(v)
|
||||
}
|
||||
|
||||
override fun onLongClick(v: View): Boolean {
|
||||
Timber.i("${this.javaClass}: user long clicked")
|
||||
return onAction(v)
|
||||
}
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Ensures [this] gets both a long click and a context click listener.
|
||||
* @see View.setOnLongClickListener
|
||||
* @see View.setOnContextClickListener
|
||||
*/
|
||||
fun View.setOnContextAndLongClickListener(listener: OnContextAndLongClickListener?) {
|
||||
setOnLongClickListener(listener)
|
||||
setOnContextClickListener(listener)
|
||||
}
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import anki.decks.DeckTreeNode
|
||||
import com.ichi2.anki.CollectionManager.withCol
|
||||
import com.ichi2.anki.DeckSpinnerSelection
|
||||
import com.ichi2.anki.OnContextAndLongClickListener.Companion.setOnContextAndLongClickListener
|
||||
import com.ichi2.anki.R
|
||||
import com.ichi2.anki.analytics.AnalyticsDialogFragment
|
||||
import com.ichi2.anki.dialogs.DeckSelectionDialog.DecksArrayAdapter.DecksFilter
|
||||
@ -179,7 +180,20 @@ open class DeckSelectionDialog : AnalyticsDialogFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSubDeckDialog(parentDeckPath: String) {
|
||||
/**
|
||||
* Displays a dialog to create a subdeck under the specified parent deck.
|
||||
*
|
||||
* If the `deckID` is equal to `DeckSpinnerSelection.ALL_DECKS_ID`, a toast message is shown
|
||||
* indicating that a subdeck cannot be created for "All Decks," and the dialog is not displayed.
|
||||
*
|
||||
* @param parentDeckPath The path of the parent deck under which the subdeck will be created.
|
||||
* @param deckID The ID of the deck where the subdeck should be created.
|
||||
*/
|
||||
private fun showSubDeckDialog(parentDeckPath: String, deckID: DeckId) {
|
||||
if (deckID == DeckSpinnerSelection.ALL_DECKS_ID) {
|
||||
context?.let { showThemedToast(it, R.string.cannot_create_subdeck_for_all_decks, true) }
|
||||
return
|
||||
}
|
||||
launchCatchingTask {
|
||||
val parentId = withCol { decks.id(parentDeckPath) }
|
||||
val createDeckDialog = CreateDeckDialog(requireActivity(), R.string.create_subdeck, CreateDeckDialog.DeckDialogType.SUB_DECK, parentId)
|
||||
@ -265,12 +279,9 @@ open class DeckSelectionDialog : AnalyticsDialogFragment() {
|
||||
expander.setOnClickListener {
|
||||
toggleExpansion(deckID)
|
||||
}
|
||||
deckHolder.setOnLongClickListener { // creating sub deck with parent deck path
|
||||
if (deckID == DeckSpinnerSelection.ALL_DECKS_ID) {
|
||||
context?.let { showThemedToast(it, R.string.cannot_create_subdeck_for_all_decks, true) }
|
||||
} else {
|
||||
showSubDeckDialog(deckName)
|
||||
}
|
||||
deckHolder.setOnContextAndLongClickListener {
|
||||
// creating sub deck with parent deck path
|
||||
showSubDeckDialog(deckName, deckID)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.ichi2.anki.OnContextAndLongClickListener
|
||||
import com.ichi2.anki.OnContextAndLongClickListener.Companion.setOnContextAndLongClickListener
|
||||
import com.ichi2.anki.R
|
||||
import com.ichi2.annotations.NeedsTest
|
||||
import com.ichi2.ui.CheckBoxTriStates
|
||||
@ -224,10 +226,10 @@ class TagsArrayAdapter(private val tags: TagsList, private val resources: Resour
|
||||
private val tagToIsExpanded: HashMap<String, Boolean>
|
||||
|
||||
/**
|
||||
* Long click listener for each tag item. Used to add a subtag for the clicked tag.
|
||||
* Context and Long click listener for each tag item. Used to add a subtag for the clicked tag.
|
||||
* The full tag is passed through View.tag
|
||||
*/
|
||||
var tagLongClickListener: View.OnLongClickListener? = null
|
||||
var tagContextAndLongClickListener: OnContextAndLongClickListener? = null
|
||||
|
||||
fun sortData() {
|
||||
tags.sort()
|
||||
@ -266,8 +268,8 @@ class TagsArrayAdapter(private val tags: TagsList, private val resources: Resour
|
||||
vh.checkBoxView.refreshDrawableState()
|
||||
}
|
||||
}
|
||||
// long clicking a tag opens the add tag dialog with the current tag as the prefix
|
||||
vh.itemView.setOnLongClickListener(tagLongClickListener)
|
||||
// context and long clicking a tag opens the add tag dialog with the current tag as the prefix
|
||||
vh.itemView.setOnContextAndLongClickListener(tagContextAndLongClickListener)
|
||||
return vh
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import androidx.core.os.BundleCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.ichi2.anki.OnContextAndLongClickListener
|
||||
import com.ichi2.anki.R
|
||||
import com.ichi2.anki.analytics.AnalyticsDialogFragment
|
||||
import com.ichi2.anki.model.CardStateFilter
|
||||
@ -189,14 +190,15 @@ class TagsDialog : AnalyticsDialogFragment {
|
||||
dialogTitle = resources.getString(R.string.card_details_tags)
|
||||
optionsGroup.visibility = View.GONE
|
||||
positiveText = getString(R.string.dialog_ok)
|
||||
tagsArrayAdapter!!.tagLongClickListener = View.OnLongClickListener { v ->
|
||||
createAddTagDialog(v.tag as String)
|
||||
true
|
||||
}
|
||||
tagsArrayAdapter!!.tagContextAndLongClickListener =
|
||||
OnContextAndLongClickListener { v ->
|
||||
createAddTagDialog(v.tag as String)
|
||||
true
|
||||
}
|
||||
} else {
|
||||
dialogTitle = resources.getString(R.string.studyoptions_limit_select_tags)
|
||||
positiveText = getString(R.string.select)
|
||||
tagsArrayAdapter!!.tagLongClickListener = View.OnLongClickListener { false }
|
||||
tagsArrayAdapter!!.tagContextAndLongClickListener = OnContextAndLongClickListener { false }
|
||||
}
|
||||
adjustToolbar(tagsDialogView)
|
||||
dialog = AlertDialog.Builder(requireActivity())
|
||||
|
@ -20,7 +20,6 @@ import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.OnLongClickListener
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Filter
|
||||
import android.widget.Filterable
|
||||
@ -32,6 +31,8 @@ import androidx.annotation.CheckResult
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.ichi2.anki.CollectionManager.withCol
|
||||
import com.ichi2.anki.OnContextAndLongClickListener
|
||||
import com.ichi2.anki.OnContextAndLongClickListener.Companion.setOnContextAndLongClickListener
|
||||
import com.ichi2.anki.R
|
||||
import com.ichi2.libanki.DeckId
|
||||
import com.ichi2.libanki.sched.DeckNode
|
||||
@ -64,7 +65,7 @@ class DeckAdapter(private val layoutInflater: LayoutInflater, context: Context)
|
||||
// Listeners
|
||||
private var deckClickListener: View.OnClickListener? = null
|
||||
private var deckExpanderClickListener: View.OnClickListener? = null
|
||||
private var deckLongClickListener: OnLongClickListener? = null
|
||||
private var deckContextAndLongClickListener: OnContextAndLongClickListener? = null
|
||||
private var countsClickListener: View.OnClickListener? = null
|
||||
|
||||
// Totals accumulated as each deck is processed
|
||||
@ -114,8 +115,8 @@ class DeckAdapter(private val layoutInflater: LayoutInflater, context: Context)
|
||||
deckExpanderClickListener = listener
|
||||
}
|
||||
|
||||
fun setDeckLongClickListener(listener: OnLongClickListener?) {
|
||||
deckLongClickListener = listener
|
||||
fun setDeckContextAndLongClickListener(listener: OnContextAndLongClickListener?) {
|
||||
deckContextAndLongClickListener = listener
|
||||
}
|
||||
|
||||
/** Sets whether the control should have partial transparency to allow a background to be seen */
|
||||
@ -219,7 +220,7 @@ class DeckAdapter(private val layoutInflater: LayoutInflater, context: Context)
|
||||
|
||||
// Set click listeners
|
||||
holder.deckLayout.setOnClickListener(deckClickListener)
|
||||
holder.deckLayout.setOnLongClickListener(deckLongClickListener)
|
||||
holder.deckLayout.setOnContextAndLongClickListener(deckContextAndLongClickListener)
|
||||
holder.countsLayout.setOnClickListener(countsClickListener)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user