mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 14:32:22 -04:00
Complete noteCanBeAdded()
This commit is contained in:
parent
0c98a68528
commit
9a054d6924
3 changed files with 159 additions and 22 deletions
|
@ -12,6 +12,7 @@ import "anki/generic.proto";
|
|||
import "anki/search.proto";
|
||||
import "anki/notes.proto";
|
||||
import "anki/notetypes.proto";
|
||||
import "anki/links.proto";
|
||||
|
||||
service FrontendService {
|
||||
// Returns values from the reviewer
|
||||
|
@ -44,6 +45,8 @@ service FrontendService {
|
|||
rpc CloseAddCards(generic.Bool) returns (generic.Empty);
|
||||
rpc CloseEditCurrent(generic.Empty) returns (generic.Empty);
|
||||
rpc OpenLink(generic.String) returns (generic.Empty);
|
||||
rpc AskUser(AskUserRequest) returns (generic.Bool);
|
||||
rpc ShowMessageBox(ShowMessageBoxRequest) returns (generic.Empty);
|
||||
|
||||
// Profile config
|
||||
rpc GetProfileConfigJson(generic.String) returns (generic.Json);
|
||||
|
@ -106,4 +109,32 @@ message ReadClipboardResponse {
|
|||
|
||||
message WriteClipboardRequest {
|
||||
map<string, bytes> data = 1;
|
||||
}
|
||||
}
|
||||
|
||||
message Help {
|
||||
oneof value {
|
||||
links.HelpPageLinkRequest.HelpPage help_page = 1;
|
||||
string help_link = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message AskUserRequest {
|
||||
string text = 1;
|
||||
optional Help help = 2;
|
||||
optional string title = 4;
|
||||
optional bool default_no = 5;
|
||||
}
|
||||
|
||||
enum MessageBoxType {
|
||||
INFO = 0;
|
||||
WARNING = 1;
|
||||
CRITICAL = 2;
|
||||
}
|
||||
|
||||
message ShowMessageBoxRequest {
|
||||
string text = 1;
|
||||
MessageBoxType type = 2;
|
||||
optional Help help = 3;
|
||||
optional string title = 4;
|
||||
optional string text_format = 5;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ from collections.abc import Callable
|
|||
from dataclasses import dataclass
|
||||
from errno import EPROTOTYPE
|
||||
from http import HTTPStatus
|
||||
from typing import Any, cast
|
||||
from typing import Any, Generic, cast
|
||||
|
||||
import flask
|
||||
import flask_cors
|
||||
|
@ -40,7 +40,14 @@ from aqt.operations import on_op_finished
|
|||
from aqt.operations.deck import update_deck_configs as update_deck_configs_op
|
||||
from aqt.progress import ProgressUpdate
|
||||
from aqt.qt import *
|
||||
from aqt.utils import aqt_data_path, openLink, show_warning, tr
|
||||
from aqt.utils import (
|
||||
aqt_data_path,
|
||||
askUser,
|
||||
openLink,
|
||||
show_info,
|
||||
show_warning,
|
||||
tr,
|
||||
)
|
||||
|
||||
# https://forums.ankiweb.net/t/anki-crash-when-using-a-specific-deck/22266
|
||||
waitress.wasyncore._DISCONNECTED = waitress.wasyncore._DISCONNECTED.union({EPROTOTYPE}) # type: ignore
|
||||
|
@ -704,18 +711,34 @@ def retrieve_url() -> bytes:
|
|||
).SerializeToString()
|
||||
|
||||
|
||||
AsyncRequestReturnType = TypeVar("AsyncRequestReturnType")
|
||||
|
||||
|
||||
class AsyncRequestHandler(Generic[AsyncRequestReturnType]):
|
||||
def __init__(self, callback: Callable[[AsyncRequestHandler], None]) -> None:
|
||||
self.callback = callback
|
||||
self.loop = asyncio.get_event_loop()
|
||||
self.future = self.loop.create_future()
|
||||
|
||||
def run(self) -> None:
|
||||
aqt.mw.taskman.run_on_main(lambda: self.callback(self))
|
||||
|
||||
def set_result(self, result: AsyncRequestReturnType) -> None:
|
||||
self.loop.call_soon_threadsafe(self.future.set_result, result)
|
||||
|
||||
async def get_result(self) -> AsyncRequestReturnType:
|
||||
return await self.future
|
||||
|
||||
|
||||
async def open_file_picker() -> bytes:
|
||||
req = frontend_pb2.openFilePickerRequest()
|
||||
req.ParseFromString(request.data)
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
future = loop.create_future()
|
||||
|
||||
def on_main() -> None:
|
||||
def callback(request_handler: AsyncRequestHandler) -> None:
|
||||
from aqt.utils import getFile
|
||||
|
||||
def cb(filename: str | None) -> None:
|
||||
loop.call_soon_threadsafe(future.set_result, filename)
|
||||
request_handler.set_result(filename)
|
||||
|
||||
window = aqt.mw.app.activeWindow()
|
||||
assert window is not None
|
||||
|
@ -727,9 +750,9 @@ async def open_file_picker() -> bytes:
|
|||
key=req.key,
|
||||
)
|
||||
|
||||
aqt.mw.taskman.run_on_main(on_main)
|
||||
|
||||
filename = await future
|
||||
request_handler: AsyncRequestHandler[str | None] = AsyncRequestHandler(callback)
|
||||
request_handler.run()
|
||||
filename = await request_handler.get_result()
|
||||
|
||||
return generic_pb2.String(val=filename if filename else "").SerializeToString()
|
||||
|
||||
|
@ -757,22 +780,19 @@ def show_in_media_folder() -> bytes:
|
|||
|
||||
|
||||
async def record_audio() -> bytes:
|
||||
loop = asyncio.get_event_loop()
|
||||
future = loop.create_future()
|
||||
|
||||
def on_main() -> None:
|
||||
def callback(request_handler: AsyncRequestHandler) -> None:
|
||||
from aqt.sound import record_audio
|
||||
|
||||
def cb(path: str | None) -> None:
|
||||
loop.call_soon_threadsafe(future.set_result, path)
|
||||
request_handler.set_result(path)
|
||||
|
||||
window = aqt.mw.app.activeWindow()
|
||||
assert window is not None
|
||||
record_audio(window, aqt.mw, True, cb)
|
||||
|
||||
aqt.mw.taskman.run_on_main(on_main)
|
||||
|
||||
path = await future
|
||||
request_handler: AsyncRequestHandler[str | None] = AsyncRequestHandler(callback)
|
||||
request_handler.run()
|
||||
path = await request_handler.get_result()
|
||||
|
||||
return generic_pb2.String(val=path if path else "").SerializeToString()
|
||||
|
||||
|
@ -838,6 +858,67 @@ def open_link() -> bytes:
|
|||
return b""
|
||||
|
||||
|
||||
async def ask_user() -> bytes:
|
||||
req = frontend_pb2.AskUserRequest()
|
||||
req.ParseFromString(request.data)
|
||||
|
||||
def callback(request_handler: AsyncRequestHandler) -> None:
|
||||
kwargs: dict[str, Any] = dict(text=req.text)
|
||||
if req.HasField("help"):
|
||||
help_arg: Any
|
||||
if req.help.WhichOneof("value") == "help_page":
|
||||
help_arg = req.help.help_page
|
||||
else:
|
||||
help_arg = req.help.help_link
|
||||
kwargs["help"] = help_arg
|
||||
if req.HasField("title"):
|
||||
kwargs["title"] = req.title
|
||||
if req.HasField("default_no"):
|
||||
kwargs["defaultno"] = req.default_no
|
||||
answer = askUser(**kwargs)
|
||||
request_handler.set_result(answer)
|
||||
|
||||
request_handler: AsyncRequestHandler[bool] = AsyncRequestHandler(callback)
|
||||
request_handler.run()
|
||||
answer = await request_handler.get_result()
|
||||
|
||||
return generic_pb2.Bool(val=answer).SerializeToString()
|
||||
|
||||
|
||||
async def show_message_box() -> bytes:
|
||||
req = frontend_pb2.ShowMessageBoxRequest()
|
||||
req.ParseFromString(request.data)
|
||||
|
||||
def callback(request_handler: AsyncRequestHandler) -> None:
|
||||
kwargs: dict[str, Any] = dict(text=req.text)
|
||||
if req.type == frontend_pb2.MessageBoxType.INFO:
|
||||
icon = QMessageBox.Icon.Information
|
||||
elif req.type == frontend_pb2.MessageBoxType.WARNING:
|
||||
icon = QMessageBox.Icon.Warning
|
||||
elif req.type == frontend_pb2.MessageBoxType.CRITICAL:
|
||||
icon = QMessageBox.Icon.Critical
|
||||
kwargs["icon"] = icon
|
||||
if req.HasField("help"):
|
||||
help_arg: Any
|
||||
if req.help.WhichOneof("value") == "help_page":
|
||||
help_arg = req.help.help_page
|
||||
else:
|
||||
help_arg = req.help.help_link
|
||||
kwargs["help"] = help_arg
|
||||
if req.HasField("title"):
|
||||
kwargs["title"] = req.title
|
||||
if req.HasField("text_format"):
|
||||
kwargs["text_format"] = req.text_format
|
||||
show_info(**kwargs)
|
||||
request_handler.set_result(True)
|
||||
|
||||
request_handler: AsyncRequestHandler[bool] = AsyncRequestHandler(callback)
|
||||
request_handler.run()
|
||||
answer = await request_handler.get_result()
|
||||
|
||||
return generic_pb2.Bool(val=answer).SerializeToString()
|
||||
|
||||
|
||||
post_handler_list = [
|
||||
congrats_info,
|
||||
get_deck_configs_for_update,
|
||||
|
@ -872,6 +953,8 @@ post_handler_list = [
|
|||
close_add_cards,
|
||||
close_edit_current,
|
||||
open_link,
|
||||
ask_user,
|
||||
show_message_box,
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -518,8 +518,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
}
|
||||
}
|
||||
if (result.state === NoteFieldsCheckResponse_State.MISSING_CLOZE) {
|
||||
// TODO: askUser(tr.addingYouHaveAClozeDeletionNote())
|
||||
return false;
|
||||
const answer = (
|
||||
await askUser({
|
||||
text: tr.addingYouHaveAClozeDeletionNote(),
|
||||
})
|
||||
).val;
|
||||
if (!answer) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (result.state === NoteFieldsCheckResponse_State.NOTETYPE_NOT_CLOZE) {
|
||||
problem = tr.addingClozeOutsideClozeNotetype();
|
||||
|
@ -527,7 +533,20 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
if (result.state === NoteFieldsCheckResponse_State.FIELD_NOT_CLOZE) {
|
||||
problem = tr.addingClozeOutsideClozeField();
|
||||
}
|
||||
return problem ? false : true;
|
||||
if (problem) {
|
||||
showMessageBox({
|
||||
text: problem,
|
||||
type: MessageBoxType.WARNING,
|
||||
help: {
|
||||
value: {
|
||||
case: "helpPage",
|
||||
value: HelpPageLinkRequest_HelpPage.ADDING_CARD_AND_NOTE,
|
||||
},
|
||||
},
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async function addCurrentNoteInner(deckId: bigint) {
|
||||
|
@ -676,6 +695,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
closeAddCards as closeAddCardsBackend,
|
||||
closeEditCurrent as closeEditCurrentBackend,
|
||||
htmlToTextLine,
|
||||
askUser,
|
||||
showMessageBox,
|
||||
} from "@generated/backend";
|
||||
import { wrapInternal } from "@tslib/wrap";
|
||||
import { getProfileConfig, getMeta, setMeta, getColConfig } from "@tslib/profile";
|
||||
|
@ -701,6 +722,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
import { registerShortcut } from "@tslib/shortcuts";
|
||||
import ActionButtons from "./ActionButtons.svelte";
|
||||
import HistoryModal from "./HistoryModal.svelte";
|
||||
import { HelpPageLinkRequest_HelpPage } from "@generated/anki/links_pb";
|
||||
import { MessageBoxType } from "@generated/anki/frontend_pb";
|
||||
|
||||
$: isIOImageLoaded = false;
|
||||
$: ioImageLoadedStore.set(isIOImageLoaded);
|
||||
|
|
Loading…
Reference in a new issue