Skip to content

Commit

Permalink
Rearrangement
Browse files Browse the repository at this point in the history
  • Loading branch information
rpearl committed Feb 19, 2017
1 parent 434111f commit 00461b3
Show file tree
Hide file tree
Showing 3 changed files with 296 additions and 298 deletions.
296 changes: 295 additions & 1 deletion CatchupPlugin.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,296 @@
from catchup import main
from aqt import mw
from aqt.qt import *
from aqt.utils import showInfo

# list of functions that this exposes:

#1) suspend all overdue cards (tag them)
#2) unsuspend oldest n days

#configuration
#
# chosen tag for overdue cards controlled by this app

class CatchupSettings(QDialog):
def add_labeled_widget(self, label, control, small=False):
if not isinstance(label, QLabel):
label = QLabel(label)
self._num_lines += 1
width = 1 if small else 2
self.grid.addWidget( label, self._num_lines, 0, 1, 1)
self.grid.addWidget(control, self._num_lines, 1, 1, width)
return control

def add_rule(self, start=0, width=3):
frame = QFrame()
frame.setFrameShape(QFrame.HLine)
frame.setFrameShadow(QFrame.Sunken)
self._num_lines += 1
self.grid.addWidget(frame, self._num_lines, start, 1, width)

def add_empty(self):
self.add_label("")

def add_widget(self, control, left=True, small=False):
start = 0 if left else 1
width = 1 if small else 3-start
self._num_lines += 1
self.grid.addWidget(control, self._num_lines, start, 1, width)
return control

def add_label(self, label):
ql = QLabel(label)
font = QFont()
font.setBold(True)
ql.setFont(font)
return self.add_widget(ql)

def load_conf(self):
if 'catchup' not in mw.col.conf:
mw.col.conf['catchup'] = {
'query': '',
'unsuspend_query': '',
'tag': 'catchup',
'numdays': 1,
'show_stats': False,
}
mw.col.setMod()
mw.reset()

def display_conf(self):
config = mw.col.conf['catchup']
self.ctl_query.setText(config['query'])
self.ctl_tag.setText(config['tag'])
self.ctl_numdays.setValue(config['numdays'])
self.ctl_unsuspend_query.setText(config['unsuspend_query'])
self.ctl_show_stats.setChecked(config['show_stats'])

def on_accept(self):
if not self.ctl_tag.text():
showInfo('You must specify a tag')
return
config = mw.col.conf['catchup']

old_tag = config['tag']

config['query'] = self.ctl_query.text()
config['unsuspend_query'] = self.ctl_unsuspend_query.text()
config['tag'] = self.ctl_tag.text()
config['numdays'] = self.ctl_numdays.value()
config['show_stats'] = self.ctl_show_stats.isChecked()

cids = mw.col.findCards('tag:%s' % (old_tag,))
for cid in cids:
card = mw.col.getCard(cid)
note = card.note()
note.delTag(old_tag)
note.addTag(config['tag'])
note.flush()

mw.col.setMod()
mw.reset()
self.set_clean_config()

def on_reject(self):
self.display_conf()
self.set_clean_config()
mw.reset()

def do_suspend(self):
config = mw.col.conf['catchup']
query = 'is:due'
if config['query']:
query += ' (%s)' % (config['query'])

cids = mw.col.findCards(query)
for cid in cids:
card = mw.col.getCard(cid)
note = card.note()
note.addTag(config['tag'])
note.flush()
mw.col.sched.suspendCards(cids)
self.update_stats()
showInfo('%d cards suspended' % len(cids))

def get_tagged_cids(self, query=None):
config = mw.col.conf['catchup']
find_query = 'tag:%s is:suspended' % (config['tag'],)
if query:
find_query += ' (%s)' % (query,)
cids = mw.col.findCards(find_query, order='c.type, c.due')

return cids

def _fixup_tags(self, unsuspended):
config = mw.col.conf['catchup']
cids = self.get_tagged_cids()
for cid in cids:
if cid in unsuspended:
continue
card = mw.col.getCard(cid)
note = card.note()
note.addTag(config['tag'])
note.flush()

def do_unsuspend(self):
config = mw.col.conf['catchup']

query = '-is:new '+config['unsuspend_query']

cids = self.get_tagged_cids(query=query)

unsuspended = []

days = set()

for cid in cids:
card = mw.col.getCard(cid)
days.add(card.due)
if len(days) > config['numdays']:
break
note = card.note()
note.delTag(config['tag'])
note.flush()
unsuspended.append(cid)
mw.col.sched.unsuspendCards(unsuspended)

self._fixup_tags(unsuspended)

self.update_stats()
showInfo('%d cards unsuspended' % len(unsuspended))

def do_unsuspend_new(self):
config = mw.col.conf['catchup']
cids = self.get_tagged_cids(query='is:new')
unsuspended = []
for cid in cids:
card = mw.col.getCard(cid)
note = card.note()
note.delTag(config['tag'])
note.flush()
unsuspended.append(cid)
mw.col.sched.unsuspendCards(unsuspended)
self._fixup_tags(unsuspended)

self.update_stats()
showInfo('%d cards unsuspended' % len(unsuspended))


