0
0
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:
SanjaySargam 2024-07-10 00:33:10 +05:30 committed by Arthur Milchior
parent 87e2a79b67
commit 76eea74a2b
7 changed files with 103 additions and 27 deletions

View File

@ -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

View File

@ -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
}

View File

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

View File

@ -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
}
}

View File

@ -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
}

View File

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

View File

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