mirror of
https://github.com/ankitects/anki.git
synced 2025-11-10 14:47:12 -05:00
Merge pull request #1178 from RumovZ/flag-labels
Custom labels for flags
This commit is contained in:
commit
055f2907ec
5 changed files with 123 additions and 78 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
###########################
|
###########################
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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."
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue