@@ -2,65 +2,34 @@ use std::{pin::Pin, time::Duration};
2
2
3
3
use crossterm:: event:: { Event as CrosstermEvent , KeyCode , KeyEvent , KeyEventKind } ;
4
4
use futures_util:: { FutureExt , Stream , StreamExt } ;
5
+ use ratatui:: widgets:: Widget ;
5
6
use tokio:: time:: { Instant , Sleep } ;
6
7
7
8
use crate :: {
8
9
auth:: {
9
10
self ,
10
11
device_flow:: { DeviceAccessTokenResponse , DeviceAuthorizationResponse } ,
11
- Authentication ,
12
+ Credential ,
12
13
} ,
13
14
client:: Client ,
14
15
command:: Command ,
15
16
job:: Jobs ,
16
17
terminal:: Terminal ,
17
18
ui:: {
18
19
self ,
19
- entries:: Entries ,
20
- login:: LoginMethods ,
21
- prompt:: Prompt ,
22
- subscription:: Subscription ,
23
- tabs:: { Tab , Tabs } ,
20
+ components:: { authentication:: Authentication , root:: Root , tabs:: Tab , Components } ,
24
21
theme:: Theme ,
25
22
} ,
26
23
} ;
27
24
28
25
mod direction;
29
26
pub use direction:: { Direction , IndexOutOfRange } ;
30
27
31
- /// Cureent ui screen
32
- pub enum Screen {
33
- Login ,
34
- Browse ,
35
- }
36
-
37
- /// Handle user authentication
38
- #[ derive( PartialEq , Eq ) ]
39
- pub enum AuthenticateState {
40
- NotAuthenticated ,
41
- DeviceFlow ( DeviceAuthorizationResponse ) ,
42
- Authenticated ,
43
- }
44
-
45
- pub struct LoginState {
46
- pub login_methods : LoginMethods ,
47
- pub auth_state : AuthenticateState ,
48
- }
49
-
50
- pub struct State {
51
- pub screen : Screen ,
52
- pub login : LoginState ,
53
- pub tabs : Tabs ,
54
- pub prompt : Prompt ,
55
- pub subscription : Subscription ,
56
- pub entries : Entries ,
57
- }
58
-
59
28
pub struct Application {
60
29
terminal : Terminal ,
61
30
client : Client ,
62
31
jobs : Jobs ,
63
- state : State ,
32
+ components : Components ,
64
33
theme : Theme ,
65
34
idle_timer : Pin < Box < Sleep > > ,
66
35
@@ -75,34 +44,21 @@ pub enum EventLoopControlFlow {
75
44
76
45
impl Application {
77
46
pub fn new ( terminal : Terminal , client : Client ) -> Self {
78
- let state = State {
79
- screen : Screen :: Login ,
80
- login : LoginState {
81
- login_methods : LoginMethods :: new ( ) ,
82
- auth_state : AuthenticateState :: NotAuthenticated ,
83
- } ,
84
- tabs : Tabs :: new ( ) ,
85
- subscription : Subscription :: new ( ) ,
86
- entries : Entries :: new ( ) ,
87
- prompt : Prompt :: new ( ) ,
88
- } ;
89
-
90
47
Self {
91
48
terminal,
92
49
client,
50
+ components : Components :: new ( ) ,
93
51
jobs : Jobs :: new ( ) ,
94
- state,
95
52
theme : Theme :: new ( ) ,
96
53
idle_timer : Box :: pin ( tokio:: time:: sleep ( Duration :: from_millis ( 250 ) ) ) ,
97
54
should_quit : false ,
98
55
should_render : false ,
99
56
}
100
57
}
101
58
102
- pub fn set_auth ( & mut self , auth : Authentication ) {
103
- self . client . set_credential ( auth) ;
104
- self . state . login . auth_state = AuthenticateState :: Authenticated ;
105
- self . state . screen = Screen :: Browse ;
59
+ pub fn set_credential ( & mut self , cred : Credential ) {
60
+ self . client . set_credential ( cred) ;
61
+ self . components . auth . authenticated ( ) ;
106
62
self . initial_fetch ( ) ;
107
63
self . should_render = true ;
108
64
}
@@ -170,7 +126,7 @@ impl Application {
170
126
if self . should_render {
171
127
self . render ( ) ;
172
128
self . should_render = false ;
173
- self . state . prompt . clear_error_message ( ) ;
129
+ self . components . prompt . clear_error_message ( ) ;
174
130
}
175
131
176
132
if self . should_quit {
@@ -204,8 +160,8 @@ impl Application {
204
160
self . complete_device_authroize_flow ( device_access_token)
205
161
}
206
162
Command :: MoveTabSelection ( direction) => {
207
- match self . state . tabs . move_selection ( direction) {
208
- Tab :: Subscription if !self . state . subscription . has_subscription ( ) => {
163
+ match self . components . tabs . move_selection ( direction) {
164
+ Tab :: Subscription if !self . components . subscription . has_subscription ( ) => {
209
165
next = Some ( Command :: FetchSubscription {
210
166
after : None ,
211
167
first : 50 ,
@@ -216,7 +172,7 @@ impl Application {
216
172
self . should_render = true ;
217
173
}
218
174
Command :: MoveSubscribedFeed ( direction) => {
219
- self . state . subscription . move_selection ( direction) ;
175
+ self . components . subscription . move_selection ( direction) ;
220
176
self . should_render = true ;
221
177
}
222
178
Command :: PromptFeedSubscription => {
@@ -239,15 +195,15 @@ impl Application {
239
195
self . fetch_subscription ( after, first)
240
196
}
241
197
Command :: UpdateSubscription ( sub) => {
242
- self . state . subscription . update_subscription ( sub) ;
198
+ self . components . subscription . update_subscription ( sub) ;
243
199
self . should_render = true ;
244
200
}
245
201
Command :: CompleteSubscribeFeed { feed } => {
246
- self . state . subscription . add_subscribed_feed ( feed) ;
202
+ self . components . subscription . add_subscribed_feed ( feed) ;
247
203
self . should_render = true ;
248
204
}
249
205
Command :: CompleteUnsubscribeFeed { url } => {
250
- self . state . subscription . remove_unsubscribed_feed ( url) ;
206
+ self . components . subscription . remove_unsubscribed_feed ( url) ;
251
207
self . should_render = true ;
252
208
}
253
209
Command :: OpenFeed => {
@@ -257,31 +213,30 @@ impl Application {
257
213
self . fetch_entries ( after, first) ;
258
214
}
259
215
Command :: UpdateEntries ( payload) => {
260
- self . state . entries . update_entries ( payload) ;
216
+ self . components . entries . update_entries ( payload) ;
261
217
self . should_render = true ;
262
218
}
263
219
Command :: MoveEntry ( direction) => {
264
- self . state . entries . move_selection ( direction) ;
220
+ self . components . entries . move_selection ( direction) ;
265
221
self . should_render = true ;
266
222
}
267
223
Command :: OpenEntry => {
268
224
self . open_entry ( ) ;
269
225
}
270
226
Command :: HandleError { message } => {
271
- self . state . prompt . set_error_message ( message) ;
227
+ self . components . prompt . set_error_message ( message) ;
272
228
self . should_render = true ;
273
229
}
274
230
}
275
231
}
276
232
}
277
233
278
234
fn render ( & mut self ) {
279
- let cx = ui:: Context {
280
- state : & mut self . state ,
281
- theme : & self . theme ,
282
- } ;
235
+ let cx = ui:: Context { theme : & self . theme } ;
236
+ let root = Root :: new ( & self . components , cx) ;
283
237
284
- self . terminal . render ( |frame| ui:: render ( frame, cx) ) . unwrap ( ) ;
238
+ self . terminal
239
+ . render ( |frame| Widget :: render ( root, frame. size ( ) , frame. buffer_mut ( ) ) ) ;
285
240
}
286
241
287
242
#[ allow( clippy:: single_match) ]
@@ -312,7 +267,7 @@ impl Application {
312
267
KeyCode :: BackTab => {
313
268
return Some ( Command :: MoveTabSelection ( Direction :: Left ) )
314
269
}
315
- _ => match self . state . tabs . current ( ) {
270
+ _ => match self . state . components . tabs . current ( ) {
316
271
Tab :: Feeds => match key. code {
317
272
KeyCode :: Char ( 'j' ) => {
318
273
return Some ( Command :: MoveEntry ( Direction :: Down ) )
@@ -379,6 +334,7 @@ impl Application {
379
334
// TODO: prompt deletion confirm
380
335
let Some ( url) = self
381
336
. state
337
+ . components
382
338
. subscription
383
339
. selected_feed_url ( )
384
340
. map ( ToOwned :: to_owned)
@@ -414,14 +370,20 @@ impl Application {
414
370
415
371
impl Application {
416
372
fn open_feed ( & mut self ) {
417
- let Some ( feed_website_url) = self . state . subscription . selected_feed_website_url ( ) else {
373
+ let Some ( feed_website_url) = self
374
+ . state
375
+ . components
376
+ . subscription
377
+ . selected_feed_website_url ( )
378
+ else {
418
379
return ;
419
380
} ;
420
381
open:: that ( feed_website_url) . ok ( ) ;
421
382
}
422
383
423
384
fn open_entry ( & mut self ) {
424
- let Some ( entry_website_url) = self . state . entries . selected_entry_website_url ( ) else {
385
+ let Some ( entry_website_url) = self . state . components . entries . selected_entry_website_url ( )
386
+ else {
425
387
return ;
426
388
} ;
427
389
open:: that ( entry_website_url) . ok ( ) ;
@@ -444,11 +406,6 @@ impl Application {
444
406
}
445
407
}
446
408
447
- #[ derive( Debug ) ]
448
- pub enum AuthenticateMethod {
449
- Github ,
450
- }
451
-
452
409
impl Application {
453
410
fn authenticate ( & mut self , method : AuthenticateMethod ) {
454
411
match method {
@@ -498,9 +455,9 @@ impl Application {
498
455
} ;
499
456
500
457
// TODO: handle error
501
- auth:: persist_authentication ( auth. clone ( ) ) . ok ( ) ;
458
+ auth:: persist_credential ( auth. clone ( ) ) . ok ( ) ;
502
459
503
- self . set_auth ( auth) ;
460
+ self . set_credential ( auth) ;
504
461
}
505
462
}
506
463
0 commit comments