Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Rework reschedule tool
The old rescheduling dialog's two options have been split into two
separate menu items, "Forget", and "Set Due Date"

For cards that are not review cards, "Set Due Date" behaves like the
old reschedule option, changing the cards into a review card, and
and setting both the interval and due date to the provided number of
days.

When "Set Due Date" is applied to a review card, it no longer resets
the card's interval. Instead, it looks at how much the provided number
of days will change the original interval, and adjusts the interval by
that amount, so that cards that are answered earlier receive a smaller
next interval, and cards that are answered after a longer delay receive
a bonus.

For example, imagine a card was answered on day 5, and given an interval
of 10 days, so it has a due date of day 15.

- if on day 10 the due date is changed to day 12 (today+2), the card
is being scheduled 3 days earlier than it was supposed to be, so the
interval will be adjusted to 7 days.
- and if on day 10 the due date is changed to day 20, the interval will
be changed from 10 days to 15 days.

There is no separate option to reset the interval of a review card, but
it can be accomplished by forgetting the card(s), and then setting the
desired due date.

Other notes:

- Added the action to the review screen as well.
- Set the shortcut to Ctrl+Shift+D, and changed the existing Delete
Tags shortcut to Ctrl+Alt+Shift+A.
  • Loading branch information
dae committed Feb 7, 2021
1 parent c91a378 commit 704b5e5
Show file tree
Hide file tree
Showing 24 changed files with 359 additions and 336 deletions.
1 change: 1 addition & 0 deletions ftl/core/actions.ftl
Expand Up @@ -33,3 +33,4 @@ actions-search = Search
actions-shortcut-key = Shortcut key: { $val }
actions-suspend-card = Suspend Card
actions-set-due-date = Set Due Date
actions-forget = Forget
2 changes: 0 additions & 2 deletions ftl/core/browsing.ftl
Expand Up @@ -66,8 +66,6 @@ browsing-optional-filter = Optional filter:
browsing-override-back-template = Override back template:
browsing-override-font = Override font:
browsing-override-front-template = Override front template:
browsing-place-at-end-of-new-card = Place at end of new card queue
browsing-place-in-review-queue-with-interval = Place in review queue with interval between:
browsing-please-give-your-filter-a-name = Please give your filter a name:
browsing-please-select-cards-from-only-one = Please select cards from only one note type.
browsing-preview-selected-card = Preview Selected Card ({ $val })
Expand Down
16 changes: 16 additions & 0 deletions ftl/core/scheduling.ftl
Expand Up @@ -143,3 +143,19 @@ scheduling-deck-updated =
[one] { $count } deck updated.
*[other] { $count } decks updated.
}
scheduling-set-due-date-prompt =
{ $cards ->
[one] Show card in how many days?
*[other] Show cards in how many days? (eg 1, or 1..7)
}
scheduling-set-due-date-changed-cards =
{ $cards ->
[one] Changed card's due date.
*[other] Changed due date of { $cards } cards.
}
scheduling-set-due-date-invalid-input = Expected a number or range (eg 1, or 1..7)
scheduling-forgot-cards =
{ $cards ->
[one] { $cards } card placed at the end of the new card queue.
*[other] { $cards } cards placed at the end of the new card queue.
}
3 changes: 2 additions & 1 deletion ftl/qt/qt-accel.ftl
Expand Up @@ -24,10 +24,11 @@ qt-accel-notes = &Notes
qt-accel-open-addons-folder = &Open Add-ons Folder...
qt-accel-preferences = &Preferences...
qt-accel-previous-card = &Previous Card
qt-accel-reschedule = &Reschedule...
qt-accel-select-all = Select &All
qt-accel-select-notes = Select &Notes
qt-accel-support-anki = &Support Anki...
qt-accel-switch-profile = &Switch Profile
qt-accel-tools = &Tools
qt-accel-undo = &Undo
qt-accel-set-due-date = Set &Due Date...
qt-accel-forget = &Forget
19 changes: 10 additions & 9 deletions pylib/anki/schedv2.py
Expand Up @@ -1397,20 +1397,17 @@ def _burySiblings(self, card: Card) -> None:
if toBury:
self.bury_cards(toBury, manual=False)

# Resetting
# Resetting/rescheduling
##########################################################################

def schedule_cards_as_new(self, card_ids: List[int]) -> None:
"Put cards at the end of the new queue."
self.col._backend.schedule_cards_as_new(card_ids=card_ids, log=True)

