11use crate :: {
2- db:: { FONT_TABLE as DB_TABLE , FontEntry } ,
2+ db:: { FONT_TABLE as DB_TABLE , FontEntry , FontSource } ,
33 db_select_all, db_update,
44 logic:: { toast, tr:: tr, video_editor:: playlist:: picker_files} ,
55 logic_cb,
66 slint_generatedAppWindow:: { AppWindow , FontEntry as UIFontEntry } ,
77} ;
88use once_cell:: sync:: Lazy ;
99use slint:: { ComponentHandle , Model , SharedString , VecModel , Weak } ;
10- use std:: { collections:: HashSet , path:: PathBuf } ;
11- use tokio:: sync:: RwLock ;
10+ use std:: { collections:: HashSet , path:: PathBuf , sync:: RwLock } ;
1211use video_editor:: font:: { get_font_family_from_file, get_fonts_info} ;
1312
1413db_update ! ( DB_TABLE , FontEntry ) ;
@@ -39,11 +38,19 @@ pub fn init(ui: &AppWindow) {
3938fn init_font_dialog ( ui : & AppWindow ) {
4039 let ui_weak = ui. as_weak ( ) ;
4140 tokio:: spawn ( async move {
42- let db_fonts = db_select_all ! ( DB_TABLE , FontEntry ) ;
43- if db_fonts. is_empty ( ) {
44- refresh_font_entries_impl ( ui_weak. clone ( ) ) . await ;
41+ let cached_fonts = {
42+ let cache = FONT_CACHE . read ( ) . unwrap ( ) ;
43+ if cache. is_empty ( ) {
44+ None
45+ } else {
46+ Some ( cache. clone ( ) )
47+ }
48+ } ;
49+
50+ if let Some ( fonts) = cached_fonts {
51+ sync_fonts_to_ui ( ui_weak, fonts) . await ;
4552 } else {
46- sync_fonts_to_ui ( ui_weak, db_fonts ) . await ;
53+ refresh_font_entries_impl ( ui_weak) . await ;
4754 }
4855 } ) ;
4956}
@@ -56,18 +63,19 @@ fn refresh_font_entries(ui: &AppWindow) {
5663}
5764
5865async fn refresh_font_entries_impl ( ui_weak : Weak < AppWindow > ) {
59- let marked_fonts: HashSet < String > = {
60- let db_fonts = db_select_all ! ( DB_TABLE , FontEntry ) ;
61- db_fonts
62- . into_iter ( )
63- . filter ( |f| f. marked )
64- . map ( |f| f. path )
65- . collect ( )
66- } ;
66+ let existing_fonts = db_select_all ! ( DB_TABLE , FontEntry ) ;
6767
68- if let Err ( e) = sqldb:: entry:: delete_all ( DB_TABLE ) . await {
69- log:: warn!( "Failed to clear font table: {}" , e) ;
70- }
68+ let imported_fonts: Vec < FontEntry > = existing_fonts
69+ . iter ( )
70+ . filter ( |f| f. source == FontSource :: Imported )
71+ . cloned ( )
72+ . collect ( ) ;
73+
74+ let marked_paths: HashSet < String > = existing_fonts
75+ . iter ( )
76+ . filter ( |f| f. marked )
77+ . map ( |f| f. path . clone ( ) )
78+ . collect ( ) ;
7179
7280 let system_fonts = match get_fonts_info ( ) {
7381 Ok ( fonts) => fonts,
@@ -77,16 +85,22 @@ async fn refresh_font_entries_impl(ui_weak: Weak<AppWindow>) {
7785 }
7886 } ;
7987
88+ if let Err ( e) = sqldb:: entry:: delete_all ( DB_TABLE ) . await {
89+ log:: warn!( "Failed to clear font table: {}" , e) ;
90+ }
91+
8092 let mut font_entries: Vec < FontEntry > = Vec :: new ( ) ;
93+
8194 for ( family, path) in system_fonts {
8295 let path_str = path. to_string_lossy ( ) . to_string ( ) ;
83- let marked = marked_fonts . contains ( & path_str) ;
96+ let marked = marked_paths . contains ( & path_str) ;
8497
8598 let entry = FontEntry {
8699 id : path_str. clone ( ) ,
87100 family,
88101 path : path_str,
89102 marked,
103+ source : FontSource :: System ,
90104 } ;
91105
92106 let data = serde_json:: to_string ( & entry) . expect ( "Serialize font entry" ) ;
@@ -97,13 +111,22 @@ async fn refresh_font_entries_impl(ui_weak: Weak<AppWindow>) {
97111 font_entries. push ( entry) ;
98112 }
99113
114+ for entry in imported_fonts {
115+ let data = serde_json:: to_string ( & entry) . expect ( "Serialize font entry" ) ;
116+ if let Err ( e) = sqldb:: entry:: insert ( DB_TABLE , entry. id . as_str ( ) , & data) . await {
117+ log:: warn!( "Failed to insert imported font {}: {}" , entry. family, e) ;
118+ }
119+ font_entries. push ( entry) ;
120+ }
121+
122+ {
123+ let mut cache = FONT_CACHE . write ( ) . unwrap ( ) ;
124+ * cache = font_entries. clone ( ) ;
125+ }
100126 sync_fonts_to_ui ( ui_weak, font_entries) . await ;
101127}
102128
103129async fn sync_fonts_to_ui ( ui_weak : Weak < AppWindow > , mut fonts : Vec < FontEntry > ) {
104- let fonts_for_cache = fonts. clone ( ) ;
105- * FONT_CACHE . write ( ) . await = fonts_for_cache;
106-
107130 fonts. sort_by ( |a, b| b. marked . cmp ( & a. marked ) ) ;
108131 let ui_fonts: Vec < UIFontEntry > = fonts. into_iter ( ) . map ( |f| f. into ( ) ) . collect ( ) ;
109132
@@ -133,9 +156,11 @@ fn import_font_files(ui: &AppWindow) {
133156 }
134157
135158 if !imported_fonts. is_empty ( ) {
136- let mut cache = FONT_CACHE . write ( ) . await ;
137- for font in & imported_fonts {
138- cache. push ( font. clone ( ) . into ( ) ) ;
159+ {
160+ let mut cache = FONT_CACHE . write ( ) . unwrap ( ) ;
161+ for font in & imported_fonts {
162+ cache. push ( font. clone ( ) . into ( ) ) ;
163+ }
139164 }
140165
141166 _ = ui_weak. upgrade_in_event_loop ( move |ui| {
@@ -166,6 +191,7 @@ async fn import_font_to_db(ui_weak: Weak<AppWindow>, file_path: PathBuf) -> Opti
166191 family,
167192 path : path_str,
168193 marked : true ,
194+ source : FontSource :: Imported ,
169195 } ;
170196
171197 let data = serde_json:: to_string ( & entry) . expect ( "Serialize font entry" ) ;
@@ -190,6 +216,13 @@ fn toggle_font_marked(ui: &AppWindow, index: i32) {
190216 font_info. marked = !font_info. marked ;
191217 db_update ( ui. as_weak ( ) , font_info. clone ( ) . into ( ) ) ;
192218
219+ {
220+ let mut cache = FONT_CACHE . write ( ) . unwrap ( ) ;
221+ if let Some ( entry) = cache. iter_mut ( ) . find ( |e| e. id == font_info. id . as_str ( ) ) {
222+ entry. marked = font_info. marked ;
223+ }
224+ }
225+
193226 let mut fonts: Vec < UIFontEntry > = store_font_entries ! ( ui) . iter ( ) . collect ( ) ;
194227 fonts[ idx] = font_info;
195228 fonts. sort_by ( |a, b| b. marked . cmp ( & a. marked ) ) ;
@@ -202,7 +235,7 @@ fn search_font_entries(ui: &AppWindow, text: SharedString) {
202235 let text = text. to_string ( ) ;
203236
204237 tokio:: spawn ( async move {
205- let cache = FONT_CACHE . read ( ) . await . clone ( ) ;
238+ let cache = FONT_CACHE . read ( ) . unwrap ( ) . clone ( ) ;
206239
207240 let filtered = if text. is_empty ( ) {
208241 cache
0 commit comments