@@ -13,6 +13,7 @@ mod token;
1313mod view;
1414
1515use rune:: { AppSpec , TextEdit , Tx } ;
16+ use rune_kit:: ComboboxState ;
1617use settings:: Settings ;
1718use sync:: { Session , Setup , SyncThread } ;
1819use zbugs_model:: args:: {
@@ -84,14 +85,11 @@ pub struct Filter {
8485/// A dropdown on the issue page.
8586#[ derive( Clone , Debug , PartialEq , Eq ) ]
8687pub enum Picker {
87- Assignee ,
8888 Labels ,
8989 Visibility ,
9090 Notifications ,
9191 /// The sidebar's.
9292 Project ,
93- CreatorFilter ,
94- AssigneeFilter ,
9593 LabelFilter ,
9694 /// Reactions to the issue (its ID) or to one of its comments.
9795 Emoji ( String ) ,
@@ -110,7 +108,6 @@ pub enum Confirm {
110108pub enum Sheet {
111109 NewIssue ,
112110 EditIssue ,
113- NewLabel ,
114111 Login ,
115112 Servers ,
116113}
@@ -172,7 +169,13 @@ pub struct App {
172169 pub title_edit : TextEdit ,
173170 pub description_edit : TextEdit ,
174171 pub token_edit : TextEdit ,
175- pub label_edit : TextEdit ,
172+ /// The label picker's filter, which also names a label to create.
173+ pub label_search : TextEdit ,
174+ /// The searchable people pickers: the list's creator and assignee
175+ /// filters, and the issue's assignee.
176+ pub creator_combo : ComboboxState ,
177+ pub assignee_filter_combo : ComboboxState ,
178+ pub assignee_combo : ComboboxState ,
176179 pub cache_edit : TextEdit ,
177180 pub api_edit : TextEdit ,
178181 pub sheet_error : Option < String > ,
@@ -284,7 +287,10 @@ impl App {
284287 title_edit : TextEdit :: new ( "" ) ,
285288 description_edit : TextEdit :: new ( "" ) ,
286289 token_edit : TextEdit :: new ( "" ) ,
287- label_edit : TextEdit :: new ( "" ) ,
290+ label_search : TextEdit :: new ( "" ) ,
291+ creator_combo : ComboboxState :: default ( ) ,
292+ assignee_filter_combo : ComboboxState :: default ( ) ,
293+ assignee_combo : ComboboxState :: default ( ) ,
288294 cache_edit : TextEdit :: new ( "" ) ,
289295 api_edit : TextEdit :: new ( "" ) ,
290296 sheet_error : None ,
@@ -727,15 +733,17 @@ impl App {
727733 }
728734 }
729735
730- /// Creates a label in the issue's project and adds it to the issue.
731- pub fn save_label ( & mut self ) {
732- let name = self . label_edit . text . trim ( ) . to_owned ( ) ;
733- if name. is_empty ( ) {
734- self . sheet_error = Some ( "A label needs a name." . into ( ) ) ;
735- return ;
736- }
737- if self . labels . iter ( ) . any ( |l| l. name == name) {
738- self . sheet_error = Some ( format ! ( "There's already a label named {name}." ) ) ;
736+ /// Creates a label named as the label picker's filter, in the issue's
737+ /// project, and adds it to the issue, unless a label has that name
738+ /// (whatever its case), as the web picker does.
739+ pub fn create_label ( & mut self ) {
740+ let name = self . label_search . text . trim ( ) . to_owned ( ) ;
741+ if name. is_empty ( )
742+ || self
743+ . labels
744+ . iter ( )
745+ . any ( |l| l. name . to_lowercase ( ) == name. to_lowercase ( ) )
746+ {
739747 return ;
740748 }
741749 let Some ( issue) = & self . detail else { return } ;
@@ -745,7 +753,8 @@ impl App {
745753 label_name : name,
746754 project_id : None ,
747755 } ) ) ;
748- self . sheet = None ;
756+ self . label_search = TextEdit :: new ( "" ) ;
757+ self . label_search . focused = true ;
749758 }
750759
751760 pub fn toggle_open ( & mut self ) {
@@ -845,9 +854,16 @@ impl App {
845854 }
846855
847856 pub fn toggle_picker ( & mut self , picker : Picker ) {
848- if matches ! ( picker, Picker :: Emoji ( _) ) {
849- self . emoji_search = TextEdit :: new ( "" ) ;
850- self . emoji_search . focused = true ;
857+ match picker {
858+ Picker :: Emoji ( _) => {
859+ self . emoji_search = TextEdit :: new ( "" ) ;
860+ self . emoji_search . focused = true ;
861+ }
862+ Picker :: Labels => {
863+ self . label_search = TextEdit :: new ( "" ) ;
864+ self . label_search . focused = true ;
865+ }
866+ _ => { }
851867 }
852868 self . picker = ( self . picker . as_ref ( ) != Some ( & picker) ) . then_some ( picker) ;
853869 }
@@ -961,11 +977,6 @@ impl App {
961977 self . title_edit = TextEdit :: new ( issue. title . clone ( ) ) ;
962978 self . description_edit = TextEdit :: new ( issue. description . clone ( ) ) ;
963979 }
964- Sheet :: NewLabel => {
965- self . picker = None ;
966- self . label_edit = TextEdit :: new ( "" ) ;
967- self . label_edit . focused = true ;
968- }
969980 Sheet :: Login => self . token_edit = TextEdit :: new ( "" ) ,
970981 Sheet :: Servers => {
971982 self . cache_edit = TextEdit :: new ( self . settings . cache_url . clone ( ) ) ;
@@ -1104,8 +1115,9 @@ fn apply_issues(s: &mut App, rows: Vec<Issue>, result_type: ResultType, tx: &mut
11041115 }
11051116}
11061117
1107- /// Keys no control took: j and k step through the list, and / starts a
1108- /// search, as on the web.
1118+ /// Keys no control took: j and k step through the list, / starts a search,
1119+ /// as on the web, and Escape closes an open picker (Rune's popovers leave
1120+ /// Escape to the app).
11091121fn on_key ( s : & mut App , event : & rune:: KeyEvent , tx : & mut Tx ) -> bool {
11101122 if s. sheet . is_some ( )
11111123 || s. confirm . is_some ( )
@@ -1116,6 +1128,7 @@ fn on_key(s: &mut App, event: &rune::KeyEvent, tx: &mut Tx) -> bool {
11161128 return false ;
11171129 }
11181130 match & event. key {
1131+ rune:: Key :: Escape if s. picker . is_some ( ) => s. picker = None ,
11191132 rune:: Key :: Text ( t) if t == "j" => s. step ( 1 , tx) ,
11201133 rune:: Key :: Text ( t) if t == "k" => s. step ( -1 , tx) ,
11211134 rune:: Key :: Text ( t) if t == "/" => s. search . focused = true ,
0 commit comments