Merge pull request #1178 from RumovZ/flag-labels

Custom labels for flags
This commit is contained in:
Damien Elmes 2021-05-20 11:59:55 +10:00 committed by GitHub
commit 055f2907ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 123 additions and 78 deletions

View file

@ -42,6 +42,7 @@ from aqt.utils import (
current_top_level_widget, current_top_level_widget,
ensure_editor_saved, ensure_editor_saved,
getTag, getTag,
load_flags,
no_arg_trigger, no_arg_trigger,
openHelp, openHelp,
qtMenuShortcutWorkaround, qtMenuShortcutWorkaround,
@ -136,7 +137,6 @@ class Browser(QMainWindow):
self.sidebar.refresh_if_needed() self.sidebar.refresh_if_needed()
def setupMenus(self) -> None: def setupMenus(self) -> None:
# pylint: disable=unnecessary-lambda
# actions # actions
f = self.form f = self.form
# edit # edit
@ -166,16 +166,15 @@ class Browser(QMainWindow):
qconnect(f.action_set_due_date.triggered, self.set_due_date) qconnect(f.action_set_due_date.triggered, self.set_due_date)
qconnect(f.action_forget.triggered, self.forget_cards) qconnect(f.action_forget.triggered, self.forget_cards)
qconnect(f.actionToggle_Suspend.triggered, self.suspend_selected_cards) qconnect(f.actionToggle_Suspend.triggered, self.suspend_selected_cards)
qconnect(f.actionRed_Flag.triggered, lambda: self.set_flag_of_selected_cards(1))
qconnect( def set_flag_func(desired_flag: int) -> Callable:
f.actionOrange_Flag.triggered, lambda: self.set_flag_of_selected_cards(2) return lambda: self.set_flag_of_selected_cards(desired_flag)
)
qconnect( for flag in load_flags(self.col):
f.actionGreen_Flag.triggered, lambda: self.set_flag_of_selected_cards(3) qconnect(
) getattr(self.form, flag.action).triggered, set_flag_func(flag.index)
qconnect( )
f.actionBlue_Flag.triggered, lambda: self.set_flag_of_selected_cards(4) self._update_flag_labels()
)
qconnect(f.actionExport.triggered, self._on_export_notes) qconnect(f.actionExport.triggered, self._on_export_notes)
# jumps # jumps
qconnect(f.actionPreviousCard.triggered, self.onPreviousCard) qconnect(f.actionPreviousCard.triggered, self.onPreviousCard)
@ -711,18 +710,15 @@ where id in %s"""
flag = self.card and self.card.user_flag() flag = self.card and self.card.user_flag()
flag = flag or 0 flag = flag or 0
flagActions = [ for f in load_flags(self.col):
self.form.actionRed_Flag, getattr(self.form, f.action).setChecked(flag == f.index)
self.form.actionOrange_Flag,
self.form.actionGreen_Flag,
self.form.actionBlue_Flag,
]
for c, act in enumerate(flagActions):
act.setChecked(flag == c + 1)
qtMenuShortcutWorkaround(self.form.menuFlag) qtMenuShortcutWorkaround(self.form.menuFlag)
def _update_flag_labels(self) -> None:
for flag in load_flags(self.col):
getattr(self.form, flag.action).setText(flag.label)
def toggle_mark_of_selected_notes(self, checked: bool) -> None: def toggle_mark_of_selected_notes(self, checked: bool) -> None:
if checked: if checked:
self.add_tags_to_selected_notes(tags=MARKED_TAG) self.add_tags_to_selected_notes(tags=MARKED_TAG)

View file

@ -40,6 +40,7 @@ class SidebarItemType(Enum):
def is_editable(self) -> bool: def is_editable(self) -> bool:
return self in ( return self in (
SidebarItemType.FLAG,
SidebarItemType.SAVED_SEARCH, SidebarItemType.SAVED_SEARCH,
SidebarItemType.DECK, SidebarItemType.DECK,
SidebarItemType.TAG, SidebarItemType.TAG,

View file

@ -35,7 +35,14 @@ from aqt.operations.tag import (
) )
from aqt.qt import * from aqt.qt import *
from aqt.theme import ColoredIcon, theme_manager from aqt.theme import ColoredIcon, theme_manager
from aqt.utils import KeyboardModifiersPressed, askUser, getOnlyText, showWarning, tr from aqt.utils import (
KeyboardModifiersPressed,
askUser,
getOnlyText,
load_flags,
showWarning,
tr,
)
class SidebarStage(Enum): class SidebarStage(Enum):
@ -361,6 +368,8 @@ class SidebarTreeView(QTreeView):
self.rename_saved_search(item, new_name) self.rename_saved_search(item, new_name)
elif item.item_type == SidebarItemType.TAG: elif item.item_type == SidebarItemType.TAG:
self.rename_tag(item, new_name) self.rename_tag(item, new_name)
elif item.item_type == SidebarItemType.FLAG:
self.rename_flag(item, new_name)
# renaming may be asynchronous so always return False # renaming may be asynchronous so always return False
return False return False
@ -600,35 +609,21 @@ class SidebarTreeView(QTreeView):
) )
root.search_node = SearchNode(flag=SearchNode.FLAG_ANY) root.search_node = SearchNode(flag=SearchNode.FLAG_ANY)
type = SidebarItemType.FLAG for flag in load_flags(self.col):
root.add_simple( root.add_child(
tr.actions_red_flag(), SidebarItem(
icon=icon.with_color(colors.FLAG1_FG), name=flag.label,
type=type, icon=flag.icon,
search_node=SearchNode(flag=SearchNode.FLAG_RED), search_node=flag.search_node,
) item_type=SidebarItemType.FLAG,
root.add_simple( id=flag.index,
tr.actions_orange_flag(), )
icon=icon.with_color(colors.FLAG2_FG), )
type=type,
search_node=SearchNode(flag=SearchNode.FLAG_ORANGE),
)
root.add_simple(
tr.actions_green_flag(),
icon=icon.with_color(colors.FLAG3_FG),
type=type,
search_node=SearchNode(flag=SearchNode.FLAG_GREEN),
)
root.add_simple(
tr.actions_blue_flag(),
icon=icon.with_color(colors.FLAG4_FG),
type=type,
search_node=SearchNode(flag=SearchNode.FLAG_BLUE),
)
root.add_simple( root.add_simple(
tr.browsing_no_flag(), tr.browsing_no_flag(),
icon=icon.with_color(colors.DISABLED), icon=icon,
type=type, type=SidebarItemType.FLAG,
search_node=SearchNode(flag=SearchNode.FLAG_NONE), search_node=SearchNode(flag=SearchNode.FLAG_NONE),
) )
@ -872,6 +867,17 @@ class SidebarTreeView(QTreeView):
lambda: set_children_expanded(False), lambda: set_children_expanded(False),
) )
# Flags
###########################
def rename_flag(self, item: SidebarItem, new_name: str) -> None:
labels = self.col.get_config("flagLabels", {})
labels[str(item.id)] = new_name
self.col.set_config("flagLabels", labels)
item.name = new_name
self.browser._update_flag_labels()
self.refresh()
# Decks # Decks
########################### ###########################

View file

@ -51,7 +51,14 @@ from aqt.qt import *
from aqt.sound import av_player, play_clicked_audio, record_audio from aqt.sound import av_player, play_clicked_audio, record_audio
from aqt.theme import theme_manager from aqt.theme import theme_manager
from aqt.toolbar import BottomBar from aqt.toolbar import BottomBar
from aqt.utils import askUserDialog, downArrow, qtMenuShortcutWorkaround, tooltip, tr from aqt.utils import (
askUserDialog,
downArrow,
load_flags,
qtMenuShortcutWorkaround,
tooltip,
tr,
)
from aqt.webview import AnkiWebView from aqt.webview import AnkiWebView
@ -443,7 +450,7 @@ class Reviewer:
def _shortcutKeys( def _shortcutKeys(
self, self,
) -> List[Union[Tuple[str, Callable], Tuple[Qt.Key, Callable]]]: ) -> Sequence[Union[Tuple[str, Callable], Tuple[Qt.Key, Callable]]]:
return [ return [
("e", self.mw.onEditCurrent), ("e", self.mw.onEditCurrent),
(" ", self.onEnterKey), (" ", self.onEnterKey),
@ -452,10 +459,10 @@ class Reviewer:
("m", self.showContextMenu), ("m", self.showContextMenu),
("r", self.replayAudio), ("r", self.replayAudio),
(Qt.Key_F5, self.replayAudio), (Qt.Key_F5, self.replayAudio),
("Ctrl+1", lambda: self.set_flag_on_current_card(1)), *(
("Ctrl+2", lambda: self.set_flag_on_current_card(2)), (f"Ctrl+{flag.index}", self.set_flag_func(flag.index))
("Ctrl+3", lambda: self.set_flag_on_current_card(3)), for flag in load_flags(self.mw.col)
("Ctrl+4", lambda: self.set_flag_on_current_card(4)), ),
("*", self.toggle_mark_on_current_note), ("*", self.toggle_mark_on_current_note),
("=", self.bury_current_note), ("=", self.bury_current_note),
("-", self.bury_current_card), ("-", self.bury_current_card),
@ -905,29 +912,12 @@ time = %(time)d;
tr.studying_flag_card(), tr.studying_flag_card(),
[ [
[ [
tr.actions_red_flag(), flag.label,
"Ctrl+1", f"Ctrl+{flag.index}",
lambda: self.set_flag_on_current_card(1), self.set_flag_func(flag.index),
dict(checked=currentFlag == 1), dict(checked=currentFlag == flag.index),
], ]
[ for flag in load_flags(self.mw.col)
tr.actions_orange_flag(),
"Ctrl+2",
lambda: self.set_flag_on_current_card(2),
dict(checked=currentFlag == 2),
],
[
tr.actions_green_flag(),
"Ctrl+3",
lambda: self.set_flag_on_current_card(3),
dict(checked=currentFlag == 3),
],
[
tr.actions_blue_flag(),
"Ctrl+4",
lambda: self.set_flag_on_current_card(4),
dict(checked=currentFlag == 4),
],
], ],
], ],
[tr.studying_mark_note(), "*", self.toggle_mark_on_current_note], [tr.studying_mark_note(), "*", self.toggle_mark_on_current_note],
@ -998,6 +988,9 @@ time = %(time)d;
redraw_flag redraw_flag
).run_in_background(initiator=self) ).run_in_background(initiator=self)
def set_flag_func(self, desired_flag: int) -> Callable:
return lambda: self.set_flag_on_current_card(desired_flag)
def toggle_mark_on_current_note(self) -> None: def toggle_mark_on_current_note(self) -> None:
def redraw_mark(out: OpChangesWithCount) -> None: def redraw_mark(out: OpChangesWithCount) -> None:
self.card.load() self.card.load()

View file

@ -6,12 +6,14 @@ import os
import re import re
import subprocess import subprocess
import sys import sys
from dataclasses import dataclass
from enum import Enum from enum import Enum
from functools import wraps from functools import wraps
from typing import ( from typing import (
TYPE_CHECKING, TYPE_CHECKING,
Any, Any,
Callable, Callable,
Dict,
List, List,
Literal, Literal,
Optional, Optional,
@ -35,10 +37,12 @@ from PyQt5.QtWidgets import (
import aqt import aqt
from anki import Collection from anki import Collection
from anki.collection import SearchNode
from anki.lang import TR, tr_legacyglobal # pylint: disable=unused-import from anki.lang import TR, tr_legacyglobal # pylint: disable=unused-import
from anki.utils import invalidFilename, isMac, isWin, noBundledLibs, versionWithBuild from anki.utils import invalidFilename, isMac, isWin, noBundledLibs, versionWithBuild
from aqt import colors
from aqt.qt import * from aqt.qt import *
from aqt.theme import theme_manager from aqt.theme import ColoredIcon, theme_manager
if TYPE_CHECKING: if TYPE_CHECKING:
TextFormat = Union[Literal["plain", "rich"]] TextFormat = Union[Literal["plain", "rich"]]
@ -1023,6 +1027,51 @@ def no_arg_trigger(func: Callable) -> Callable:
return pyqtSlot()(func) # type: ignore return pyqtSlot()(func) # type: ignore
@dataclass
class Flag:
index: int
label: str
icon: ColoredIcon
search_node: SearchNode
action: str
def load_flags(col: Collection) -> List[Flag]:
labels = cast(Dict[str, str], col.get_config("flagLabels", {}))
icon = ColoredIcon(path=":/icons/flag.svg", color=colors.DISABLED)
return [
Flag(
1,
labels["1"] if "1" in labels else tr.actions_red_flag(),
icon.with_color(colors.FLAG1_FG),
SearchNode(flag=SearchNode.FLAG_RED),
"actionRed_Flag",
),
Flag(
2,
labels["2"] if "2" in labels else tr.actions_orange_flag(),
icon.with_color(colors.FLAG2_FG),
SearchNode(flag=SearchNode.FLAG_ORANGE),
"actionOrange_Flag",
),
Flag(
3,
labels["3"] if "3" in labels else tr.actions_green_flag(),
icon.with_color(colors.FLAG3_FG),
SearchNode(flag=SearchNode.FLAG_GREEN),
"actionGreen_Flag",
),
Flag(
4,
labels["4"] if "4" in labels else tr.actions_blue_flag(),
icon.with_color(colors.FLAG4_FG),
SearchNode(flag=SearchNode.FLAG_BLUE),
"actionBlue_Flag",
),
]
class KeyboardModifiersPressed: class KeyboardModifiersPressed:
"Util for type-safe checks of currently-pressed modifier keys." "Util for type-safe checks of currently-pressed modifier keys."