11from collections import deque
2+ from enum import Enum , auto
3+ from textual import events
24from textual .app import ComposeResult
35from textual .binding import Binding
46from textual .containers import Container
1012from memotica .sm2 import sm2
1113
1214
15+ class ReviewStatus (Enum ):
16+ LOADING = auto ()
17+ SHOW_QUESTION = auto ()
18+ SHOW_ANSWER = auto ()
19+
20+
1321class ReviewScreen (Screen ):
1422 BINDINGS = [
1523 Binding (
@@ -22,79 +30,113 @@ class ReviewScreen(Screen):
2230 Binding ("ctrl+n" , "disable_binding" , "Nothing" , show = False , priority = True ),
2331 ]
2432
25- front_content : reactive [str ] = reactive ("" , recompose = True )
26- back_content : reactive [str ] = reactive ("" , recompose = True )
33+ review_status : reactive [ReviewStatus ] = reactive (ReviewStatus .LOADING )
2734
2835 def __init__ (self , reviews : list [Review ], * args , ** kwargs ):
2936 super ().__init__ (* args , ** kwargs )
3037 self .review_queue = deque (reviews )
31- self .current_review = self .review_queue .popleft ()
32-
33- if self .current_review .reversed :
34- self .front_content = self .current_review .flashcard .back
35- self .back_content = self .current_review .flashcard .front
36- else :
37- self .front_content = self .current_review .flashcard .front
38- self .back_content = self .current_review .flashcard .back
38+ self .loading = True
3939
4040 def compose (self ) -> ComposeResult :
4141 yield Container (
4242 Markdown (
43- self .front_content ,
44- classes = "review__screen__question" ,
45- ),
46- Container (
47- Button ("Show" , variant = "primary" , id = "show" ),
48- classes = "review__screen__controls" ,
43+ "" ,
44+ classes = "review__question" ,
4945 ),
50- classes = "review__screen review__screen--question" ,
51- )
52-
53- yield Container (
5446 Markdown (
55- self . front_content ,
56- classes = "review__screen__front " ,
47+ "" ,
48+ classes = "review__answer hide " ,
5749 ),
58- Markdown (
59- self . back_content ,
60- classes = "review__screen__back " ,
50+ Container (
51+ Button ( "Show" , variant = "primary" , id = "show" ) ,
52+ classes = "review__show " ,
6153 ),
6254 Container (
63- Button ("Wrong" , variant = "error" ),
64- Button ("Good" , variant = "warning" ),
65- Button ("Easy" , variant = "success" ),
66- classes = "review__screen__controls " ,
55+ Button ("Wrong" , variant = "error" , id = "wrong" ),
56+ Button ("Good" , variant = "warning" , id = "good" ),
57+ Button ("Easy" , variant = "success" , id = "easy" ),
58+ classes = "review__assestment hide " ,
6759 ),
68- classes = "review__screen review__screen--answer hide " ,
60+ classes = "review-screen " ,
6961 )
7062
7163 yield Footer ()
7264
73- def action_disable_binding (self ) -> None :
74- return None
75-
76- def on_button_pressed (self , event : Button .Pressed ) -> None :
77- self .answer = self .query (".review__screen--answer" )
78- self .question = self .query (".review__screen--question" )
65+ def on_mount (self ) -> None :
66+ self .question = self .query (".review__question" ).only_one ()
67+ self .answer = self .query (".review__answer" ).only_one ()
68+ self .show_button = self .query (".review__show" ).only_one ()
69+ self .assestment_buttons = self .query (".review__assestment" ).only_one ()
7970
80- button_label = f" { event . button . label } "
71+ self . load_next ()
8172
82- if button_label == "Show" :
83- self .answer .remove_class ("hide" )
84- self .question .add_class ("hide" )
73+ def on_button_pressed (self , event : Button .Pressed ) -> None :
74+ button_id = event .button .id
75+ if button_id == "show" :
76+ self .review_status = ReviewStatus .SHOW_ANSWER
8577 else :
86- if button_label == "Easy " :
78+ if button_id == "easy " :
8779 self .update_review (5 )
88- elif button_label == "Good " :
80+ elif button_id == "good " :
8981 self .update_review (3 )
9082 else :
9183 self .update_review ()
9284
93- self .load_next_review ()
94- self .answer .add_class ("hide" )
95- self .question .remove_class ("hide" )
85+ self .load_next ()
86+
87+ def on_key (self , event : events .Key ) -> None :
88+ key = event .key
89+ if (
90+ key == "space" or key == "enter"
91+ ) and self .review_status == ReviewStatus .SHOW_QUESTION :
92+ self .review_status = ReviewStatus .SHOW_ANSWER
93+
94+ if key in ["1" , "2" , "3" ] and self .review_status == ReviewStatus .SHOW_ANSWER :
95+ if key == "1" :
96+ self .update_review ()
97+ elif key == "2" :
98+ self .update_review (3 )
99+ elif key == "3" :
100+ self .update_review (5 )
101+
102+ self .load_next ()
96103
97- def load_next_review (self ) -> None :
104+ def action_disable_binding (self ) -> None :
105+ return None
106+
107+ def update_review (self , q : int = 0 ) -> None :
108+ (n , ef , i ) = sm2 (
109+ self .current_question .repetitions ,
110+ self .current_question .ef ,
111+ self .current_question .interval ,
112+ q ,
113+ )
114+
115+ self .post_message (UpdateReview (self .current_question .id , n , ef , i ))
116+
117+ if q < 3 :
118+ self .current_question .repetitions = n
119+ self .current_question .ef = ef
120+ self .current_question .interval = i
121+
122+ self .review_queue .append (self .current_question )
123+
124+ def watch_review_status (self , _ : ReviewStatus , new_status : ReviewStatus ) -> None :
125+ if new_status == ReviewStatus .LOADING :
126+ self .loading = True
127+ else :
128+ self .loading = False
129+
130+ if new_status == ReviewStatus .SHOW_QUESTION :
131+ self .show_button .remove_class ("hide" )
132+ self .answer .add_class ("hide" )
133+ self .assestment_buttons .add_class ("hide" )
134+ else :
135+ self .show_button .add_class ("hide" )
136+ self .answer .remove_class ("hide" )
137+ self .assestment_buttons .remove_class ("hide" )
138+
139+ def load_next (self ) -> None :
98140 if not self .review_queue :
99141 self .notify (
100142 "There are no more cards to review. Well done!" ,
@@ -104,28 +146,14 @@ def load_next_review(self) -> None:
104146 self .app .pop_screen ()
105147 return
106148
107- self .current_review = self . review_queue . popleft ()
149+ self .review_status = ReviewStatus . LOADING
108150
109- if self .current_review .reversed :
110- self .front_content = self .current_review .flashcard .back
111- self .back_content = self .current_review .flashcard .front
151+ self .current_question = self .review_queue .popleft ()
152+ if self .current_question .reversed :
153+ self .question .update (self .current_question .flashcard .back )
154+ self .answer .update (self .current_question .flashcard .front )
112155 else :
113- self .front_content = self .current_review .flashcard .front
114- self .back_content = self .current_review .flashcard .back
115-
116- def update_review (self , q : int = 0 ) -> None :
117- (n , ef , i ) = sm2 (
118- self .current_review .repetitions ,
119- self .current_review .ef ,
120- self .current_review .interval ,
121- q ,
122- )
123-
124- self .post_message (UpdateReview (self .current_review .id , n , ef , i ))
125-
126- if q < 3 :
127- self .current_review .repetitions = n
128- self .current_review .ef = ef
129- self .current_review .interval = i
156+ self .question .update (self .current_question .flashcard .front )
157+ self .answer .update (self .current_question .flashcard .back )
130158
131- self . review_queue . append ( self . current_review )
159+ self . review_status = ReviewStatus . SHOW_QUESTION
0 commit comments