Support suspending new anki cards (#1240)

* Add new option: anki.suspendNewCards

* Update Anki APIs

* Suspend card based on options

* Add setting

* Disable wrap for toggle property
This commit is contained in:
toasted-nutbread 2021-01-14 22:42:11 -05:00 committed by GitHub
parent d9f5d21d15
commit 1dcfbf6ba6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 61 additions and 3 deletions

View File

@ -739,7 +739,8 @@
"kanji", "kanji",
"duplicateScope", "duplicateScope",
"checkForDuplicates", "checkForDuplicates",
"fieldTemplates" "fieldTemplates",
"suspendNewCards"
], ],
"properties": { "properties": {
"enable": { "enable": {
@ -841,6 +842,10 @@
"fieldTemplates": { "fieldTemplates": {
"type": ["string", "null"], "type": ["string", "null"],
"default": null "default": null
},
"suspendNewCards": {
"type": "boolean",
"default": false
} }
} }
}, },

View File

@ -122,6 +122,22 @@ class AnkiConnect {
return await this._invoke('multi', {actions}); return await this._invoke('multi', {actions});
} }
async suspendCards(cardIds) {
if (!this._enabled) { return false; }
await this._checkVersion();
return await this._invoke('suspend', {cards: cardIds});
}
async findCards(query) {
if (!this._enabled) { return []; }
await this._checkVersion();
return await this._invoke('findCards', {query});
}
async findCardsForNote(noteId) {
return await this.findCards(`nid:${noteId}`);
}
getRootDeckName(deckName) { getRootDeckName(deckName) {
const index = deckName.indexOf('::'); const index = deckName.indexOf('::');
return index >= 0 ? deckName.substring(0, index) : deckName; return index >= 0 ? deckName.substring(0, index) : deckName;

View File

@ -97,6 +97,7 @@ class Backend {
['getAnkiNoteInfo', {async: true, contentScript: true, handler: this._onApiGetAnkiNoteInfo.bind(this)}], ['getAnkiNoteInfo', {async: true, contentScript: true, handler: this._onApiGetAnkiNoteInfo.bind(this)}],
['injectAnkiNoteMedia', {async: true, contentScript: true, handler: this._onApiInjectAnkiNoteMedia.bind(this)}], ['injectAnkiNoteMedia', {async: true, contentScript: true, handler: this._onApiInjectAnkiNoteMedia.bind(this)}],
['noteView', {async: true, contentScript: true, handler: this._onApiNoteView.bind(this)}], ['noteView', {async: true, contentScript: true, handler: this._onApiNoteView.bind(this)}],
['suspendAnkiCardsForNote', {async: true, contentScript: true, handler: this._onApiSuspendAnkiCardsForNote.bind(this)}],
['commandExec', {async: false, contentScript: true, handler: this._onApiCommandExec.bind(this)}], ['commandExec', {async: false, contentScript: true, handler: this._onApiCommandExec.bind(this)}],
['getDefinitionAudioInfo', {async: true, contentScript: true, handler: this._onApiGetDefinitionAudioInfo.bind(this)}], ['getDefinitionAudioInfo', {async: true, contentScript: true, handler: this._onApiGetDefinitionAudioInfo.bind(this)}],
['downloadDefinitionAudio', {async: true, contentScript: true, handler: this._onApiDownloadDefinitionAudio.bind(this)}], ['downloadDefinitionAudio', {async: true, contentScript: true, handler: this._onApiDownloadDefinitionAudio.bind(this)}],
@ -495,6 +496,16 @@ class Backend {
return await this._anki.guiBrowseNote(noteId); return await this._anki.guiBrowseNote(noteId);
} }
async _onApiSuspendAnkiCardsForNote({noteId}) {
const cardIds = await this._anki.findCardsForNote(noteId);
const count = cardIds.length;
if (count > 0) {
const okay = await this._anki.suspendCards(cardIds);
if (!okay) { return 0; }
}
return count;
}
_onApiCommandExec({command, params}) { _onApiCommandExec({command, params}) {
return this._runCommand(command, params); return this._runCommand(command, params);
} }

View File

@ -687,6 +687,8 @@ class OptionsUtil {
// Added sentenceParsing.enableTerminationCharacters. // Added sentenceParsing.enableTerminationCharacters.
// Added sentenceParsing.terminationCharacters. // Added sentenceParsing.terminationCharacters.
// Changed general.popupActionBarLocation. // Changed general.popupActionBarLocation.
// Added inputs.hotkeys.
// Added anki.suspendNewCards.
for (const profile of options.profiles) { for (const profile of options.profiles) {
profile.options.translation.textReplacements = { profile.options.translation.textReplacements = {
searchOriginal: true, searchOriginal: true,
@ -731,6 +733,7 @@ class OptionsUtil {
{action: 'copyHostSelection', key: 'KeyC', modifiers: ['ctrl'], scopes: ['popup', 'search'], enabled: true} {action: 'copyHostSelection', key: 'KeyC', modifiers: ['ctrl'], scopes: ['popup', 'search'], enabled: true}
] ]
}; };
profile.options.anki.suspendNewCards = false;
} }
return options; return options;
} }