def set_dirty_config(self):
self.ctl_suspend.setEnabled(False)
self.ctl_unsuspend.setEnabled(False)

def set_clean_config(self):
self.ctl_suspend.setEnabled(True)
self.ctl_unsuspend.setEnabled(True)

def toggle_stats(self):
config = mw.col.conf['catchup']
config['show_stats'] = self.ctl_show_stats.isChecked()
mw.col.setMod()
mw.reset()
self.update_stats()

def update_stats(self):
config = mw.col.conf['catchup']
if config['show_stats']:
days = set()

all_cids = self.get_tagged_cids()
new_behind = 0

for cid in all_cids:
card = mw.col.getCard(cid)
if card.type == 2: # review
days.add(card.due)
else:
new_behind += 1
total_behind = len(all_cids)
review_behind = total_behind - new_behind
self.days_behind_label.setText("Days behind")
self.days_behind.setText("%d" % len(days))
self.cards_behind_label.setText("Cards behind")
self.cards_behind.setText("New/Learn: %d\t In review: %d\t Total %d" %
(new_behind, review_behind, total_behind)
)
else:
self.days_behind_label.setText("Intentionally left blank")
self.days_behind.setText("")
self.cards_behind_label.setText("")
self.cards_behind.setText("")

def __init__(self):
QDialog.__init__(self, parent=mw)
self.load_conf()
self.grid = QGridLayout()
self.grid.setSpacing(10)
self._num_lines = 0

self.add_label("Settings")
self.ctl_query = self.add_labeled_widget("Suspend filter", QLineEdit())
self.ctl_tag = self.add_labeled_widget("Catchup tag", QLineEdit())
self.add_empty()
self.ctl_unsuspend_query = self.add_labeled_widget("Unsuspend filter", QLineEdit())
self.ctl_numdays = self.add_labeled_widget("Number of days to unsuspend", QSpinBox(), small=True)

self.ctl_save = self.add_widget(QPushButton("Save settings"), small=True)
self.ctl_cancel = self.add_widget(QPushButton("Undo"), small=True)

self.ctl_save.clicked.connect(self.on_accept)
self.ctl_cancel.clicked.connect(self.on_reject)

self.add_rule()
self.stats_label = self.add_label("Stats")
self.ctl_show_stats = self.add_labeled_widget('Show stats', QCheckBox())

self.days_behind_label = QLabel("Days behind")
self.cards_behind_label = QLabel("Cards behind")

self.days_behind = self.add_labeled_widget(self.days_behind_label, QLabel(""))
self.cards_behind = self.add_labeled_widget(self.cards_behind_label, QLabel(""))
self.update_stats()

self.add_rule()

self.add_label("Actions")
self.ctl_suspend = self.add_widget(QPushButton("Suspend overdue cards"), small=True)
self.ctl_unsuspend = self.add_widget(QPushButton("Unsuspend earliest cards"), small=True)
self.ctl_unsuspend_new = self.add_widget(QPushButton("Unsuspend new/learn cards"), small=True)

self.ctl_suspend.clicked.connect(self.do_suspend)
self.ctl_unsuspend.clicked.connect(self.do_unsuspend)
self.ctl_unsuspend_new.clicked.connect(self.do_unsuspend_new)

self.add_rule()
self.add_widget(QLabel('Check the README for instructions and examples'))
self.ctl_close = self.add_widget(QPushButton("Close"), small=True)
self.ctl_close.clicked.connect(self.close)
self.ctl_close.setDefault(True)


layout_main = QVBoxLayout()
layout_main.addLayout(self.grid)

self.display_conf()

self.ctl_query.textEdited.connect(self.set_dirty_config)
self.ctl_unsuspend_query.textEdited.connect(self.set_dirty_config)
self.ctl_tag.textEdited.connect(self.set_dirty_config)
self.ctl_numdays.valueChanged.connect(self.set_dirty_config)

self.ctl_show_stats.stateChanged.connect(self.toggle_stats)

self.setLayout(layout_main)
self.setMinimumWidth(512)
self.setWindowTitle('CatchUp')

def on_catchup_settings():
dialog = CatchupSettings()
dialog.exec_()

def main():
action = QAction("&CatchUp", mw)
action.triggered.connect(on_catchup_settings)
mw.form.menuTools.addAction(action)

main()
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ This is somewhat antithetical to the Idea of Anki, because you're supposed to do
You could! But I'm lazy. You could do all of this manually, with just suspend and tagging; it wouldn't be very complicated, it would just be fiddly and repetitive. This streamlines it.

## Installation
To install CatchUp, download the [latest .zip release](https://github.com/rpearl/anki-catchup/releases/latest). Extract it and copy `CatchupPlugin.py` and the `catchup `directory to your Anki add-ons directory. Your folder structure should look like this:
- `Documents/Anki/addons/CatchupPlugin.py`
- `Documents/Anki/addons/catchup/*allFilesAndDirectories*`
To install CatchUp, download the [latest .zip release](https://github.com/rpearl/anki-catchup/releases/latest). Extract it and copy `CatchupPlugin.py` to your Anki add-ons directory.

After restarting Anki you should see an entry called CatchUp under the Tools menu.

Expand Down
Loading

0 comments on commit 00461b3

Please sign in to comment.