def schedule_cards_as_reviews(
self, card_ids: List[int], min_interval: int, max_interval: int
) -> None:
"Make cards review cards, with a new interval randomly selected from range."
self.col._backend.schedule_cards_as_reviews(
card_ids=card_ids, min_interval=min_interval, max_interval=max_interval
)
def set_due_date(self, card_ids: List[int], days: str) -> None:
"""Set cards to be due in `days`, turning them into review cards if necessary.
`days` can be of the form '5' or '5..7'"""
self.col._backend.set_due_date(card_ids=card_ids, days=days)

def resetCards(self, ids: List[int]) -> None:
"Completely reset cards for export."
Expand All @@ -1430,8 +1427,12 @@ def resetCards(self, ids: List[int]) -> None:

# legacy

def reschedCards(
self, card_ids: List[int], min_interval: int, max_interval: int
) -> None:
self.set_due_date(card_ids, f"{min_interval}..{max_interval}")

forgetCards = schedule_cards_as_new
reschedCards = schedule_cards_as_reviews

# Repositioning new cards
##########################################################################
Expand Down
17 changes: 0 additions & 17 deletions pylib/tests/test_schedv1.py
Expand Up @@ -1077,23 +1077,6 @@ def test_forget():
assert col.sched.counts() == (1, 0, 0)


def test_resched():
col = getEmptyCol()
note = col.newNote()
note["Front"] = "one"
col.addNote(note)
c = note.cards()[0]
col.sched.reschedCards([c.id], 0, 0)
c.load()
assert c.due == col.sched.today
assert c.ivl == 1
assert c.queue == CARD_TYPE_REV and c.type == QUEUE_TYPE_REV
col.sched.reschedCards([c.id], 1, 1)
c.load()
assert c.due == col.sched.today + 1
assert c.ivl == +1


def test_norelearn():
col = getEmptyCol()
# add a note
Expand Down
9 changes: 8 additions & 1 deletion pylib/tests/test_schedv2.py
Expand Up @@ -1124,10 +1124,17 @@ def test_resched():
assert c.due == col.sched.today
assert c.ivl == 1
assert c.queue == QUEUE_TYPE_REV and c.type == CARD_TYPE_REV
# make it due tomorrow, which increases its interval by a day
col.sched.reschedCards([c.id], 1, 1)
c.load()
assert c.due == col.sched.today + 1
assert c.ivl == +1
assert c.ivl == 2
# but if it was new, that would not happen
col.sched.forgetCards([c.id])
col.sched.reschedCards([c.id], 1, 1)
c.load()
assert c.due == col.sched.today + 1
assert c.ivl == 1