View File

@ -1357,7 +1357,7 @@
</div> </div>
</div></div> </div></div>
<div class="settings-item advanced-only"> <div class="settings-item advanced-only">
<div class="settings-item-inner settings-item-inner-wrappable"> <div class="settings-item-inner">
<div class="settings-item-left"> <div class="settings-item-left">
<div class="settings-item-label">Check for card duplicates</div> <div class="settings-item-label">Check for card duplicates</div>
<div class="settings-item-description">When a card is detected as a duplicate, the add buttons will be disabled.</div> <div class="settings-item-description">When a card is detected as a duplicate, the add buttons will be disabled.</div>
@ -1435,6 +1435,16 @@
</div> </div>
</div> </div>
</div></div> </div></div>
<div class="settings-item advanced-only"><div class="settings-item-inner">
<div class="settings-item-left">
<div class="settings-item-label">Suspend new cards</div>
<div class="settings-item-description">New cards will be suspended when a note is added.</div>
</div>
<div class="settings-item-right">
<label class="toggle"><input type="checkbox" data-setting="anki.suspendNewCards"><span class="toggle-body"><span class="toggle-track"></span><span class="toggle-knob"></span></span></label>
</div>
</div></div>
<div class="settings-item settings-item-button" data-modal-action="show,anki-cards"><div class="settings-item-inner"> <div class="settings-item settings-item-button" data-modal-action="show,anki-cards"><div class="settings-item-inner">
<div class="settings-item-left"> <div class="settings-item-left">
<div class="settings-item-label">Configure Anki card format&hellip;</div> <div class="settings-item-label">Configure Anki card format&hellip;</div>

View File

@ -93,6 +93,10 @@ const api = (() => {
return this._invoke('noteView', {noteId}); return this._invoke('noteView', {noteId});
} }
suspendAnkiCardsForNote(noteId) {
return this._invoke('suspendAnkiCardsForNote', {noteId});
}
getDefinitionAudioInfo(source, expression, reading, details) { getDefinitionAudioInfo(source, expression, reading, details) {
return this._invoke('getDefinitionAudioInfo', {source, expression, reading, details}); return this._invoke('getDefinitionAudioInfo', {source, expression, reading, details});
} }

View File

@ -1181,10 +1181,18 @@ class Display extends EventDispatcher {
const overrideToken = this._progressIndicatorVisible.setOverride(true); const overrideToken = this._progressIndicatorVisible.setOverride(true);
try { try {
const {anki: {suspendNewCards}} = this._options;
const noteContext = this._getNoteContext(); const noteContext = this._getNoteContext();
const note = await this._createNote(definition, mode, noteContext, true); const note = await this._createNote(definition, mode, noteContext, true);
const noteId = await api.addAnkiNote(note); const noteId = await api.addAnkiNote(note);
if (noteId) { if (noteId) {
if (suspendNewCards) {
try {
await api.suspendAnkiCardsForNote(noteId);
} catch (e) {
// NOP
}
}
button.disabled = true; button.disabled = true;
this._viewerButtonShow(definitionIndex, noteId); this._viewerButtonShow(definitionIndex, noteId);
} else { } else {

View File

@ -417,7 +417,8 @@ function createProfileOptionsUpdatedTestData1() {
kanji: {deck: '', model: '', fields: {}}, kanji: {deck: '', model: '', fields: {}},
duplicateScope: 'collection', duplicateScope: 'collection',
checkForDuplicates: true, checkForDuplicates: true,
fieldTemplates: null fieldTemplates: null,
suspendNewCards: false
}, },
sentenceParsing: { sentenceParsing: {
scanExtent: 200, scanExtent: 200,