Skip to content

Commit

Permalink
fix: Use flags from col, dynamically loading them into the menu
Browse files Browse the repository at this point in the history
Co-authored-by: David Allison <[email protected]>
  • Loading branch information
criticalAY and david-allison committed Apr 19, 2024
1 parent ed49388 commit 854f34e
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 258 deletions.
100 changes: 36 additions & 64 deletions AnkiDroid/src/main/java/com/ichi2/anki/CardBrowser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -713,6 +713,7 @@ open class CardBrowser :
// restore drawer click listener and icon
restoreDrawerIcon()
menuInflater.inflate(R.menu.card_browser, menu)
addFlags(menu.findItem(R.id.action_search_by_flag).subMenu, Mode.SINGLE_SELECT)
saveSearchItem = menu.findItem(R.id.action_save_search)
saveSearchItem?.isVisible = false // the searchview's query always starts empty.
mySearchesItem = menu.findItem(R.id.action_list_my_searches)
Expand Down Expand Up @@ -766,6 +767,7 @@ open class CardBrowser :
} else {
// multi-select mode
menuInflater.inflate(R.menu.card_browser_multiselect, menu)
addFlags(menu.findItem(R.id.action_flag).subMenu, Mode.MULTI_SELECT)
showBackIcon()
increaseHorizontalPaddingOfOverflowMenuIcons(menu)
}
Expand All @@ -791,6 +793,30 @@ open class CardBrowser :
return super.onCreateOptionsMenu(menu)
}

/**
* Representing different selection modes.
*/
enum class Mode(val value: Int) {
SINGLE_SELECT(1000),
MULTI_SELECT(1001)
}

private fun addFlags(subMenu: SubMenu?, mode: Mode) {
lifecycleScope.launch {
val flagNames = getFlagData(this@CardBrowser)

val groupId = when (mode) {
Mode.SINGLE_SELECT -> mode.value
Mode.MULTI_SELECT -> mode.value
}

flagNames.forEach { (flag, pair) ->
val (title, drawableRes) = pair
subMenu?.add(groupId, flag.ordinal, Menu.NONE, title)?.setIcon(drawableRes)
}
}
}

