@@ -7,11 +7,11 @@ use std::rc::Rc;
77
88use futures:: { StreamExt as _, channel:: mpsc} ;
99use gpui:: {
10- AnyElement , App , AppContext as _, ClickEvent , Context , DismissEvent , Entity , FocusHandle ,
11- Focusable , InteractiveElement as _, IntoElement , KeyDownEvent , Keystroke , MouseButton ,
12- MouseDownEvent , MouseMoveEvent , MouseUpEvent , ParentElement , Pixels , Point , Render ,
13- SharedString , Size , StatefulInteractiveElement as _, Styled , Window , div , hsla ,
14- prelude:: FluentBuilder as _, px, red, size,
10+ AnyElement , App , AppContext as _, AsyncApp , ClickEvent , Context , DismissEvent , Entity ,
11+ FocusHandle , Focusable , InteractiveElement as _, IntoElement , KeyDownEvent , Keystroke ,
12+ MouseButton , MouseDownEvent , MouseMoveEvent , MouseUpEvent , ParentElement , PathPromptOptions ,
13+ Pixels , Point , Render , SharedString , Size , StatefulInteractiveElement as _, Styled , Window ,
14+ div , hsla , prelude:: FluentBuilder as _, px, red, size,
1515} ;
1616use gpui_component:: {
1717 ActiveTheme as _, Sizable , StyledExt , VirtualListScrollHandle ,
@@ -25,7 +25,7 @@ use gpui_component::{
2525use crate :: ui:: CONTENT_PX ;
2626use crate :: {
2727 library:: { Library , LibraryEvent } ,
28- model:: { AudioFormat , FileRecord } ,
28+ model:: { AudioFormat , Category , FileRecord } ,
2929} ;
3030
3131const TAG_CELL_X_PADDING_WIDTH : f32 = 24. ;
@@ -107,6 +107,7 @@ pub struct FileTable {
107107 row_sizes : Rc < Vec < Size < Pixels > > > ,
108108 row_sizes_len : usize ,
109109 tag_width_cache : Option < TagWidthCache > ,
110+ folder_prompt_active : bool ,
110111}
111112
112113impl FileTable {
@@ -202,9 +203,54 @@ impl FileTable {
202203 row_sizes : Rc :: new ( Vec :: new ( ) ) ,
203204 row_sizes_len : 0 ,
204205 tag_width_cache : None ,
206+ folder_prompt_active : false ,
205207 }
206208 }
207209
210+ fn choose_category_folder ( & mut self , category : Category , cx : & mut Context < Self > ) {
211+ if self . folder_prompt_active {
212+ return ;
213+ }
214+
215+ self . folder_prompt_active = true ;
216+ cx. notify ( ) ;
217+
218+ let paths = cx. prompt_for_paths ( PathPromptOptions {
219+ files : false ,
220+ directories : true ,
221+ multiple : false ,
222+ prompt : Some ( format ! ( "Select {} folder" , category. label( ) ) . into ( ) ) ,
223+ } ) ;
224+ let library = self . library . downgrade ( ) ;
225+
226+ cx. spawn ( async move |this, cx : & mut AsyncApp | {
227+ let path = paths
228+ . await
229+ . ok ( )
230+ . and_then ( |paths| paths. ok ( ) )
231+ . flatten ( )
232+ . and_then ( |paths| paths. into_iter ( ) . next ( ) ) ;
233+
234+ this. update ( cx, |this, cx| {
235+ this. folder_prompt_active = false ;
236+ cx. notify ( ) ;
237+ } )
238+ . ok ( ) ?;
239+
240+ let Some ( path) = path else {
241+ return Some ( ( ) ) ;
242+ } ;
243+
244+ library
245+ . update ( cx, |lib, cx| {
246+ let _ = lib. set_category_folder ( category, path, cx) ;
247+ } )
248+ . ok ( ) ?;
249+ Some ( ( ) )
250+ } )
251+ . detach ( ) ;
252+ }
253+
208254 fn table_columns ( & mut self , cx : & mut Context < Self > ) -> ( Vec < String > , Vec < Pixels > , usize ) {
209255 let editing = self . editing . clone ( ) ;
210256 let ( keys, row_count, widths) = {
@@ -1345,7 +1391,16 @@ impl Render for FileTable {
13451391 fn render ( & mut self , _: & mut Window , cx : & mut Context < Self > ) -> impl IntoElement {
13461392 crate :: perf:: sample ( "table.render.rate" ) ;
13471393 let render_start = crate :: perf:: start ( ) ;
1348- let ( keys, tag_widths, row_count) = self . table_columns ( cx) ;
1394+ let missing_folder_category = {
1395+ let library = self . library . read ( cx) ;
1396+ let active = library. active ( ) ;
1397+ library. category_needs_folder ( active) . then_some ( active)
1398+ } ;
1399+ let ( keys, tag_widths, row_count) = if missing_folder_category. is_some ( ) {
1400+ ( Vec :: new ( ) , Vec :: new ( ) , 0 )
1401+ } else {
1402+ self . table_columns ( cx)
1403+ } ;
13491404
13501405 let mut header_row = TableRow :: new ( ) . child (
13511406 TableHead :: new ( )
@@ -1369,25 +1424,51 @@ impl Render for FileTable {
13691424 let virtual_tag_widths = tag_widths. clone ( ) ;
13701425 let row_sizes = self . row_sizes ( row_count) ;
13711426 let row_scroll_handle = self . row_scroll_handle . clone ( ) ;
1372- let rows = div ( )
1373- . size_full ( )
1374- . child (
1375- v_virtual_list (
1376- cx. entity ( ) . clone ( ) ,
1377- "file-table-rows" ,
1378- row_sizes,
1379- move |this, range, _, cx| {
1380- this. render_rows (
1381- range,
1382- virtual_keys. clone ( ) ,
1383- virtual_tag_widths. clone ( ) ,
1384- cx,
1385- )
1386- } ,
1427+ let rows: AnyElement = if let Some ( category) = missing_folder_category {
1428+ div ( )
1429+ . id ( "missing-category-folder" )
1430+ . size_full ( )
1431+ . flex ( )
1432+ . flex_col ( )
1433+ . items_center ( )
1434+ . justify_center ( )
1435+ . gap_2 ( )
1436+ . px ( CONTENT_PX )
1437+ . text_sm ( )
1438+ . text_color ( cx. theme ( ) . muted_foreground )
1439+ . cursor_pointer ( )
1440+ . child ( SharedString :: from ( format ! (
1441+ "Click this area to choose the {} folder." ,
1442+ category. label( )
1443+ ) ) )
1444+ . child ( "You can always change it via the category buttons above." )
1445+ . on_click ( cx. listener ( move |this, _: & ClickEvent , _, cx| {
1446+ this. choose_category_folder ( category, cx) ;
1447+ cx. stop_propagation ( ) ;
1448+ } ) )
1449+ . into_any_element ( )
1450+ } else {
1451+ div ( )
1452+ . size_full ( )
1453+ . child (
1454+ v_virtual_list (
1455+ cx. entity ( ) . clone ( ) ,
1456+ "file-table-rows" ,
1457+ row_sizes,
1458+ move |this, range, _, cx| {
1459+ this. render_rows (
1460+ range,
1461+ virtual_keys. clone ( ) ,
1462+ virtual_tag_widths. clone ( ) ,
1463+ cx,
1464+ )
1465+ } ,
1466+ )
1467+ . track_scroll ( & row_scroll_handle) ,
13871468 )
1388- . track_scroll ( & row_scroll_handle) ,
1389- )
1390- . scrollbar ( & row_scroll_handle , ScrollbarAxis :: Vertical ) ;
1469+ . scrollbar ( & row_scroll_handle, ScrollbarAxis :: Vertical )
1470+ . into_any_element ( )
1471+ } ;
13911472
13921473 let table = div ( )
13931474 . track_focus ( & self . focus_handle )
0 commit comments