Pop-up dictionary browser extension for language learning. Successor to Yomichan. (PERSONAL FORK)

Change view notes button color based on card state (#1978)

* Make viewNoteButton background yellow if card is suspended

* fix: resolve PR concerns

* fix: address PR concerns

* fix: attempt to address concerns

* fix: address PR concern

authored by

Kolby Moroz Liebl and committed by
GitHub
67a3b2ca a3593e3f

+500 -9
+6 -1
ext/css/display.css
··· 741 741 background-color: var(--action-button-active-color); 742 742 box-shadow: none; 743 743 } 744 - .icon[data-icon=view-note] { background-image: url('/images/view-note.svg'); } 744 + 745 + .icon[data-icon=view-note] { background-image: url('/images/view-note.svg'); } 746 + .icon[data-icon=view-note-learning] { background-image: url('/images/view-note-learning.svg'); } 747 + .icon[data-icon=view-note-review] { background-image: url('/images/view-note-review.svg'); } 748 + .icon[data-icon=view-note-suspended] { background-image: url('/images/view-note-suspended.svg'); } 749 + .icon[data-icon=view-note-buried] { background-image: url('/images/view-note-buried.svg'); } 745 750 .icon[data-icon=big-circle] { background-image: url('/images/big-circle.svg'); } 746 751 .icon[data-icon=small-circle] { background-image: url('/images/small-circle.svg'); } 747 752 .icon[data-icon=big-square] { background-image: url('/images/big-square.svg'); }
+105
ext/images/view-note-buried.svg
··· 1 + <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 + <svg 3 + width="16" 4 + height="16" 5 + version="1.1" 6 + viewBox="0 0 16 16" 7 + id="svg9" 8 + sodipodi:docname="view-note-buried.svg" 9 + inkscape:version="1.4 (e7c3feb100, 2024-10-09)" 10 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 11 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 12 + xmlns="http://www.w3.org/2000/svg" 13 + xmlns:svg="http://www.w3.org/2000/svg"> 14 + <sodipodi:namedview 15 + id="namedview9" 16 + pagecolor="#ffffff" 17 + bordercolor="#000000" 18 + borderopacity="0.25" 19 + inkscape:showpageshadow="2" 20 + inkscape:pageopacity="0.0" 21 + inkscape:pagecheckerboard="0" 22 + inkscape:deskcolor="#d1d1d1" 23 + inkscape:zoom="49" 24 + inkscape:cx="7.9897959" 25 + inkscape:cy="8" 26 + inkscape:window-width="1920" 27 + inkscape:window-height="1007" 28 + inkscape:window-x="0" 29 + inkscape:window-y="0" 30 + inkscape:window-maximized="1" 31 + inkscape:current-layer="g9" /> 32 + <defs 33 + id="defs4"> 34 + <linearGradient 35 + id="linearGradient5010" 36 + x2="-3.9688" 37 + y1="3.7042" 38 + y2="1.0583" 39 + gradientTransform="matrix(3.7795 0 0 3.7795 15.5 -.5)" 40 + gradientUnits="userSpaceOnUse"> 41 + <stop 42 + stop-color="#012e5b" 43 + offset="0" 44 + id="stop1" 45 + style="stop-color:#5b3f01;stop-opacity:1;" /> 46 + <stop 47 + stop-color="#6399c6" 48 + offset="1" 49 + id="stop2" 50 + style="stop-color:#c6a263;stop-opacity:1;" /> 51 + </linearGradient> 52 + <linearGradient 53 + id="linearGradient5018-3" 54 + x1="3.8365" 55 + x2=".39687" 56 + y1="3.0427" 57 + y2=".59531" 58 + gradientTransform="scale(3.7795 3.7795)" 59 + gradientUnits="userSpaceOnUse"> 60 + <stop 61 + stop-color="#012e5b" 62 + offset="0" 63 + id="stop3" 64 + style="stop-color:#5b3f01;stop-opacity:1;" /> 65 + <stop 66 + stop-color="#6399c6" 67 + offset="1" 68 + id="stop4" 69 + style="stop-color:#c6a263;stop-opacity:1;" /> 70 + </linearGradient> 71 + </defs> 72 + <g 73 + stroke-width="1px" 74 + id="g9"> 75 + <path 76 + d="m 9.75,13.5 -1,1 h -1.5 l -1,-1 H 0.5 v -10 h 6 l 1,1 h 1 l 1,-1 h 6 v 10 h -1.479592 z" 77 + fill="#5d8bb3" 78 + stroke="url(#linearGradient5010)" 79 + id="path4" 80 + sodipodi:nodetypes="cccccccccccccc" 81 + style="fill:#b3955d;fill-opacity:1" /> 82 + <path 83 + d="m 14.5,11.5 h -5 l -1,1 h -1 l -1,-1 h -5 V 2.25 h 5 l 1,1 h 1 l 1,-1 h 5 v 9.25" 84 + fill="#f8f8f8" 85 + stroke="url(#linearGradient5018-3)" 86 + id="path5" 87 + sodipodi:nodetypes="ccccccccccccc" /> 88 + <g 89 + fill="none" 90 + id="g8"> 91 + <path 92 + d="m10 8.75h3m-3-2h3m-3-2h3m-10 4h3m-3-2h3m-3-2h3" 93 + stroke="#bdbdbd" 94 + id="path6" /> 95 + <path 96 + d="m7.5 10.25v-4.75" 97 + stroke="#a6a6a6" 98 + id="path7" /> 99 + <path 100 + d="m8.5 5.75v4.25" 101 + stroke="#d8d8d8" 102 + id="path8" /> 103 + </g> 104 + </g> 105 + </svg>
+105
ext/images/view-note-learning.svg
··· 1 + <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 + <svg 3 + width="16" 4 + height="16" 5 + version="1.1" 6 + viewBox="0 0 16 16" 7 + id="svg9" 8 + sodipodi:docname="view-note-learning.svg" 9 + inkscape:version="1.4 (e7c3feb100, 2024-10-09)" 10 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 11 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 12 + xmlns="http://www.w3.org/2000/svg" 13 + xmlns:svg="http://www.w3.org/2000/svg"> 14 + <sodipodi:namedview 15 + id="namedview9" 16 + pagecolor="#ffffff" 17 + bordercolor="#000000" 18 + borderopacity="0.25" 19 + inkscape:showpageshadow="2" 20 + inkscape:pageopacity="0.0" 21 + inkscape:pagecheckerboard="0" 22 + inkscape:deskcolor="#d1d1d1" 23 + inkscape:zoom="49" 24 + inkscape:cx="7.9897959" 25 + inkscape:cy="8" 26 + inkscape:window-width="1920" 27 + inkscape:window-height="1007" 28 + inkscape:window-x="0" 29 + inkscape:window-y="0" 30 + inkscape:window-maximized="1" 31 + inkscape:current-layer="g9" /> 32 + <defs 33 + id="defs4"> 34 + <linearGradient 35 + id="linearGradient5010" 36 + x2="-3.9688" 37 + y1="3.7042" 38 + y2="1.0583" 39 + gradientTransform="matrix(3.7795 0 0 3.7795 15.5 -.5)" 40 + gradientUnits="userSpaceOnUse"> 41 + <stop 42 + stop-color="#012e5b" 43 + offset="0" 44 + id="stop1" 45 + style="stop-color:#5b0101;stop-opacity:1;" /> 46 + <stop 47 + stop-color="#6399c6" 48 + offset="1" 49 + id="stop2" 50 + style="stop-color:#c66368;stop-opacity:1;" /> 51 + </linearGradient> 52 + <linearGradient 53 + id="linearGradient5018-3" 54 + x1="3.8365" 55 + x2=".39687" 56 + y1="3.0427" 57 + y2=".59531" 58 + gradientTransform="scale(3.7795 3.7795)" 59 + gradientUnits="userSpaceOnUse"> 60 + <stop 61 + stop-color="#012e5b" 62 + offset="0" 63 + id="stop3" 64 + style="stop-color:#5b0101;stop-opacity:1;" /> 65 + <stop 66 + stop-color="#6399c6" 67 + offset="1" 68 + id="stop4" 69 + style="stop-color:#c66368;stop-opacity:1;" /> 70 + </linearGradient> 71 + </defs> 72 + <g 73 + stroke-width="1px" 74 + id="g9"> 75 + <path 76 + d="m 9.75,13.5 -1,1 h -1.5 l -1,-1 H 0.5 v -10 h 6 l 1,1 h 1 l 1,-1 h 6 v 10 z" 77 + fill="#5d8bb3" 78 + stroke="url(#linearGradient5010)" 79 + id="path4" 80 + sodipodi:nodetypes="ccccccccccccc" 81 + style="fill:#b35d60;fill-opacity:1" /> 82 + <path 83 + d="m 14.5,11.5 h -5 l -1,1 h -1 l -1,-1 h -5 V 2.25 h 5 l 1,1 h 1 l 1,-1 h 5 v 9.25" 84 + fill="#f8f8f8" 85 + stroke="url(#linearGradient5018-3)" 86 + id="path5" 87 + sodipodi:nodetypes="ccccccccccccc" /> 88 + <g 89 + fill="none" 90 + id="g8"> 91 + <path 92 + d="m10 8.75h3m-3-2h3m-3-2h3m-10 4h3m-3-2h3m-3-2h3" 93 + stroke="#bdbdbd" 94 + id="path6" /> 95 + <path 96 + d="m7.5 10.25v-4.75" 97 + stroke="#a6a6a6" 98 + id="path7" /> 99 + <path 100 + d="m8.5 5.75v4.25" 101 + stroke="#d8d8d8" 102 + id="path8" /> 103 + </g> 104 + </g> 105 + </svg>
+105
ext/images/view-note-review.svg
··· 1 + <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 + <svg 3 + width="16" 4 + height="16" 5 + version="1.1" 6 + viewBox="0 0 16 16" 7 + id="svg9" 8 + sodipodi:docname="view-note-review.svg" 9 + inkscape:version="1.4 (e7c3feb100, 2024-10-09)" 10 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 11 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 12 + xmlns="http://www.w3.org/2000/svg" 13 + xmlns:svg="http://www.w3.org/2000/svg"> 14 + <sodipodi:namedview 15 + id="namedview9" 16 + pagecolor="#ffffff" 17 + bordercolor="#000000" 18 + borderopacity="0.25" 19 + inkscape:showpageshadow="2" 20 + inkscape:pageopacity="0.0" 21 + inkscape:pagecheckerboard="0" 22 + inkscape:deskcolor="#d1d1d1" 23 + inkscape:zoom="49" 24 + inkscape:cx="7.9897959" 25 + inkscape:cy="8" 26 + inkscape:window-width="1920" 27 + inkscape:window-height="1007" 28 + inkscape:window-x="0" 29 + inkscape:window-y="0" 30 + inkscape:window-maximized="1" 31 + inkscape:current-layer="g9" /> 32 + <defs 33 + id="defs4"> 34 + <linearGradient 35 + id="linearGradient5010" 36 + x2="-3.9688" 37 + y1="3.7042" 38 + y2="1.0583" 39 + gradientTransform="matrix(3.7795 0 0 3.7795 15.5 -.5)" 40 + gradientUnits="userSpaceOnUse"> 41 + <stop 42 + stop-color="#012e5b" 43 + offset="0" 44 + id="stop1" 45 + style="stop-color:#015b12;stop-opacity:1;" /> 46 + <stop 47 + stop-color="#6399c6" 48 + offset="1" 49 + id="stop2" 50 + style="stop-color:#63c670;stop-opacity:1;" /> 51 + </linearGradient> 52 + <linearGradient 53 + id="linearGradient5018-3" 54 + x1="3.8365" 55 + x2=".39687" 56 + y1="3.0427" 57 + y2=".59531" 58 + gradientTransform="scale(3.7795 3.7795)" 59 + gradientUnits="userSpaceOnUse"> 60 + <stop 61 + stop-color="#012e5b" 62 + offset="0" 63 + id="stop3" 64 + style="stop-color:#015b12;stop-opacity:1;" /> 65 + <stop 66 + stop-color="#6399c6" 67 + offset="1" 68 + id="stop4" 69 + style="stop-color:#63c670;stop-opacity:1;" /> 70 + </linearGradient> 71 + </defs> 72 + <g 73 + stroke-width="1px" 74 + id="g9"> 75 + <path 76 + d="m 9.75,13.5 -1,1 h -1.5 l -1,-1 H 0.5 v -10 h 6 l 1,1 h 1 l 1,-1 h 6 v 10 z" 77 + fill="#5d8bb3" 78 + stroke="url(#linearGradient5010)" 79 + id="path4" 80 + sodipodi:nodetypes="ccccccccccccc" 81 + style="fill:#5db36a;fill-opacity:1" /> 82 + <path 83 + d="m 14.5,11.5 h -5 l -1,1 h -1 l -1,-1 h -5 V 2.25 h 5 l 1,1 h 1 l 1,-1 h 5 v 9.25" 84 + fill="#f8f8f8" 85 + stroke="url(#linearGradient5018-3)" 86 + id="path5" 87 + sodipodi:nodetypes="ccccccccccccc" /> 88 + <g 89 + fill="none" 90 + id="g8"> 91 + <path 92 + d="m10 8.75h3m-3-2h3m-3-2h3m-10 4h3m-3-2h3m-3-2h3" 93 + stroke="#bdbdbd" 94 + id="path6" /> 95 + <path 96 + d="m7.5 10.25v-4.75" 97 + stroke="#a6a6a6" 98 + id="path7" /> 99 + <path 100 + d="m8.5 5.75v4.25" 101 + stroke="#d8d8d8" 102 + id="path8" /> 103 + </g> 104 + </g> 105 + </svg>
+104
ext/images/view-note-suspended.svg
··· 1 + <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 + <svg 3 + width="16" 4 + height="16" 5 + version="1.1" 6 + viewBox="0 0 16 16" 7 + id="svg9" 8 + sodipodi:docname="view-note-suspended.svg" 9 + inkscape:version="1.4 (e7c3feb100, 2024-10-09)" 10 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 11 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 12 + xmlns="http://www.w3.org/2000/svg" 13 + xmlns:svg="http://www.w3.org/2000/svg"> 14 + <sodipodi:namedview 15 + id="namedview9" 16 + pagecolor="#ffffff" 17 + bordercolor="#000000" 18 + borderopacity="0.25" 19 + inkscape:showpageshadow="2" 20 + inkscape:pageopacity="0.0" 21 + inkscape:pagecheckerboard="0" 22 + inkscape:deskcolor="#d1d1d1" 23 + showgrid="false" 24 + inkscape:zoom="49" 25 + inkscape:cx="7.9897959" 26 + inkscape:cy="8" 27 + inkscape:window-width="1920" 28 + inkscape:window-height="1007" 29 + inkscape:window-x="0" 30 + inkscape:window-y="0" 31 + inkscape:window-maximized="1" 32 + inkscape:current-layer="g9" /> 33 + <defs 34 + id="defs4"> 35 + <linearGradient 36 + id="linearGradient5010" 37 + x2="-3.9688" 38 + y1="3.7042" 39 + y2="1.0583" 40 + gradientTransform="matrix(3.7795 0 0 3.7795 15.5 -.5)" 41 + gradientUnits="userSpaceOnUse"> 42 + <stop 43 + stop-color="#012e5b" 44 + offset="0" 45 + id="stop1" 46 + style="stop-color:#545b01;stop-opacity:1;" /> 47 + <stop 48 + stop-color="#6399c6" 49 + offset="1" 50 + id="stop2" 51 + style="stop-color:#c3c663;stop-opacity:1;" /> 52 + </linearGradient> 53 + <linearGradient 54 + id="linearGradient5018-3" 55 + x1="3.8365" 56 + x2=".39687" 57 + y1="3.0427" 58 + y2=".59531" 59 + gradientTransform="scale(3.7795 3.7795)" 60 + gradientUnits="userSpaceOnUse"> 61 + <stop 62 + stop-color="#012e5b" 63 + offset="0" 64 + id="stop3" 65 + style="stop-color:#545b01;stop-opacity:1;" /> 66 + <stop 67 + stop-color="#6399c6" 68 + offset="1" 69 + id="stop4" 70 + style="stop-color:#c1c663;stop-opacity:1;" /> 71 + </linearGradient> 72 + </defs> 73 + <g 74 + stroke-width="1px" 75 + id="g9"> 76 + <path 77 + d="m9.75 13.5-1 1h-1.5l-1-1h-5.75v-10h6l1 1h1l1-1h6v10z" 78 + fill="#5d8bb3" 79 + stroke="url(#linearGradient5010)" 80 + id="path4" 81 + style="fill:#adb35d;fill-opacity:1" /> 82 + <path 83 + d="m14.5 11.5h-5l-1 1h-1l-1-1h-5v-9.25h5l1 1h1l1-1h5v9.25" 84 + fill="#f8f8f8" 85 + stroke="url(#linearGradient5018-3)" 86 + id="path5" /> 87 + <g 88 + fill="none" 89 + id="g8"> 90 + <path 91 + d="m10 8.75h3m-3-2h3m-3-2h3m-10 4h3m-3-2h3m-3-2h3" 92 + stroke="#bdbdbd" 93 + id="path6" /> 94 + <path 95 + d="m7.5 10.25v-4.75" 96 + stroke="#a6a6a6" 97 + id="path7" /> 98 + <path 99 + d="m8.5 5.75v4.25" 100 + stroke="#d8d8d8" 101 + id="path8" /> 102 + </g> 103 + </g> 104 + </svg>
+2 -1
ext/js/comm/anki-connect.js
··· 697 697 result2.push(null); 698 698 continue; 699 699 } 700 - const {note, flags} = /** @type {{[key: string]: unknown}} */ (item); 700 + const {note, flags, queue} = /** @type {{[key: string]: unknown}} */ (item); 701 701 if (typeof note !== 'number') { 702 702 result2.push(null); 703 703 continue; ··· 708 708 noteId: note, 709 709 cardId, 710 710 flags: typeof flags === 'number' ? flags : 0, 711 + cardState: typeof queue === 'number' ? queue : 0, 711 712 }; 712 713 result2.push(item2); 713 714 }
+72 -7
ext/js/display/display-anki.js
··· 468 468 469 469 const validNoteIds = noteIds?.filter((id) => id !== INVALID_NOTE_ID) ?? []; 470 470 471 - this._createViewNoteButton(entryIndex, cardFormatIndex, validNoteIds); 471 + this._createViewNoteButton(entryIndex, cardFormatIndex, validNoteIds, Array.isArray(noteInfos) ? noteInfos : []); 472 472 473 473 if (displayTagsAndFlags !== 'never' && Array.isArray(noteInfos)) { 474 474 this._setupTagsIndicator(entryIndex, cardFormatIndex, noteInfos); ··· 791 791 /** @type {HTMLButtonElement | null} */ 792 792 let viewNoteButton = singleNoteActions.querySelector('.action-button[data-action=view-note]'); 793 793 if (viewNoteButton === null) { 794 - viewNoteButton = this._createViewNoteButton(dictionaryEntryIndex, cardFormatIndex, noteIds); 794 + viewNoteButton = this._createViewNoteButton(dictionaryEntryIndex, cardFormatIndex, noteIds, []); 795 795 } 796 796 if (viewNoteButton === null) { return; } 797 797 const newNoteIds = new Set([...this._getNodeNoteIds(viewNoteButton), ...noteIds]); ··· 914 914 } 915 915 916 916 /** 917 + * Checks whether fetching additional information (e.g. tags and flags, or overwrite) is enabled 918 + * based on the current instance's display settings and duplicate handling behavior. 919 + * @returns {boolean} - True if additional info fetching is enabled, false otherwise. 920 + */ 921 + _isAdditionalInfoEnabled() { 922 + return this._displayTagsAndFlags !== 'never' || this._duplicateBehavior === 'overwrite'; 923 + } 924 + 925 + /** 917 926 * @param {import('dictionary').DictionaryEntry[]} dictionaryEntries 918 927 * @returns {Promise<import('display-anki').DictionaryEntryDetails[]>} 919 928 */ 920 929 async _getDictionaryEntryDetails(dictionaryEntries) { 921 - const fetchAdditionalInfo = (this._displayTagsAndFlags !== 'never') || this._duplicateBehavior === 'overwrite'; 922 - 923 930 const notePromises = []; 924 931 const noteTargets = []; 925 932 for (let i = 0, ii = dictionaryEntries.length; i < ii; ++i) { ··· 944 951 } 945 952 946 953 infos = this._checkForDuplicates ? 947 - await this._display.application.api.getAnkiNoteInfo(notes, fetchAdditionalInfo) : 954 + await this._display.application.api.getAnkiNoteInfo(notes, this._isAdditionalInfoEnabled()) : 948 955 this._getAnkiNoteInfoForceValue(notes, true); 949 956 } catch (e) { 950 957 infos = this._getAnkiNoteInfoForceValue(notes, false); ··· 1110 1117 * @param {number} index 1111 1118 * @param {number} cardFormatIndex 1112 1119 * @param {number[]} noteIds 1120 + * @param {(?import('anki').NoteInfo)[]} noteInfos 1113 1121 * @returns {?HTMLButtonElement} 1114 1122 */ 1115 - _createViewNoteButton(index, cardFormatIndex, noteIds) { 1123 + _createViewNoteButton(index, cardFormatIndex, noteIds, noteInfos) { 1116 1124 if (noteIds.length === 0) { return null; } 1117 - const viewNoteButton = /** @type {HTMLButtonElement} */ (this._display.displayGenerator.instantiateTemplate('note-action-button-view-note')); 1125 + let viewNoteButton = /** @type {HTMLButtonElement} */ (this._display.displayGenerator.instantiateTemplate('note-action-button-view-note')); 1118 1126 if (viewNoteButton === null) { return null; } 1119 1127 const disabled = (noteIds.length === 0); 1120 1128 viewNoteButton.disabled = disabled; 1121 1129 viewNoteButton.hidden = disabled; 1122 1130 viewNoteButton.dataset.noteIds = noteIds.join(' '); 1131 + 1132 + viewNoteButton = this._setViewNoteButtonCardState(noteInfos, viewNoteButton); 1123 1133 1124 1134 this._setViewButtonBadge(viewNoteButton); 1125 1135 ··· 1140 1150 } 1141 1151 1142 1152 /** 1153 + * @param {(?import('anki').NoteInfo)[]} noteInfos 1154 + * @param {HTMLButtonElement} viewNoteButton 1155 + * @returns {HTMLButtonElement} 1156 + */ 1157 + _setViewNoteButtonCardState(noteInfos, viewNoteButton) { 1158 + if (this._isAdditionalInfoEnabled() === false || noteInfos.length === 0) { return viewNoteButton; } 1159 + 1160 + const cardStates = []; 1161 + for (const item of noteInfos) { 1162 + if (item === null) { continue; } 1163 + for (const cardInfo of item.cardsInfo) { 1164 + cardStates.push(cardInfo.cardState); 1165 + } 1166 + } 1167 + 1168 + const highestState = this._getHighestPriorityCardState(cardStates); 1169 + const dataIcon = /** @type {HTMLElement} */ (viewNoteButton.querySelector('.icon[data-icon^="view-note"]')); 1170 + dataIcon.dataset.icon = highestState !== 'new' ? `view-note-${highestState}` : 'view-note'; 1171 + 1172 + const label = `View added note (${highestState})`; 1173 + viewNoteButton.title = label; 1174 + viewNoteButton.dataset.hotkey = JSON.stringify(['viewNotes', 'title', `${label} ({0})`]); 1175 + return viewNoteButton; 1176 + } 1177 + 1178 + /** 1143 1179 * @param {HTMLButtonElement} viewNoteButton 1144 1180 */ 1145 1181 _setViewButtonBadge(viewNoteButton) { ··· 1302 1338 } 1303 1339 1304 1340 return 'linear-gradient(to right,' + gradientSlices.join(',') + ')'; 1341 + } 1342 + 1343 + /** 1344 + * Get the highest priority state from a list of Anki queue states. 1345 + * Source: https://github.com/ankidroid/Anki-Android/wiki/Database-Structure#cards 1346 + * 1347 + * Priority order: 1348 + * - -3, -2 → "buried" 1349 + * - -1 → "suspended" 1350 + * - 2 → "review" 1351 + * - 1, 3 → "learning" 1352 + * - 0 → "new" (default fallback) 1353 + * @param {number[]} cardStates Array of queue state integers. 1354 + * @returns {"buried" | "suspended" | "review" | "learning" | "new" } - The highest priority state found. 1355 + */ 1356 + _getHighestPriorityCardState(cardStates) { 1357 + if (cardStates.includes(-3) || cardStates.includes(-2)) { 1358 + return 'buried'; 1359 + } 1360 + if (cardStates.includes(-1)) { 1361 + return 'suspended'; 1362 + } 1363 + if (cardStates.includes(2)) { 1364 + return 'review'; 1365 + } 1366 + if (cardStates.includes(1) || cardStates.includes(3)) { 1367 + return 'learning'; 1368 + } 1369 + return 'new'; 1305 1370 } 1306 1371 } 1307 1372
+1
types/ext/anki.d.ts
··· 69 69 noteId: NoteId; 70 70 cardId: CardId; 71 71 flags: number; 72 + cardState: number; 72 73 }; 73 74 74 75 export type ApiReflectResult = {