ditch marked tag in favour of card flags
Users can now mark individual cards with one of four different coloured flags, instead of relying on a tag that applied to the whole note. - replaced marking functionality in reviewer and browser with new flag options - added flag:x search - marked and leech tags now show in normal tag list in filter screen, instead of being treated specially - the other clients will need updating to set and shown the flags, but flags set in the beta should be preserved by the other clients
This commit is contained in:
parent
6bbd6d2dd5
commit
71101d041a
@ -187,3 +187,10 @@ lapses=?, left=?, odue=?, odid=?, did=? where id = ?""",
|
|||||||
del d['col']
|
del d['col']
|
||||||
del d['timerStarted']
|
del d['timerStarted']
|
||||||
return pprint.pformat(d, width=300)
|
return pprint.pformat(d, width=300)
|
||||||
|
|
||||||
|
def userFlag(self):
|
||||||
|
return self.flags & 0b111
|
||||||
|
|
||||||
|
def setUserFlag(self, flag):
|
||||||
|
assert 0 <= flag <= 7
|
||||||
|
self.flags = (self.flags & ~0b111) | flag
|
||||||
|
@ -850,3 +850,11 @@ and queue = 0""", intTime(), self.usn())
|
|||||||
|
|
||||||
def _closeLog(self):
|
def _closeLog(self):
|
||||||
self._logHnd = None
|
self._logHnd = None
|
||||||
|
|
||||||
|
# Card Flags
|
||||||
|
##########################################################################
|
||||||
|
|
||||||
|
def setUserFlag(self, flag, cids):
|
||||||
|
assert 0 <= flag <= 7
|
||||||
|
self.db.execute("update cards set flags = (flags & ~?) | ? where id in %s" %
|
||||||
|
ids2str(cids), 0b111, flag)
|
||||||
|
@ -29,6 +29,7 @@ class Finder:
|
|||||||
rated=self._findRated,
|
rated=self._findRated,
|
||||||
tag=self._findTag,
|
tag=self._findTag,
|
||||||
dupe=self._findDupes,
|
dupe=self._findDupes,
|
||||||
|
flag=self._findFlag,
|
||||||
)
|
)
|
||||||
self.search['is'] = self._findCardState
|
self.search['is'] = self._findCardState
|
||||||
runHook("search", self.search)
|
runHook("search", self.search)
|
||||||
@ -271,6 +272,14 @@ select distinct(n.id) from cards c, notes n where c.nid=n.id and """+preds
|
|||||||
(c.queue = 1 and c.due <= %d)""" % (
|
(c.queue = 1 and c.due <= %d)""" % (
|
||||||
self.col.sched.today, self.col.sched.dayCutoff)
|
self.col.sched.today, self.col.sched.dayCutoff)
|
||||||
|
|
||||||
|
def _findFlag(self, args):
|
||||||
|
(val, args) = args
|
||||||
|
if not val or val not in "01234":
|
||||||
|
return
|
||||||
|
val = int(val)
|
||||||
|
mask = 2**3 - 1
|
||||||
|
return "(c.flags & %d) == %d" % (mask, val)
|
||||||
|
|
||||||
def _findRated(self, args):
|
def _findRated(self, args):
|
||||||
# days(:optional_ease)
|
# days(:optional_ease)
|
||||||
(val, args) = args
|
(val, args) = args
|
||||||
|
@ -24,11 +24,6 @@ from aqt.webview import AnkiWebView
|
|||||||
from anki.consts import *
|
from anki.consts import *
|
||||||
from anki.sound import playFromText, clearAudioQueue
|
from anki.sound import playFromText, clearAudioQueue
|
||||||
|
|
||||||
COLOUR_SUSPENDED = "#FFFFB2"
|
|
||||||
COLOUR_MARKED = "#D9B2E9"
|
|
||||||
|
|
||||||
# fixme: need to refresh after undo
|
|
||||||
|
|
||||||
# Data model
|
# Data model
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
|
||||||
@ -318,6 +313,15 @@ class DataModel(QAbstractTableModel):
|
|||||||
# Line painter
|
# Line painter
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
COLOUR_SUSPENDED = "#FFFFB2"
|
||||||
|
|
||||||
|
flagColours = {
|
||||||
|
1: "#F5B7B1",
|
||||||
|
2: "#BB8FCE",
|
||||||
|
3: "#82E0AA",
|
||||||
|
4: "#85C1E9",
|
||||||
|
}
|
||||||
|
|
||||||
class StatusDelegate(QItemDelegate):
|
class StatusDelegate(QItemDelegate):
|
||||||
|
|
||||||
def __init__(self, browser, model):
|
def __init__(self, browser, model):
|
||||||
@ -335,16 +339,19 @@ class StatusDelegate(QItemDelegate):
|
|||||||
return
|
return
|
||||||
finally:
|
finally:
|
||||||
self.browser.mw.progress.blockUpdates = True
|
self.browser.mw.progress.blockUpdates = True
|
||||||
|
|
||||||
col = None
|
col = None
|
||||||
if c.note().hasTag("Marked"):
|
if c.queue == -1:
|
||||||
col = COLOUR_MARKED
|
|
||||||
elif c.queue == -1:
|
|
||||||
col = COLOUR_SUSPENDED
|
col = COLOUR_SUSPENDED
|
||||||
|
elif c.userFlag() > 0:
|
||||||
|
col = flagColours[c.userFlag()]
|
||||||
|
|
||||||
if col:
|
if col:
|
||||||
brush = QBrush(QColor(col))
|
brush = QBrush(QColor(col))
|
||||||
painter.save()
|
painter.save()
|
||||||
painter.fillRect(option.rect, brush)
|
painter.fillRect(option.rect, brush)
|
||||||
painter.restore()
|
painter.restore()
|
||||||
|
|
||||||
return QItemDelegate.paint(self, painter, option, index)
|
return QItemDelegate.paint(self, painter, option, index)
|
||||||
|
|
||||||
# Browser window
|
# Browser window
|
||||||
@ -403,7 +410,6 @@ class Browser(QMainWindow):
|
|||||||
f.actionChangeModel.triggered.connect(self.onChangeModel)
|
f.actionChangeModel.triggered.connect(self.onChangeModel)
|
||||||
f.actionFindDuplicates.triggered.connect(self.onFindDupes)
|
f.actionFindDuplicates.triggered.connect(self.onFindDupes)
|
||||||
f.actionFindReplace.triggered.connect(self.onFindReplace)
|
f.actionFindReplace.triggered.connect(self.onFindReplace)
|
||||||
f.actionToggle_Mark.triggered.connect(lambda: self.onMark())
|
|
||||||
f.actionDelete.triggered.connect(self.deleteNotes)
|
f.actionDelete.triggered.connect(self.deleteNotes)
|
||||||
# cards
|
# cards
|
||||||
f.actionChange_Deck.triggered.connect(self.setDeck)
|
f.actionChange_Deck.triggered.connect(self.setDeck)
|
||||||
@ -411,6 +417,11 @@ class Browser(QMainWindow):
|
|||||||
f.actionReposition.triggered.connect(self.reposition)
|
f.actionReposition.triggered.connect(self.reposition)
|
||||||
f.actionReschedule.triggered.connect(self.reschedule)
|
f.actionReschedule.triggered.connect(self.reschedule)
|
||||||
f.actionToggle_Suspend.triggered.connect(self.onSuspend)
|
f.actionToggle_Suspend.triggered.connect(self.onSuspend)
|
||||||
|
f.actionRed_Flag.triggered.connect(lambda: self.onSetFlag(1))
|
||||||
|
f.actionPurple_Flag.triggered.connect(lambda: self.onSetFlag(2))
|
||||||
|
f.actionGreen_Flag.triggered.connect(lambda: self.onSetFlag(3))
|
||||||
|
f.actionBlue_Flag.triggered.connect(lambda: self.onSetFlag(4))
|
||||||
|
f.actionClear_Flag.triggered.connect(lambda: self.onSetFlag(0))
|
||||||
# jumps
|
# jumps
|
||||||
f.actionPreviousCard.triggered.connect(self.onPreviousCard)
|
f.actionPreviousCard.triggered.connect(self.onPreviousCard)
|
||||||
f.actionNextCard.triggered.connect(self.onNextCard)
|
f.actionNextCard.triggered.connect(self.onNextCard)
|
||||||
@ -743,11 +754,10 @@ by clicking on one on the left."""))
|
|||||||
|
|
||||||
self._addTodayFilters(m)
|
self._addTodayFilters(m)
|
||||||
self._addCardStateFilters(m)
|
self._addCardStateFilters(m)
|
||||||
m.addSeparator()
|
|
||||||
|
|
||||||
self._addDeckFilters(m)
|
self._addDeckFilters(m)
|
||||||
self._addNoteTypeFilters(m)
|
self._addNoteTypeFilters(m)
|
||||||
self._addTagFilters(m)
|
self._addTagFilters(m)
|
||||||
|
|
||||||
self._addSavedSearches(m)
|
self._addSavedSearches(m)
|
||||||
|
|
||||||
m.exec_(self.form.filter.mapToGlobal(QPoint(0,0)))
|
m.exec_(self.form.filter.mapToGlobal(QPoint(0,0)))
|
||||||
@ -793,10 +803,7 @@ by clicking on one on the left."""))
|
|||||||
def _addCommonFilters(self, m):
|
def _addCommonFilters(self, m):
|
||||||
items = (
|
items = (
|
||||||
(_("Whole Collection"), ""),
|
(_("Whole Collection"), ""),
|
||||||
(_("Current Deck"), "deck:current"),
|
(_("Current Deck"), "deck:current"))
|
||||||
None,
|
|
||||||
(_("Marked"), "tag:marked"),
|
|
||||||
(_("Leech"), "tag:leech"))
|
|
||||||
self._addSimpleFilters(m, items)
|
self._addSimpleFilters(m, items)
|
||||||
|
|
||||||
def _addTodayFilters(self, m):
|
def _addTodayFilters(self, m):
|
||||||
@ -816,7 +823,15 @@ by clicking on one on the left."""))
|
|||||||
(_("Due"), "is:due"),
|
(_("Due"), "is:due"),
|
||||||
None,
|
None,
|
||||||
(_("Suspended"), "is:suspended"),
|
(_("Suspended"), "is:suspended"),
|
||||||
(_("Buried"), "is:buried"))
|
(_("Buried"), "is:buried"),
|
||||||
|
None,
|
||||||
|
(_("Red Flag"), "flag:1"),
|
||||||
|
(_("Purple Flag"), "flag:2"),
|
||||||
|
(_("Green Flag"), "flag:3"),
|
||||||
|
(_("Blue Flag"), "flag:4"),
|
||||||
|
(_("No Flag"), "flag:0"),
|
||||||
|
(_("Any Flag"), "-flag:0"),
|
||||||
|
)
|
||||||
self._addSimpleFilters(m, items)
|
self._addSimpleFilters(m, items)
|
||||||
|
|
||||||
_tagsMenuSize = 30
|
_tagsMenuSize = 30
|
||||||
@ -847,8 +862,6 @@ by clicking on one on the left."""))
|
|||||||
|
|
||||||
def _addTagFilterBlock(self, m, tags):
|
def _addTagFilterBlock(self, m, tags):
|
||||||
for t in tags:
|
for t in tags:
|
||||||
if t.lower() == "marked" or t.lower() == "leech":
|
|
||||||
continue
|
|
||||||
a = m.addAction(t)
|
a = m.addAction(t)
|
||||||
a.triggered.connect(lambda *, tag=t: self.setFilter("tag", tag))
|
a.triggered.connect(lambda *, tag=t: self.setFilter("tag", tag))
|
||||||
|
|
||||||
@ -1338,7 +1351,7 @@ update cards set usn=?, mod=?, did=? where id in """ + scids,
|
|||||||
def _clearUnusedTags(self):
|
def _clearUnusedTags(self):
|
||||||
self.col.tags.registerNotes()
|
self.col.tags.registerNotes()
|
||||||
|
|
||||||
# Suspending and marking
|
# Suspending
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
def isSuspended(self):
|
def isSuspended(self):
|
||||||
@ -1357,16 +1370,12 @@ update cards set usn=?, mod=?, did=? where id in """ + scids,
|
|||||||
self.model.reset()
|
self.model.reset()
|
||||||
self.mw.requireReset()
|
self.mw.requireReset()
|
||||||
|
|
||||||
def isMarked(self):
|
# Flags
|
||||||
return not not (self.card and self.card.note().hasTag("Marked"))
|
######################################################################
|
||||||
|
|
||||||
def onMark(self, mark=None):
|
def onSetFlag(self, n):
|
||||||
if mark is None:
|
self.col.setUserFlag(n, self.selectedCards())
|
||||||
mark = not self.isMarked()
|
self.model.reset()
|
||||||
if mark:
|
|
||||||
self.addTags(tags="marked", label=False)
|
|
||||||
else:
|
|
||||||
self.deleteTags(tags="marked", label=False)
|
|
||||||
|
|
||||||
# Repositioning
|
# Repositioning
|
||||||
######################################################################
|
######################################################################
|
||||||
|
@ -120,7 +120,7 @@ class Reviewer:
|
|||||||
def revHtml(self):
|
def revHtml(self):
|
||||||
extra = self.mw.col.conf.get("reviewExtra", "")
|
extra = self.mw.col.conf.get("reviewExtra", "")
|
||||||
return f"""
|
return f"""
|
||||||
<img src="/_anki/imgs/rating.png" id=star class=marked>
|
<div id=_flag>⚑</div>
|
||||||
<div id=qa></div>
|
<div id=qa></div>
|
||||||
{extra}
|
{extra}
|
||||||
"""
|
"""
|
||||||
@ -170,7 +170,7 @@ The front of this card is empty. Please run Tools>Empty Cards.""")
|
|||||||
bodyclass = "card card%d" % (c.ord+1)
|
bodyclass = "card card%d" % (c.ord+1)
|
||||||
|
|
||||||
self.web.eval("_showQuestion(%s,'%s');" % (json.dumps(q), bodyclass))
|
self.web.eval("_showQuestion(%s,'%s');" % (json.dumps(q), bodyclass))
|
||||||
self._toggleStar()
|
self._drawFlag()
|
||||||
self._showAnswerButton()
|
self._showAnswerButton()
|
||||||
# if we have a type answer field, focus main web
|
# if we have a type answer field, focus main web
|
||||||
if self.typeCorrect:
|
if self.typeCorrect:
|
||||||
@ -187,9 +187,8 @@ The front of this card is empty. Please run Tools>Empty Cards.""")
|
|||||||
return s.mw.col.decks.confForDid(
|
return s.mw.col.decks.confForDid(
|
||||||
s.card.odid or s.card.did).get('replayq', True)
|
s.card.odid or s.card.did).get('replayq', True)
|
||||||
|
|
||||||
def _toggleStar(self):
|
def _drawFlag(self):
|
||||||
self.web.eval("_toggleStar(%s);" % json.dumps(
|
self.web.eval("_drawFlag(%s);" % self.card.userFlag())
|
||||||
self.card.note().hasTag("marked")))
|
|
||||||
|
|
||||||
# Showing the answer
|
# Showing the answer
|
||||||
##########################################################################
|
##########################################################################
|
||||||
@ -239,7 +238,11 @@ The front of this card is empty. Please run Tools>Empty Cards.""")
|
|||||||
(Qt.Key_Enter, self.onEnterKey),
|
(Qt.Key_Enter, self.onEnterKey),
|
||||||
("r", self.replayAudio),
|
("r", self.replayAudio),
|
||||||
(Qt.Key_F5, self.replayAudio),
|
(Qt.Key_F5, self.replayAudio),
|
||||||
("*", self.onMark),
|
("Ctrl+1", lambda: self.setFlag(1)),
|
||||||
|
("Ctrl+2", lambda: self.setFlag(2)),
|
||||||
|
("Ctrl+3", lambda: self.setFlag(3)),
|
||||||
|
("Ctrl+4", lambda: self.setFlag(4)),
|
||||||
|
("Ctrl+0", lambda: self.setFlag(0)),
|
||||||
("=", self.onBuryNote),
|
("=", self.onBuryNote),
|
||||||
("-", self.onBuryCard),
|
("-", self.onBuryCard),
|
||||||
("!", self.onSuspend),
|
("!", self.onSuspend),
|
||||||
@ -564,7 +567,13 @@ time = %(time)d;
|
|||||||
# note the shortcuts listed here also need to be defined above
|
# note the shortcuts listed here also need to be defined above
|
||||||
def showContextMenu(self):
|
def showContextMenu(self):
|
||||||
opts = [
|
opts = [
|
||||||
[_("Mark Note"), "*", self.onMark],
|
[_("Flag Card"), [
|
||||||
|
[_("Red Flag"), "Ctrl+1", lambda: self.setFlag(1)],
|
||||||
|
[_("Purple Flag"), "Ctrl+2", lambda: self.setFlag(2)],
|
||||||
|
[_("Green Flag"), "Ctrl+3", lambda: self.setFlag(3)],
|
||||||
|
[_("Blue Flag"), "Ctrl+4", lambda: self.setFlag(4)],
|
||||||
|
[_("No Flag"), "Ctrl+5", lambda: self.setFlag(0)],
|
||||||
|
]],
|
||||||
[_("Bury Card"), "-", self.onBuryCard],
|
[_("Bury Card"), "-", self.onBuryCard],
|
||||||
[_("Bury Note"), "=", self.onBuryNote],
|
[_("Bury Note"), "=", self.onBuryNote],
|
||||||
[_("Suspend Card"), "@", self.onSuspendCard],
|
[_("Suspend Card"), "@", self.onSuspendCard],
|
||||||
@ -577,30 +586,35 @@ time = %(time)d;
|
|||||||
[_("Replay Own Voice"), "V", self.onReplayRecorded],
|
[_("Replay Own Voice"), "V", self.onReplayRecorded],
|
||||||
]
|
]
|
||||||
m = QMenu(self.mw)
|
m = QMenu(self.mw)
|
||||||
for row in opts:
|
self._addMenuItems(m, opts)
|
||||||
|
|
||||||
|
runHook("Reviewer.contextMenuEvent",self,m)
|
||||||
|
m.exec_(QCursor.pos())
|
||||||
|
|
||||||
|
def _addMenuItems(self, m, rows):
|
||||||
|
for row in rows:
|
||||||
if not row:
|
if not row:
|
||||||
m.addSeparator()
|
m.addSeparator()
|
||||||
continue
|
continue
|
||||||
|
if len(row) == 2:
|
||||||
|
subm = m.addMenu(row[0])
|
||||||
|
self._addMenuItems(subm, row[1])
|
||||||
|
continue
|
||||||
label, scut, func = row
|
label, scut, func = row
|
||||||
a = m.addAction(label)
|
a = m.addAction(label)
|
||||||
if scut:
|
if scut:
|
||||||
a.setShortcut(QKeySequence(scut))
|
a.setShortcut(QKeySequence(scut))
|
||||||
a.triggered.connect(func)
|
a.triggered.connect(func)
|
||||||
runHook("Reviewer.contextMenuEvent",self,m)
|
|
||||||
m.exec_(QCursor.pos())
|
|
||||||
|
|
||||||
def onOptions(self):
|
def onOptions(self):
|
||||||
self.mw.onDeckConf(self.mw.col.decks.get(
|
self.mw.onDeckConf(self.mw.col.decks.get(
|
||||||
self.card.odid or self.card.did))
|
self.card.odid or self.card.did))
|
||||||
|
|
||||||
def onMark(self):
|
def setFlag(self, flag):
|
||||||
f = self.card.note()
|
self.card.setUserFlag(flag)
|
||||||
if f.hasTag("marked"):
|
self.card.flush()
|
||||||
f.delTag("marked")
|
self._drawFlag()
|
||||||
else:
|
|
||||||
f.addTag("marked")
|
|
||||||
f.flush()
|
|
||||||
self._toggleStar()
|
|
||||||
|
|
||||||
def onSuspend(self):
|
def onSuspend(self):
|
||||||
self.mw.checkpoint(_("Suspend"))
|
self.mw.checkpoint(_("Suspend"))
|
||||||
|
@ -268,6 +268,17 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>&Cards</string>
|
<string>&Cards</string>
|
||||||
</property>
|
</property>
|
||||||
|
<widget class="QMenu" name="menuFlag">
|
||||||
|
<property name="title">
|
||||||
|
<string>Flag</string>
|
||||||
|
</property>
|
||||||
|
<addaction name="actionRed_Flag"/>
|
||||||
|
<addaction name="actionPurple_Flag"/>
|
||||||
|
<addaction name="actionGreen_Flag"/>
|
||||||
|
<addaction name="actionBlue_Flag"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionClear_Flag"/>
|
||||||
|
</widget>
|
||||||
<addaction name="actionChange_Deck"/>
|
<addaction name="actionChange_Deck"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionReschedule"/>
|
<addaction name="actionReschedule"/>
|
||||||
@ -275,6 +286,8 @@
|
|||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionToggle_Suspend"/>
|
<addaction name="actionToggle_Suspend"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
<addaction name="menuFlag"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
<addaction name="action_Info"/>
|
<addaction name="action_Info"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menu_Notes">
|
<widget class="QMenu" name="menu_Notes">
|
||||||
@ -291,8 +304,6 @@
|
|||||||
<addaction name="actionFindDuplicates"/>
|
<addaction name="actionFindDuplicates"/>
|
||||||
<addaction name="actionFindReplace"/>
|
<addaction name="actionFindReplace"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionToggle_Mark"/>
|
|
||||||
<addaction name="separator"/>
|
|
||||||
<addaction name="actionDelete"/>
|
<addaction name="actionDelete"/>
|
||||||
</widget>
|
</widget>
|
||||||
<addaction name="menuEdit"/>
|
<addaction name="menuEdit"/>
|
||||||
@ -502,12 +513,44 @@
|
|||||||
<string>Ctrl+D</string>
|
<string>Ctrl+D</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionToggle_Mark">
|
<action name="actionClear_Flag">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Toggle Mark</string>
|
<string>Clear Flag</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="shortcut">
|
<property name="shortcut">
|
||||||
<string>Ctrl+K</string>
|
<string>Ctrl+0</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionRed_Flag">
|
||||||
|
<property name="text">
|
||||||
|
<string>Red Flag</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+1</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionPurple_Flag">
|
||||||
|
<property name="text">
|
||||||
|
<string>Purple Flag</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+2</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionGreen_Flag">
|
||||||
|
<property name="text">
|
||||||
|
<string>Green Flag</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+3</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
|
<action name="actionBlue_Flag">
|
||||||
|
<property name="text">
|
||||||
|
<string>Blue Flag</string>
|
||||||
|
</property>
|
||||||
|
<property name="shortcut">
|
||||||
|
<string>Ctrl+4</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
|
41
tests/test_flags.py
Normal file
41
tests/test_flags.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
from tests.shared import assertException, getEmptyCol
|
||||||
|
|
||||||
|
def test_flags():
|
||||||
|
col = getEmptyCol()
|
||||||
|
n = col.newNote()
|
||||||
|
n['Front'] = "one"; n['Back'] = "two"
|
||||||
|
cnt = col.addNote(n)
|
||||||
|
c = n.cards()[0]
|
||||||
|
# make sure higher bits are preserved
|
||||||
|
origBits = 0b101 << 3
|
||||||
|
c.flags = origBits
|
||||||
|
c.flush()
|
||||||
|
# no flags to start with
|
||||||
|
assert c.userFlag() == 0
|
||||||
|
assert len(col.findCards("flag:0")) == 1
|
||||||
|
assert len(col.findCards("flag:1")) == 0
|
||||||
|
# set flag 2
|
||||||
|
col.setUserFlag(2, [c.id])
|
||||||
|
c.load()
|
||||||
|
print("db is", col.db.all("select id, flags from cards"))
|
||||||
|
assert c.userFlag() == 2
|
||||||
|
assert c.flags & origBits == origBits
|
||||||
|
assert len(col.findCards("flag:0")) == 0
|
||||||
|
assert len(col.findCards("flag:2")) == 1
|
||||||
|
assert len(col.findCards("flag:3")) == 0
|
||||||
|
# change to 3
|
||||||
|
col.setUserFlag(3, [c.id])
|
||||||
|
c.load()
|
||||||
|
assert c.userFlag() == 3
|
||||||
|
# unset
|
||||||
|
col.setUserFlag(0, [c.id])
|
||||||
|
c.load()
|
||||||
|
assert c.userFlag() == 0
|
||||||
|
|
||||||
|
# should work with Cards method as well
|
||||||
|
c.setUserFlag(2)
|
||||||
|
assert c.userFlag() == 2
|
||||||
|
c.setUserFlag(3)
|
||||||
|
assert c.userFlag() == 3
|
||||||
|
c.setUserFlag(0)
|
||||||
|
assert c.userFlag() == 0
|
Binary file not shown.
Before Width: | Height: | Size: 2.4 KiB |
@ -1,7 +1,9 @@
|
|||||||
hr { background-color:#ccc; margin: 1em; }
|
hr { background-color:#ccc; margin: 1em; }
|
||||||
body { margin:1.5em; }
|
body { margin:1.5em; }
|
||||||
img { max-width: 95%; max-height: 95%; }
|
img { max-width: 95%; max-height: 95%; }
|
||||||
.marked { position:fixed; right: 7px; top: 7px; width: 24px; height: 24px; display: none; }
|
#_flag {
|
||||||
|
position:fixed; right: 7px; top: 0px; font-size: 30px; display: none;
|
||||||
|
}
|
||||||
#typeans { width: 100%; }
|
#typeans { width: 100%; }
|
||||||
.typeGood { background: #0f0; }
|
.typeGood { background: #0f0; }
|
||||||
.typeBad { background: #f00; }
|
.typeBad { background: #f00; }
|
||||||
|
@ -59,12 +59,21 @@ function _showAnswer(a, bodyclass) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function _toggleStar(show) {
|
_flagColours = {
|
||||||
if (show) {
|
1: "red",
|
||||||
$(".marked").show();
|
2: "purple",
|
||||||
} else {
|
3: "green",
|
||||||
$(".marked").hide();
|
4: "blue"
|
||||||
|
};
|
||||||
|
|
||||||
|
function _drawFlag(flag) {
|
||||||
|
var elem = $("#_flag");
|
||||||
|
if (flag === 0) {
|
||||||
|
elem.hide();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
elem.show();
|
||||||
|
elem.css("color", _flagColours[flag]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _typeAnsPress() {
|
function _typeAnsPress() {
|
||||||
|
Loading…
Reference in New Issue
Block a user