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 <62114487+david-allison@users.noreply.github.com>
(cherry picked from commit a281a9a)
  • Loading branch information
criticalAY authored and david-allison committed Apr 28, 2024
1 parent c43e71e commit 3ba4f9a
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 260 deletions.
98 changes: 34 additions & 64 deletions AnkiDroid/src/main/java/com/ichi2/anki/CardBrowser.kt
Expand Up @@ -733,6 +733,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 @@ -786,6 +787,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 @@ -811,6 +813,28 @@ 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 groupId = when (mode) {
Mode.SINGLE_SELECT -> mode.value
Mode.MULTI_SELECT -> mode.value
}

for (flag in Flag.entries) {
val title = flag.getName(resources)
subMenu?.add(groupId, flag.ordinal, Menu.NONE, title)?.setIcon(flag.drawableRes)
}
}
}

override fun onNavigationPressed() {
if (viewModel.isInMultiSelectMode) {
viewModel.endMultiSelectMode()
Expand Down Expand Up @@ -920,6 +944,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 @@ -982,70 +1016,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: 31 additions & 9 deletions AnkiDroid/src/main/java/com/ichi2/anki/Flag.kt
Expand Up @@ -15,21 +15,43 @@
*/
package com.ichi2.anki

import android.content.res.Resources
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import com.ichi2.anki.CollectionManager.withCol
import com.ichi2.anki.utils.ext.getStringOrNull
import com.ichi2.libanki.Card
import com.ichi2.libanki.CardId
import com.ichi2.libanki.Collection
import org.json.JSONObject

enum class Flag(val code: Int, @DrawableRes val drawableRes: Int, @ColorRes val browserColorRes: Int?) {
NONE(0, R.drawable.ic_flag_transparent, null),
RED(1, R.drawable.ic_flag_red, R.color.flag_red),
ORANGE(2, R.drawable.ic_flag_orange, R.color.flag_orange),
GREEN(3, R.drawable.ic_flag_green, R.color.flag_green),
BLUE(4, R.drawable.ic_flag_blue, R.color.flag_blue),
PINK(5, R.drawable.ic_flag_pink, R.color.flag_pink),
TURQUOISE(6, R.drawable.ic_flag_turquoise, R.color.flag_turquoise),
PURPLE(7, R.drawable.ic_flag_purple, R.color.flag_purple);
enum class Flag(
val code: Int,
@DrawableRes val drawableRes: Int,
@ColorRes val browserColorRes: Int?,
private val defaultNameRes: Int
) {
NONE(0, R.drawable.ic_flag_transparent, null, R.string.menu_flag_card_zero),
RED(1, R.drawable.ic_flag_red, R.color.flag_red, R.string.menu_flag_card_one),
ORANGE(2, R.drawable.ic_flag_orange, R.color.flag_orange, R.string.menu_flag_card_two),
GREEN(3, R.drawable.ic_flag_green, R.color.flag_green, R.string.menu_flag_card_three),
BLUE(4, R.drawable.ic_flag_blue, R.color.flag_blue, R.string.menu_flag_card_four),
PINK(5, R.drawable.ic_flag_pink, R.color.flag_pink, R.string.menu_flag_card_five),
TURQUOISE(6, R.drawable.ic_flag_turquoise, R.color.flag_turquoise, R.string.menu_flag_card_six),
PURPLE(7, R.drawable.ic_flag_purple, R.color.flag_purple, R.string.menu_flag_card_seven);

/**
* Retrieves the name associated with the flag.
* If an override for the flag name is provided in the configuration, it is fetched; otherwise,
* the default name resource ID is used to fetch the name from the application resources.
*
* @param resources The Resources object used to access application resources.
* @return The name associated with the flag, either fetched from overrides or default resources.
*/
suspend fun getName(resources: Resources): String {
val overrides = withCol { config.getObject("flagLabels", JSONObject()) }
return overrides.getStringOrNull(code.toString()) ?: resources.getString(defaultNameRes)
}

companion object {
fun fromCode(code: Int): Flag {
Expand Down
82 changes: 27 additions & 55 deletions AnkiDroid/src/main/java/com/ichi2/anki/Reviewer.kt
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 @@ -87,6 +88,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 @@ -349,6 +351,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 @@ -448,38 +455,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 @@ -678,12 +653,27 @@ open class Reviewer :
startActivityWithAnimation(intent, animation)
}

private val flagItemIds = mutableSetOf<Int>()

private fun addFlags(subMenu: SubMenu?) {
lifecycleScope.launch {
for (flag in Flag.entries) {
val title = flag.getName(resources)
val menuItem = subMenu?.add(Menu.NONE, flag.ordinal, Menu.NONE, title)?.setIcon(flag.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 @@ -695,23 +685,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 @@ -835,11 +808,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 @@ -853,10 +829,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
Expand Up @@ -122,6 +122,14 @@ class PreviewerFragment :
}
}

lifecycleScope.launch {
val submenu = menu.findItem(R.id.action_flag).subMenu
for (flag in Flag.entries) {
val title = flag.getName(resources)
submenu?.add(Menu.NONE, flag.ordinal, Menu.NONE, title)?.setIcon(flag.drawableRes)
}
}

lifecycleScope.launch {
viewModel.flagCode
.flowWithLifecycle(lifecycle)
Expand Down Expand Up @@ -188,18 +196,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

0 comments on commit 3ba4f9a

Please sign in to comment.