1
+ use std:: str:: FromStr ;
1
2
use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
2
3
3
4
use timeago;
4
5
6
+ use librad:: collaborative_objects:: ObjectId ;
7
+
5
8
use tui_realm_stdlib:: Phantom ;
6
9
7
10
use tuirealm:: command:: { Cmd , CmdResult , Direction } ;
@@ -14,11 +17,11 @@ use tuirealm::tui::widgets::{List as TuiList, ListItem, ListState as TuiListStat
14
17
use tuirealm:: { Component , Frame , MockComponent , NoUserEvent , State , StateValue } ;
15
18
16
19
use radicle_common:: cobs:: issue:: * ;
20
+ use radicle_common:: cobs:: Comment ;
17
21
use radicle_terminal_tui as tui;
18
22
use tui:: components:: { ApplicationTitle , ShortcutBar , TabContainer } ;
19
23
use tui:: state:: ListState ;
20
24
21
- use super :: app:: Group ;
22
25
use super :: app:: Message ;
23
26
24
27
/// Since `terminal-tui` does not know the type of messages that are being
@@ -64,6 +67,20 @@ impl Component<Message, NoUserEvent> for TabContainer {
64
67
_ => None ,
65
68
}
66
69
}
70
+ Event :: Keyboard ( KeyEvent {
71
+ code : Key :: Enter , ..
72
+ } ) => match self . perform ( Cmd :: Submit ) {
73
+ CmdResult :: Batch ( batch) => batch. iter ( ) . fold ( None , |_, result| match result {
74
+ CmdResult :: Submit ( State :: One ( StateValue :: String ( id) ) ) => {
75
+ match ObjectId :: from_str ( & id) {
76
+ Ok ( id) => Some ( Message :: EnterDetail ( id) ) ,
77
+ Err ( _) => None ,
78
+ }
79
+ }
80
+ _ => None ,
81
+ } ) ,
82
+ _ => None ,
83
+ } ,
67
84
Event :: Keyboard ( KeyEvent { code : Key :: Up , .. } ) => {
68
85
self . perform ( Cmd :: Move ( Direction :: Up ) ) ;
69
86
None
@@ -80,16 +97,14 @@ impl Component<Message, NoUserEvent> for TabContainer {
80
97
}
81
98
82
99
pub struct IssueList {
83
- props : Props ,
84
- group : Group ,
100
+ attributes : Props ,
85
101
issues : ListState < ( IssueId , Issue ) > ,
86
102
}
87
103
88
104
impl IssueList {
89
- pub fn new ( issues : Vec < ( IssueId , Issue ) > , group : Group ) -> Self {
105
+ pub fn new ( issues : Vec < ( IssueId , Issue ) > ) -> Self {
90
106
Self {
91
- props : Props :: default ( ) ,
92
- group : group,
107
+ attributes : Props :: default ( ) ,
93
108
issues : ListState :: new ( issues) ,
94
109
}
95
110
}
@@ -150,11 +165,11 @@ impl MockComponent for IssueList {
150
165
}
151
166
152
167
fn query ( & self , attr : Attribute ) -> Option < AttrValue > {
153
- self . props . get ( attr)
168
+ self . attributes . get ( attr)
154
169
}
155
170
156
171
fn attr ( & mut self , attr : Attribute , value : AttrValue ) {
157
- self . props . set ( attr, value) ;
172
+ self . attributes . set ( attr, value) ;
158
173
}
159
174
160
175
fn state ( & self ) -> State {
@@ -165,18 +180,113 @@ impl MockComponent for IssueList {
165
180
match cmd {
166
181
Cmd :: Move ( Direction :: Up ) => {
167
182
self . issues . select_previous ( ) ;
183
+ let selected = self . issues . items ( ) . selected_index ( ) ;
184
+ CmdResult :: Changed ( State :: One ( StateValue :: Usize ( selected) ) )
168
185
}
169
186
Cmd :: Move ( Direction :: Down ) => {
170
187
self . issues . select_next ( ) ;
188
+ let selected = self . issues . items ( ) . selected_index ( ) ;
189
+ CmdResult :: Changed ( State :: One ( StateValue :: Usize ( selected) ) )
171
190
}
172
- _ => { }
191
+ Cmd :: Submit => {
192
+ let ( id, _) = self . issues . items ( ) . selected ( ) . unwrap ( ) ;
193
+ CmdResult :: Submit ( State :: One ( StateValue :: String ( id. to_string ( ) ) ) )
194
+ }
195
+ _ => CmdResult :: None ,
173
196
}
174
- CmdResult :: None
175
197
}
176
198
}
177
199
178
200
impl Component < Message , NoUserEvent > for IssueList {
179
- fn on ( & mut self , ev : Event < NoUserEvent > ) -> Option < Message > {
201
+ fn on ( & mut self , _event : Event < NoUserEvent > ) -> Option < Message > {
180
202
None
181
203
}
182
204
}
205
+
206
+ pub struct CommentList < R > {
207
+ attributes : Props ,
208
+ comments : ListState < Comment < R > > ,
209
+ }
210
+
211
+ impl < R > CommentList < R > {
212
+ pub fn new ( comments : Vec < Comment < R > > ) -> Self {
213
+ Self {
214
+ attributes : Props :: default ( ) ,
215
+ comments : ListState :: new ( comments) ,
216
+ }
217
+ }
218
+
219
+ fn items ( & self , comment : & Comment < R > ) -> ListItem {
220
+ let lines = vec ! [ Spans :: from( Span :: styled(
221
+ comment. body. clone( ) ,
222
+ Style :: default ( ) . fg( Color :: Rgb ( 117 , 113 , 249 ) ) ,
223
+ ) ) ] ;
224
+ ListItem :: new ( lines)
225
+ }
226
+ }
227
+
228
+ impl < R > MockComponent for CommentList < R > {
229
+ fn view ( & mut self , render : & mut Frame , area : Rect ) {
230
+ let items = self
231
+ . comments
232
+ . items ( )
233
+ . all ( )
234
+ . iter ( )
235
+ . map ( |comment| self . items ( comment) )
236
+ . collect :: < Vec < _ > > ( ) ;
237
+
238
+ let list = TuiList :: new ( items)
239
+ . style ( Style :: default ( ) . fg ( Color :: White ) )
240
+ . highlight_style ( Style :: default ( ) . fg ( Color :: Rgb ( 238 , 111 , 248 ) ) )
241
+ . highlight_symbol ( "│ " )
242
+ . repeat_highlight_symbol ( true ) ;
243
+
244
+ let mut state: TuiListState = TuiListState :: default ( ) ;
245
+ state. select ( Some ( self . comments . items ( ) . selected_index ( ) ) ) ;
246
+ render. render_stateful_widget ( list, area, & mut state) ;
247
+ }
248
+
249
+ fn query ( & self , attr : Attribute ) -> Option < AttrValue > {
250
+ self . attributes . get ( attr)
251
+ }
252
+
253
+ fn attr ( & mut self , attr : Attribute , value : AttrValue ) {
254
+ self . attributes . set ( attr, value) ;
255
+ }
256
+
257
+ fn state ( & self ) -> State {
258
+ State :: One ( StateValue :: Usize ( self . comments . items ( ) . selected_index ( ) ) )
259
+ }
260
+
261
+ fn perform ( & mut self , cmd : Cmd ) -> CmdResult {
262
+ match cmd {
263
+ Cmd :: Move ( Direction :: Up ) => {
264
+ self . comments . select_previous ( ) ;
265
+ }
266
+ Cmd :: Move ( Direction :: Down ) => {
267
+ self . comments . select_next ( ) ;
268
+ }
269
+ _ => { }
270
+ }
271
+ CmdResult :: None
272
+ }
273
+ }
274
+
275
+ impl < R > Component < Message , NoUserEvent > for CommentList < R > {
276
+ fn on ( & mut self , event : Event < NoUserEvent > ) -> Option < Message > {
277
+ match event {
278
+ Event :: Keyboard ( KeyEvent {
279
+ code : Key :: Down , ..
280
+ } ) => {
281
+ self . perform ( Cmd :: Move ( Direction :: Down ) ) ;
282
+ None
283
+ }
284
+ Event :: Keyboard ( KeyEvent { code : Key :: Up , .. } ) => {
285
+ self . perform ( Cmd :: Move ( Direction :: Up ) ) ;
286
+ None
287
+ }
288
+ Event :: Keyboard ( KeyEvent { code : Key :: Esc , .. } ) => Some ( Message :: LeaveDetail ) ,
289
+ _ => None ,
290
+ }
291
+ }
292
+ }
0 commit comments