override fun onNavigationPressed() {
if (viewModel.isInMultiSelectMode) {
viewModel.endMultiSelectMode()
Expand Down Expand Up @@ -900,6 +926,16 @@ open class CardBrowser :
undoSnackbar != null && undoSnackbar!!.isShown -> undoSnackbar!!.dismiss()
}

val flag = Flag.entries.find { it.ordinal == item.itemId }
flag?.let {
when (item.groupId) {
Mode.SINGLE_SELECT.value -> filterByFlag(it)
Mode.MULTI_SELECT.value -> updateFlagForSelectedRows(it)
else -> return@let
}
return true
}

when (item.itemId) {
android.R.id.home -> {
viewModel.endMultiSelectMode()
Expand Down Expand Up @@ -962,70 +998,6 @@ open class CardBrowser :
showFilterByTagsDialog()
return true
}
R.id.action_flag_zero -> {
updateFlagForSelectedRows(Flag.NONE)
return true
}
R.id.action_flag_one -> {
updateFlagForSelectedRows(Flag.RED)
return true
}
R.id.action_flag_two -> {
updateFlagForSelectedRows(Flag.ORANGE)
return true
}
R.id.action_flag_three -> {
updateFlagForSelectedRows(Flag.GREEN)
return true
}
R.id.action_flag_four -> {
updateFlagForSelectedRows(Flag.BLUE)
return true
}
R.id.action_flag_five -> {
updateFlagForSelectedRows(Flag.PINK)
return true
}
R.id.action_flag_six -> {
updateFlagForSelectedRows(Flag.TURQUOISE)
return true
}
R.id.action_flag_seven -> {
updateFlagForSelectedRows(Flag.PURPLE)
return true
}
R.id.action_select_flag_zero -> {
filterByFlag(Flag.NONE)
return true
}
R.id.action_select_flag_one -> {
filterByFlag(Flag.RED)
return true
}
R.id.action_select_flag_two -> {
filterByFlag(Flag.ORANGE)
return true
}
R.id.action_select_flag_three -> {
filterByFlag(Flag.GREEN)
return true
}
R.id.action_select_flag_four -> {
filterByFlag(Flag.BLUE)
return true
}
R.id.action_select_flag_five -> {
filterByFlag(Flag.PINK)
return true
}
R.id.action_select_flag_six -> {
filterByFlag(Flag.TURQUOISE)
return true
}
R.id.action_select_flag_seven -> {
filterByFlag(Flag.PURPLE)
return true
}
R.id.action_delete_card -> {
deleteSelectedNotes()
return true
Expand Down
40 changes: 40 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/Flag.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,26 @@
*/
package com.ichi2.anki

import android.content.Context
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import com.ichi2.anki.CollectionManager.withCol
import com.ichi2.libanki.Card
import com.ichi2.libanki.CardId
import com.ichi2.libanki.Collection
import org.json.JSONObject

// this is not part of the enum as getFlagNames should be used to handle overrides
private val flagToName = hashMapOf(
Flag.NONE to R.string.menu_flag_card_zero,
Flag.RED to R.string.menu_flag_card_one,
Flag.ORANGE to R.string.menu_flag_card_two,
Flag.GREEN to R.string.menu_flag_card_three,
Flag.BLUE to R.string.menu_flag_card_four,
Flag.PINK to R.string.menu_flag_card_five,
Flag.TURQUOISE to R.string.menu_flag_card_six,
Flag.PURPLE to R.string.menu_flag_card_seven
)

enum class Flag(val code: Int, @DrawableRes val drawableRes: Int, @ColorRes val browserColorRes: Int?) {
NONE(0, R.drawable.ic_flag_transparent, null),
Expand All @@ -39,3 +54,28 @@ enum class Flag(val code: Int, @DrawableRes val drawableRes: Int, @ColorRes val
}
fun Collection.setUserFlag(flag: Flag, cids: List<CardId>) = this.setUserFlag(flag.code, cids)
fun Card.setUserFlag(flag: Flag) = this.setUserFlag(flag.code)

/**
* Retrieves the flag data, including flag names and corresponding drawable resource IDs.
* This method asynchronously fetches the flag names and drawable resource IDs for each flag.
*
* @param context The context used to access application resources.
* @return A map where each Flag enum is associated with a pair containing its name as a string and its corresponding drawable resource ID.
*/
suspend fun getFlagData(context: Context): Map<Flag, Pair<String, Int>> {
val overrides = withCol { config.getObject("flagLabels", JSONObject()) }
return Flag.entries.associateWith { flag ->
val flagName = overrides.getStringOrNull(flag.code.toString()) ?: context.getString(flagToName[flag]!!)
val drawableResId = flag.drawableRes
flagName to drawableResId
}
}

private fun JSONObject.getStringOrNull(key: String): String? {
if (!has(key)) return null
return try {
getString(key)
} catch (_: Exception) {
null
}
}
83 changes: 28 additions & 55 deletions AnkiDroid/src/main/java/com/ichi2/anki/Reviewer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import androidx.appcompat.view.menu.MenuBuilder
import androidx.appcompat.widget.Toolbar
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
import anki.frontend.SetSchedulingStatesRequest
import com.google.android.material.color.MaterialColors
Expand Down Expand Up @@ -88,6 +89,7 @@ import com.ichi2.utils.HandlerUtils.getDefaultLooper
import com.ichi2.utils.Permissions.canRecordAudio
import com.ichi2.utils.ViewGroupUtils.setRenderWorkaround
import com.ichi2.widget.WidgetStatus.updateInBackground
import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.File

Expand Down Expand Up @@ -350,6 +352,11 @@ open class Reviewer :
if (drawerToggle.onOptionsItemSelected(item)) {
return true
}
val flag = Flag.entries.find { it.ordinal == item.itemId }
flag?.let {
onFlag(currentCard, it)
return true
}
when (item.itemId) {
android.R.id.home -> {
Timber.i("Reviewer:: Home button pressed")
Expand Down Expand Up @@ -449,38 +456,6 @@ open class Reviewer :
Timber.i("Reviewer:: Add note button pressed")
addNote()
}
R.id.action_flag_zero -> {
Timber.i("Reviewer:: No flag")
onFlag(currentCard, Flag.NONE)
}
R.id.action_flag_one -> {
Timber.i("Reviewer:: Flag one")
onFlag(currentCard, Flag.RED)
}
R.id.action_flag_two -> {
Timber.i("Reviewer:: Flag two")
onFlag(currentCard, Flag.ORANGE)
}
R.id.action_flag_three -> {
Timber.i("Reviewer:: Flag three")
onFlag(currentCard, Flag.GREEN)
}
R.id.action_flag_four -> {
Timber.i("Reviewer:: Flag four")
onFlag(currentCard, Flag.BLUE)
}
R.id.action_flag_five -> {
Timber.i("Reviewer:: Flag five")
onFlag(currentCard, Flag.PINK)
}
R.id.action_flag_six -> {
Timber.i("Reviewer:: Flag six")
onFlag(currentCard, Flag.TURQUOISE)
}
R.id.action_flag_seven -> {
Timber.i("Reviewer:: Flag seven")
onFlag(currentCard, Flag.PURPLE)
}
R.id.action_card_info -> {
Timber.i("Card Viewer:: Card Info")
openCardInfo()
Expand Down Expand Up @@ -692,12 +667,28 @@ open class Reviewer :
startActivityWithAnimation(intent, animation)
}

private val flagItemIds = mutableSetOf<Int>()

private fun addFlags(subMenu: SubMenu?) {
lifecycleScope.launch {
val flagNames = getFlagData(this@Reviewer)
flagNames.forEach { (flag, pair) ->
val (title, drawableRes) = pair
val menuItem = subMenu?.add(Menu.NONE, flag.ordinal, Menu.NONE, title)?.setIcon(drawableRes)
menuItem?.let {
flagItemIds.add(it.itemId)
}
}
}
}

// Related to https://github.com/ankidroid/Anki-Android/pull/11061#issuecomment-1107868455
@NeedsTest("Order of operations needs Testing around Menu (Overflow) Icons and their colors.")
override fun onCreateOptionsMenu(menu: Menu): Boolean {
Timber.d("onCreateOptionsMenu()")
// NOTE: This is called every time a new question is shown via invalidate options menu
menuInflater.inflate(R.menu.reviewer, menu)
addFlags(menu.findItem(R.id.action_flag).subMenu)
displayIcons(menu)
actionButtons.setCustomButtonsStatus(menu)
val alpha = Themes.ALPHA_ICON_ENABLED_LIGHT
Expand All @@ -709,23 +700,6 @@ open class Reviewer :
}
markCardIcon.iconAlpha = alpha

val flagIcon = menu.findItem(R.id.action_flag)
if (flagIcon != null) {
if (currentCard != null) {
when (currentCard!!.userFlag()) {
1 -> flagIcon.setIcon(R.drawable.ic_flag_red)
2 -> flagIcon.setIcon(R.drawable.ic_flag_orange)
3 -> flagIcon.setIcon(R.drawable.ic_flag_green)
4 -> flagIcon.setIcon(R.drawable.ic_flag_blue)
5 -> flagIcon.setIcon(R.drawable.ic_flag_pink)
6 -> flagIcon.setIcon(R.drawable.ic_flag_turquoise)
7 -> flagIcon.setIcon(R.drawable.ic_flag_purple)
else -> flagIcon.setIcon(R.drawable.ic_flag_transparent)
}
}
flagIcon.iconAlpha = alpha
}

// Anki Desktop Translations
menu.findItem(R.id.action_reschedule_card).title =
CollectionManager.TR.actionsSetDueDate().toSentenceCase(R.string.sentence_set_due_date)
Expand Down Expand Up @@ -849,11 +823,14 @@ open class Reviewer :
onboarding.onCreate()

increaseHorizontalPaddingOfOverflowMenuIcons(menu)
tintOverflowMenuIcons(menu, skipIf = { isFlagResource(it.itemId) })

tintOverflowMenuIcons(menu, skipIf = { isFlagItem(it) })
return super.onCreateOptionsMenu(menu)
}

private fun isFlagItem(menuItem: MenuItem): Boolean {
return flagItemIds.contains(menuItem.itemId)
}

@SuppressLint("RestrictedApi")
private fun displayIcons(menu: Menu) {
try {
Expand All @@ -867,10 +844,6 @@ open class Reviewer :
}
}

private fun isFlagResource(itemId: Int): Boolean {
return itemId == R.id.action_flag_seven || itemId == R.id.action_flag_six || itemId == R.id.action_flag_five || itemId == R.id.action_flag_four || itemId == R.id.action_flag_three || itemId == R.id.action_flag_two || itemId == R.id.action_flag_one
}

override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (answerFieldIsFocused()) {
return super.onKeyDown(keyCode, event)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import com.ichi2.anki.Flag
import com.ichi2.anki.R
import com.ichi2.anki.browser.PreviewerIdsFile
import com.ichi2.anki.cardviewer.CardMediaPlayer
import com.ichi2.anki.getFlagData
import com.ichi2.anki.snackbar.BaseSnackbarBuilderProvider
import com.ichi2.anki.snackbar.SnackbarBuilder
import com.ichi2.anki.utils.ext.sharedPrefs
Expand Down Expand Up @@ -122,6 +123,15 @@ class PreviewerFragment :
}
}

lifecycleScope.launch {
val flagData = getFlagData(requireContext())
val submenu = menu.findItem(R.id.action_flag).subMenu
flagData.forEach { (flag, pair) ->
val (title, drawableRes) = pair
submenu?.add(Menu.NONE, flag.ordinal, Menu.NONE, title)?.setIcon(drawableRes)
}
}

lifecycleScope.launch {
viewModel.flagCode
.flowWithLifecycle(lifecycle)
Expand Down Expand Up @@ -188,18 +198,15 @@ class PreviewerFragment :
}

override fun onMenuItemClick(item: MenuItem): Boolean {
val flag = Flag.entries.find { it.ordinal == item.itemId }
flag?.let {
viewModel.setFlag(it)
return true
}
when (item.itemId) {
R.id.action_edit -> editCard()
R.id.action_mark -> viewModel.toggleMark()
R.id.action_back_side_only -> viewModel.toggleBackSideOnly()
R.id.action_flag_zero -> viewModel.setFlag(Flag.NONE)
R.id.action_flag_one -> viewModel.setFlag(Flag.RED)
R.id.action_flag_two -> viewModel.setFlag(Flag.ORANGE)
R.id.action_flag_three -> viewModel.setFlag(Flag.GREEN)
R.id.action_flag_four -> viewModel.setFlag(Flag.BLUE)
R.id.action_flag_five -> viewModel.setFlag(Flag.PINK)
R.id.action_flag_six -> viewModel.setFlag(Flag.TURQUOISE)
R.id.action_flag_seven -> viewModel.setFlag(Flag.PURPLE)
}
return true
}
Expand Down
Loading

0 comments on commit 854f34e

Please sign in to comment.