def test_norelearn():
Expand Down
51 changes: 27 additions & 24 deletions qt/aqt/browser.py
Expand Up @@ -28,6 +28,7 @@
from aqt.previewer import BrowserPreviewer as PreviewDialog
from aqt.previewer import Previewer
from aqt.qt import *
from aqt.scheduling import forget_cards, set_due_date_dialog
from aqt.sidebar import SidebarSearchBar, SidebarTreeView
from aqt.theme import theme_manager
from aqt.utils import (
Expand Down Expand Up @@ -503,7 +504,8 @@ def setupMenus(self) -> None:
qconnect(f.actionChange_Deck.triggered, self.setDeck)
qconnect(f.action_Info.triggered, self.showCardInfo)
qconnect(f.actionReposition.triggered, self.reposition)
qconnect(f.actionReschedule.triggered, self.reschedule)
qconnect(f.action_set_due_date.triggered, self.set_due_date)
qconnect(f.action_forget.triggered, self.forget_cards)
qconnect(f.actionToggle_Suspend.triggered, self.onSuspend)
qconnect(f.actionRed_Flag.triggered, lambda: self.onSetFlag(1))
qconnect(f.actionOrange_Flag.triggered, lambda: self.onSetFlag(2))
Expand Down Expand Up @@ -1384,32 +1386,33 @@ def _reposition(self) -> None:
self.mw.requireReset(reason=ResetReason.BrowserReposition, context=self)
self.model.endReset()

# Rescheduling
# Scheduling
######################################################################

def reschedule(self) -> None:
self.editor.saveNow(self._reschedule)

def _reschedule(self) -> None:
d = QDialog(self)
disable_help_button(d)
d.setWindowModality(Qt.WindowModal)
frm = aqt.forms.reschedule.Ui_Dialog()
frm.setupUi(d)
if not d.exec_():
return
self.model.beginReset()
self.mw.checkpoint(tr(TR.BROWSING_RESCHEDULE))
if frm.asNew.isChecked():
self.col.sched.forgetCards(self.selectedCards())
else:
fmin = frm.min.value()
fmax = frm.max.value()
fmax = max(fmin, fmax)
self.col.sched.reschedCards(self.selectedCards(), fmin, fmax)
self.search()
def _after_schedule(self) -> None:
self.model.reset()
self.mw.requireReset(reason=ResetReason.BrowserReschedule, context=self)
self.model.endReset()

def set_due_date(self) -> None:
self.editor.saveNow(
lambda: set_due_date_dialog(
mw=self.mw,
parent=self,
card_ids=self.selectedCards(),
default="0",
on_done=self._after_schedule,
)
)

def forget_cards(self) -> None:
self.editor.saveNow(
lambda: forget_cards(
mw=self.mw,
parent=self,
card_ids=self.selectedCards(),
on_done=self._after_schedule,
)
)

# Edit: selection
######################################################################
Expand Down
1 change: 0 additions & 1 deletion qt/aqt/forms/__init__.py
Expand Up @@ -32,7 +32,6 @@
from . import profiles
from . import progress
from . import reposition
from . import reschedule
from . import setgroup
from . import setlang
from . import stats
Expand Down
26 changes: 16 additions & 10 deletions qt/aqt/forms/browser.ui
Expand Up @@ -262,7 +262,8 @@
</widget>
<addaction name="actionChange_Deck"/>
<addaction name="separator"/>
<addaction name="actionReschedule"/>
<addaction name="action_set_due_date"/>
<addaction name="action_forget"/>
<addaction name="actionReposition"/>
<addaction name="separator"/>
<addaction name="actionToggle_Suspend"/>
Expand Down Expand Up @@ -298,14 +299,6 @@
<addaction name="menuJump"/>
<addaction name="menu_Help"/>
</widget>
<action name="actionReschedule">
<property name="text">
<string>QT_ACCEL_RESCHEDULE</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+Alt+R</string>
</property>
</action>
<action name="actionSelectAll">
<property name="text">
<string>QT_ACCEL_SELECT_ALL</string>
Expand Down Expand Up @@ -465,7 +458,7 @@
<string>BROWSING_REMOVE_TAGS</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+Shift+D</string>
<string notr="true">Ctrl+Alt+Shift+A</string>
</property>
</action>
<action name="actionToggle_Suspend">
Expand Down Expand Up @@ -586,6 +579,19 @@
<string notr="true">Ctrl+G</string>
</property>
</action>
<action name="action_set_due_date">
<property name="text">
<string>QT_ACCEL_SET_DUE_DATE</string>
</property>
<property name="shortcut">
<string notr="true">Ctrl+Shift+D</string>
</property>
</action>
<action name="action_forget">
<property name="text">
<string>QT_ACCEL_FORGET</string>
</property>
</action>
</widget>
<resources>
<include location="icons.qrc"/>
Expand Down
30 changes: 0 additions & 30 deletions qt/aqt/forms/build_ui.py
Expand Up @@ -18,33 +18,3 @@

with open(py_file, "w") as file:
file.write(outdata)

# init=aqt/forms/__init__.py
# temp=aqt/forms/scratch
# rm -f $init $temp
# echo "# This file auto-generated by build_ui.sh. Don't edit." > $init
# echo "__all__ = [" >> $init

# echo "Generating forms.."
# for i in designer/*.ui
# do
# base=$(basename $i .ui)
# py="aqt/forms/${base}.py"
# echo " \"$base\"," >> $init
# echo "from . import $base" >> $temp
# if [ $i -nt $py ]; then
# echo " * "$py
# pyuic5 --from-imports $i -o $py.tmp
# (cat <<EOF; tail -n +3 $py.tmp) | perl -p -e 's/(QtGui\.QApplication\.)?_?translate\(".*?", /_(/; s/, None.*/))/' > $py
# # -*- coding: utf-8 -*-
# # pylint: disable=unsubscriptable-object,unused-import
# # EOF
# rm $py.tmp
# fi
# done
# echo "]" >> $init
# cat $temp >> $init
# rm $temp

# echo "Building resources.."
# pyrcc5 designer/icons.qrc -o aqt/forms/icons_rc.py

0 comments on commit 704b5e5

Please sign in to comment.