Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions proto/anki/collection.proto
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ message OpChangesOnly {
collection.OpChanges changes = 1;
}

message NestedOpChanges {
OpChangesOnly changes = 1;
}

message OpChangesWithCount {
OpChanges changes = 1;
uint32 count = 2;
Expand Down
2 changes: 2 additions & 0 deletions proto/anki/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ message ConfigKey {
LOAD_BALANCER_ENABLED = 26;
FSRS_SHORT_TERM_WITH_STEPS_ENABLED = 27;
FSRS_LEGACY_EVALUATE = 28;
NEW_REVIEWER = 29;
}
enum String {
SET_DUE_BROWSER = 0;
Expand Down Expand Up @@ -120,6 +121,7 @@ message Preferences {
uint32 time_limit_secs = 5;
bool load_balancer_enabled = 6;
bool fsrs_short_term_with_steps_enabled = 7;
bool new_reviewer = 8;
}
message Editing {
bool adding_defaults_to_current_deck = 1;
Expand Down
37 changes: 37 additions & 0 deletions proto/anki/frontend.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ package anki.frontend;
import "anki/scheduler.proto";
import "anki/generic.proto";
import "anki/search.proto";
import "anki/card_rendering.proto";

service FrontendService {
// Returns values from the reviewer
Expand All @@ -30,6 +31,10 @@ service FrontendService {

// Save colour picker's custom colour palette
rpc SaveCustomColours(generic.Empty) returns (generic.Empty);

// Plays the listed AV tags
rpc PlayAVTags(PlayAVTagsRequest) returns (generic.Empty);
rpc ReviewerAction(ReviewerActionRequest) returns (generic.Empty);
}

service BackendFrontendService {}
Expand All @@ -43,3 +48,35 @@ message SetSchedulingStatesRequest {
string key = 1;
scheduler.SchedulingStates states = 2;
}

message PlayAVTagsRequest {
repeated card_rendering.AVTag tags = 1;
}

message ReviewerActionRequest {
enum ReviewerAction {
// Menus
EditCurrent = 0;
SetDueDate = 1;
CardInfo = 2;
PreviousCardInfo = 3;
CreateCopy = 4;
// Reset
Forget = 5;
// Preset Options
Options = 6;
// "Congratulations"
Overview = 7;

// Audio
PauseAudio = 9;
SeekBackward = 10;
SeekForward = 11;
RecordVoice = 12;
ReplayRecorded = 13;
};

ReviewerAction menu = 1;
// In case the card isn't set in a next_card_data intercept function
optional int64 current_card_id = 2;
}
57 changes: 57 additions & 0 deletions proto/anki/scheduler.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ import "anki/decks.proto";
import "anki/collection.proto";
import "anki/config.proto";
import "anki/deck_config.proto";
import "anki/card_rendering.proto";

service SchedulerService {
rpc GetQueuedCards(GetQueuedCardsRequest) returns (QueuedCards);
rpc AnswerCard(CardAnswer) returns (collection.OpChanges);
rpc NextCardData(NextCardDataRequest) returns (NextCardDataResponse);
rpc SchedTimingToday(generic.Empty) returns (SchedTimingTodayResponse);
rpc StudiedToday(generic.Empty) returns (generic.String);
rpc StudiedTodayMessage(StudiedTodayMessageRequest) returns (generic.String);
Expand Down Expand Up @@ -285,6 +287,61 @@ message CardAnswer {
uint32 milliseconds_taken = 6;
}

message NextCardDataRequest {
optional CardAnswer answer = 1;
}

message NextCardDataResponse {
message TypedAnswer {
string text = 1;
string args = 2;
}

message TimerPreferences {
uint32 max_time_ms = 1;
bool stop_on_answer = 2;
}

message PartialTemplate {
repeated card_rendering.RenderedTemplateNode front = 1;
repeated card_rendering.RenderedTemplateNode back = 2;
}

message NextCardData {
QueuedCards queue = 1;
bool showDue = 2;

string front = 3;
string back = 4;
string css = 5;
string body_class = 6;
bool autoplay = 7;
bool marked = 13;
optional TypedAnswer typed_answer = 12;
optional TimerPreferences timer = 14;
// TODO: Is it worth setting up some sort of "ReviewerPreferences" endpoint
// akin to GetGraphPreferences Also should this reviewer setting be moved to
// a config bool rather than config.meta
bool accept_enter = 15;

repeated card_rendering.AVTag question_av_tags = 8;
repeated card_rendering.AVTag answer_av_tags = 9;

float autoAdvanceQuestionSeconds = 16;
float autoAdvanceAnswerSeconds = 17;
bool autoAdvanceWaitForAudio = 20;

deck_config.DeckConfig.Config.QuestionAction autoAdvanceQuestionAction = 18;
deck_config.DeckConfig.Config.AnswerAction autoAdvanceAnswerAction = 19;

optional PartialTemplate partialTemplate = 11;
}

optional NextCardData next_card = 1;
// For media pre-loading. The fields of the note after next_card.
string preload = 2;
}

message CustomStudyRequest {
message Cram {
enum CramKind {
Expand Down
1 change: 1 addition & 0 deletions pylib/anki/collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
UndoStatus = collection_pb2.UndoStatus
OpChanges = collection_pb2.OpChanges
OpChangesOnly = collection_pb2.OpChangesOnly
NestedOpChanges = collection_pb2.NestedOpChanges
OpChangesWithCount = collection_pb2.OpChangesWithCount
OpChangesWithId = collection_pb2.OpChangesWithId
OpChangesAfterUndo = collection_pb2.OpChangesAfterUndo
Expand Down
46 changes: 45 additions & 1 deletion rslib/proto/typescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use anki_proto_gen::Method;
use anyhow::Result;
use inflections::Inflect;
use itertools::Itertools;
use prost_reflect::MessageDescriptor;

pub(crate) fn write_ts_interface(services: &[BackendService]) -> Result<()> {
let root = Path::new("../../out/ts/lib/generated");
Expand Down Expand Up @@ -73,14 +74,16 @@ fn write_ts_method(
input_type,
output_type,
comments,
op_changes_type,
}: &MethodDetails,
out: &mut String,
) {
let op_changes_type = *op_changes_type as u8;
let comments = format_comments(comments);
writeln!(
out,
r#"{comments}export async function {method_name}(input: PlainMessage<{input_type}>, options?: PostProtoOptions): Promise<{output_type}> {{
return await postProto("{method_name}", new {input_type}(input), {output_type}, options);
return await postProto("{method_name}", new {input_type}(input), {output_type}, options, {op_changes_type});
}}"#
).unwrap()
}
Expand All @@ -92,11 +95,21 @@ fn format_comments(comments: &Option<String>) -> String {
.unwrap_or_default()
}

#[derive(Clone, Copy)]
#[repr(u8)]
enum OpChangesType {
None = 0,
OpChanges = 1,
OpChangesOnly = 2,
NestedOpChanges = 3,
}

struct MethodDetails {
method_name: String,
input_type: String,
output_type: String,
comments: Option<String>,
op_changes_type: OpChangesType,
}

impl MethodDetails {
Expand All @@ -105,12 +118,43 @@ impl MethodDetails {
let input_type = full_name_to_imported_reference(method.proto.input().full_name());
let output_type = full_name_to_imported_reference(method.proto.output().full_name());
let comments = method.comments.clone();
let op_changes_type =
get_op_changes_type(&method.proto.output(), &method.proto.output(), 1);
Self {
method_name: name,
input_type,
output_type,
comments,
op_changes_type,
}
}
}

fn get_op_changes_type(
root_message: &MessageDescriptor,
message: &MessageDescriptor,
level: u8,
) -> OpChangesType {
if message.full_name() == "anki.collection.OpChanges" {
match level {
0 => OpChangesType::None,
1 => OpChangesType::OpChanges,
2 => OpChangesType::OpChangesOnly,
3 => OpChangesType::NestedOpChanges,
_ => panic!(
"unhandled op changes level for message {}: {}",
root_message.full_name(),
level
),
}
} else if let Some(field) = message.get_field(1) {
if let Some(field_message) = field.kind().as_message() {
get_op_changes_type(root_message, field_message, level + 1)
} else {
OpChangesType::None
}
} else {
OpChangesType::None
}
}

Expand Down
11 changes: 9 additions & 2 deletions rslib/src/backend/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ impl From<BoolKeyProto> for BoolKey {
BoolKeyProto::LoadBalancerEnabled => BoolKey::LoadBalancerEnabled,
BoolKeyProto::FsrsShortTermWithStepsEnabled => BoolKey::FsrsShortTermWithStepsEnabled,
BoolKeyProto::FsrsLegacyEvaluate => BoolKey::FsrsLegacyEvaluate,
BoolKeyProto::NewReviewer => BoolKey::NewReviewer,
}
}
}
Expand All @@ -57,8 +58,14 @@ impl From<StringKeyProto> for StringKey {

impl crate::services::ConfigService for Collection {
fn get_config_json(&mut self, input: generic::String) -> Result<generic::Json> {
let val: Option<Value> = self.get_config_optional(input.val.as_str());
val.or_not_found(input.val)
let key = input.val.as_str();
let val: Option<Value> = self.get_config_optional(key);
let default = match key {
"reviewerStorage" => Some(serde_json::from_str("{}").unwrap()),
_ => None,
};
val.or(default)
.or_not_found(key)
.and_then(|v| serde_json::to_vec(&v).map_err(Into::into))
.map(Into::into)
}
Expand Down
2 changes: 1 addition & 1 deletion rslib/src/card_rendering/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ impl crate::services::CardRenderingService for Collection {
}
}

fn rendered_nodes_to_proto(
pub(crate) fn rendered_nodes_to_proto(
nodes: Vec<RenderedNode>,
) -> Vec<anki_proto::card_rendering::RenderedTemplateNode> {
nodes
Expand Down
1 change: 1 addition & 0 deletions rslib/src/config/bool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub enum BoolKey {
FsrsLegacyEvaluate,
LoadBalancerEnabled,
FsrsShortTermWithStepsEnabled,
NewReviewer,
#[strum(to_string = "normalize_note_text")]
NormalizeNoteText,
#[strum(to_string = "dayLearnFirst")]
Expand Down
2 changes: 2 additions & 0 deletions rslib/src/preferences.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ impl Collection {
load_balancer_enabled: self.get_config_bool(BoolKey::LoadBalancerEnabled),
fsrs_short_term_with_steps_enabled: self
.get_config_bool(BoolKey::FsrsShortTermWithStepsEnabled),
new_reviewer: self.get_config_bool(BoolKey::NewReviewer),
})
}

Expand All @@ -125,6 +126,7 @@ impl Collection {
BoolKey::FsrsShortTermWithStepsEnabled,
s.fsrs_short_term_with_steps_enabled,
)?;
self.set_config_bool_inner(BoolKey::NewReviewer, settings.new_reviewer)?;
Ok(())
}

Expand Down
Loading