11use crate :: * ;
22use arrayvec:: ArrayString ;
33use core:: fmt:: { Arguments , Error , Write } ;
4+ use core:: str:: from_utf8;
45
56use nanos_sdk:: buttons:: * ;
67use nanos_ui:: bagls:: * ;
8+ use nanos_ui:: layout:: * ;
9+ use nanos_ui:: ui:: clear_screen;
710
811#[ derive( Clone , Debug ) ]
912pub struct PromptQueue {
1013 io : HostIO ,
1114 prev : SHA256Sum ,
1215}
1316
17+ const HASH_LENGTH : usize = 32 ;
18+
19+ const PROMPT_TITLE_LENGTH : usize = 17 ;
20+
1421#[ cfg( target_os = "nanos" ) ]
1522const PROMPT_CHUNK_LENGTH : usize = 16 ;
1623
1724#[ cfg( not( target_os = "nanos" ) ) ]
18- const PROMPT_CHUNK_LENGTH : usize = 64 ;
25+ const PROMPT_CHUNK_LENGTH : usize = 48 ;
1926
20- type PromptBuffer = ArrayVec < u8 , { 32 + 19 + PROMPT_CHUNK_LENGTH } > ;
27+ // The two bytes are to store the actual "length" of title and chunk, respectively
28+ type PromptBuffer = ArrayVec < u8 , { HASH_LENGTH + 2 + PROMPT_TITLE_LENGTH + PROMPT_CHUNK_LENGTH } > ;
2129
2230#[ derive( Debug , PartialEq ) ]
2331pub struct PromptingError ;
@@ -45,22 +53,32 @@ impl From<ChunkNotFound> for PromptingError {
4553
4654impl PromptQueue {
4755 pub fn new ( io : HostIO ) -> PromptQueue {
48- PromptQueue { io, prev : [ 0 ; 32 ] }
56+ PromptQueue {
57+ io,
58+ prev : [ 0 ; HASH_LENGTH ] ,
59+ }
4960 }
5061
5162 async fn pop (
5263 & mut self ,
53- ) -> Result < Option < ( ArrayString < 16 > , ArrayString < PROMPT_CHUNK_LENGTH > ) > , PromptingError > {
54- if self . prev == [ 0 ; 32 ] {
64+ ) -> Result <
65+ Option < (
66+ ArrayString < PROMPT_TITLE_LENGTH > ,
67+ ArrayString < PROMPT_CHUNK_LENGTH > ,
68+ ) > ,
69+ PromptingError ,
70+ > {
71+ if self . prev == [ 0 ; HASH_LENGTH ] {
5572 return Ok ( None ) ;
5673 }
5774 let chunk = PromptBuffer :: try_from ( self . io . get_chunk ( self . prev ) . await ?. as_ref ( ) ) ?;
58- self . prev [ 0 ..32 ] . copy_from_slice ( & chunk[ 0 ..32 ] ) ;
59- let title =
60- ArrayString :: try_from ( core:: str:: from_utf8 ( & chunk[ 34 ..34 + chunk[ 32 ] as usize ] ) ?) ?;
61- let body = ArrayString :: try_from ( core:: str:: from_utf8 (
62- & chunk[ 34 + chunk[ 32 ] as usize ..( 34 + chunk[ 32 ] + chunk[ 33 ] ) as usize ] ,
63- ) ?) ?;
75+ self . prev [ 0 ..HASH_LENGTH ] . copy_from_slice ( & chunk[ 0 ..HASH_LENGTH ] ) ;
76+ let title_len = chunk[ 32 ] as usize ;
77+ let title_end = 34 + title_len;
78+ let body_len = chunk[ 33 ] as usize ;
79+ let body_end = title_end + body_len;
80+ let title = ArrayString :: try_from ( core:: str:: from_utf8 ( & chunk[ 34 ..title_end] ) ?) ?;
81+ let body = ArrayString :: try_from ( core:: str:: from_utf8 ( & chunk[ title_end..body_end] ) ?) ?;
6482 Ok ( Some ( ( title, body) ) )
6583 }
6684
@@ -82,7 +100,7 @@ impl PromptQueue {
82100 }
83101
84102 pub async fn show ( & mut self ) -> Result < bool , PromptingError > {
85- if self . prev == [ 0 ; 32 ] {
103+ if self . prev == [ 0 ; HASH_LENGTH ] {
86104 return Err ( PromptingError ) ;
87105 } // No showing empty PromptQueues.
88106
@@ -100,47 +118,44 @@ impl PromptQueue {
100118 let mut buttons = Default :: default ( ) ;
101119
102120 loop {
121+ clear_screen ( ) ;
103122 // Display
104123 let ( current_title, current_body) = title_and_body;
105124 match state {
106125 PromptingState :: Prompts => {
107- Bagl :: LABELLINE ( LabelLine :: new ( ) . pos ( 0 , 10 ) . text ( current_title. as_str ( ) ) )
108- . display ( ) ;
126+ current_title. as_str ( ) . place ( Location :: Top , Layout :: Centered , false ) ;
109127 #[ cfg( target_os = "nanos" ) ]
110128 {
111- Bagl :: LABELLINE ( LabelLine :: new ( ) . pos ( 0 , 25 ) . text ( current_body. as_str ( ) ) )
112- . paint ( ) ;
129+ current_body. as_str ( ) . place ( Location :: Custom ( 15 ) , Layout :: Centered , false ) ;
113130 }
114131 #[ cfg( not( target_os = "nanos" ) ) ]
115132 {
116- current_body. as_str ( ) . get ( 0 ..16 ) . map ( |body| {
117- Bagl :: LABELLINE ( LabelLine :: new ( ) . pos ( 0 , 25 ) . text ( body) ) . paint ( )
118- } ) ;
119- current_body. as_str ( ) . get ( 16 ..32 ) . map ( |body| {
120- Bagl :: LABELLINE ( LabelLine :: new ( ) . pos ( 0 , 37 ) . text ( body) ) . paint ( )
121- } ) ;
122- current_body. as_str ( ) . get ( 32 ..48 ) . map ( |body| {
123- Bagl :: LABELLINE ( LabelLine :: new ( ) . pos ( 0 , 49 ) . text ( body) ) . paint ( )
124- } ) ;
125- current_body. as_str ( ) . get ( 48 ..64 ) . map ( |body| {
126- Bagl :: LABELLINE ( LabelLine :: new ( ) . pos ( 0 , 61 ) . text ( body) ) . paint ( )
127- } ) ;
133+ let mut iter = current_body. as_bytes ( ) . chunks ( 16 ) ;
134+ if let Some ( body) = iter. next ( ) . map ( |s| from_utf8 ( s) . ok ( ) ) . flatten ( ) {
135+ body. place ( Location :: Custom ( 16 ) , Layout :: Centered , false ) ;
136+ } ;
137+ if let Some ( body) = iter. next ( ) . map ( |s| from_utf8 ( s) . ok ( ) ) . flatten ( ) {
138+ body. place ( Location :: Custom ( 31 ) , Layout :: Centered , false ) ;
139+ } ;
140+ if let Some ( body) = iter. next ( ) . map ( |s| from_utf8 ( s) . ok ( ) ) . flatten ( ) {
141+ body. place ( Location :: Custom ( 46 ) , Layout :: Centered , false ) ;
142+ } ;
128143 }
129- if backward. prev != [ 0 ; 32 ] {
130- LEFT_ARROW . paint ( ) ;
144+ if backward. prev != [ 0 ; HASH_LENGTH ] {
145+ LEFT_ARROW . instant_display ( ) ;
131146 }
132- RIGHT_ARROW . paint ( ) ;
147+ RIGHT_ARROW . instant_display ( ) ;
133148 }
134149 PromptingState :: Confirm => {
135- Bagl :: ICON ( Icon :: new ( Icons :: CheckBadge ) . pos ( 18 , 12 ) ) . display ( ) ;
136- Bagl :: LABELLINE ( LabelLine :: new ( ) . text ( "Confirm" ) . pos ( 0 , 20 ) ) . paint ( ) ;
137- LEFT_ARROW . paint ( ) ;
138- RIGHT_ARROW . paint ( ) ;
150+ CHECKMARK_ICON . set_x ( 18 ) . display ( ) ;
151+ "Confirm" . place ( Location :: Middle , Layout :: Centered , false ) ;
152+ LEFT_ARROW . instant_display ( ) ;
153+ RIGHT_ARROW . instant_display ( ) ;
139154 }
140155 PromptingState :: Cancel => {
141- Bagl :: ICON ( Icon :: new ( Icons :: CrossBadge ) . pos ( 18 , 12 ) ) . display ( ) ;
142- Bagl :: LABELLINE ( LabelLine :: new ( ) . text ( "Cancel" ) . pos ( 0 , 20 ) ) . paint ( ) ;
143- LEFT_ARROW . paint ( ) ;
156+ CROSS_ICON . set_x ( 18 ) . display ( ) ;
157+ "Reject" . place ( Location :: Middle , Layout :: Centered , false ) ;
158+ LEFT_ARROW . instant_display ( ) ;
144159 }
145160 }
146161 // Handle buttons
@@ -155,15 +170,15 @@ impl PromptQueue {
155170 // {
156171 match ( state. clone ( ) , buttons_evt) {
157172 ( PromptingState :: Prompts , ButtonEvent :: LeftButtonRelease ) => {
158- if backward. prev != [ 0 ; 32 ] {
173+ if backward. prev != [ 0 ; HASH_LENGTH ] {
159174 forward
160175 . add_prompt_chunk ( & current_title, & current_body)
161176 . await ?;
162177 title_and_body = backward. pop ( ) . await ?. unwrap ( ) ;
163178 }
164179 }
165180 ( PromptingState :: Prompts , ButtonEvent :: RightButtonRelease ) => {
166- if forward. prev != [ 0 ; 32 ] {
181+ if forward. prev != [ 0 ; HASH_LENGTH ] {
167182 backward
168183 . add_prompt_chunk ( & current_title, & current_body)
169184 . await ?;
@@ -187,7 +202,9 @@ impl PromptQueue {
187202 ( PromptingState :: Cancel , ButtonEvent :: LeftButtonRelease ) => {
188203 state = PromptingState :: Confirm ;
189204 }
190- _ => { }
205+ _ => {
206+ continue ;
207+ }
191208 }
192209 break ;
193210 } else {
@@ -197,7 +214,7 @@ impl PromptQueue {
197214 }
198215
199216 async fn add_prompt_chunk ( & mut self , title : & str , segment : & str ) -> Result < ( ) , PromptingError > {
200- if title. len ( ) > 17 {
217+ if title. len ( ) > PROMPT_TITLE_LENGTH {
201218 return Err ( PromptingError ) ;
202219 }
203220 if segment. len ( ) > PROMPT_CHUNK_LENGTH {
0 commit comments