@@ -55,11 +55,25 @@ impl Default for RecentNotesConfig {
5555
5656pub struct RecentNotesWidget {
5757 cfg : RecentNotesConfig ,
58+ cached : Vec < CachedRecentNote > ,
59+ last_notes_version : u64 ,
60+ }
61+
62+ #[ derive( Clone ) ]
63+ struct CachedRecentNote {
64+ title : String ,
65+ slug : String ,
66+ tags : Vec < String > ,
67+ snippet : String ,
5868}
5969
6070impl RecentNotesWidget {
6171 pub fn new ( cfg : RecentNotesConfig ) -> Self {
62- Self { cfg }
72+ Self {
73+ cfg,
74+ cached : Vec :: new ( ) ,
75+ last_notes_version : u64:: MAX ,
76+ }
6377 }
6478
6579 pub fn settings_ui (
@@ -132,11 +146,11 @@ impl RecentNotesWidget {
132146 . unwrap_or ( 0 )
133147 }
134148
135- fn build_action ( & self , note : & Note ) -> ( Action , Option < String > ) {
149+ fn build_cached_action ( & self , note : & CachedRecentNote ) -> ( Action , Option < String > ) {
136150 match self . cfg . open_mode {
137151 NoteOpenMode :: Panel => (
138152 Action {
139- label : note. alias . as_ref ( ) . unwrap_or ( & note . title ) . clone ( ) ,
153+ label : note. title . clone ( ) ,
140154 desc : "Note" . into ( ) ,
141155 action : format ! ( "note:open:{}" , note. slug) ,
142156 args : None ,
@@ -159,10 +173,7 @@ impl RecentNotesWidget {
159173 action : "query:note open " . into ( ) ,
160174 args : None ,
161175 } ,
162- Some ( format ! (
163- "note open {}" ,
164- note. alias. as_ref( ) . unwrap_or( & note. title)
165- ) ) ,
176+ Some ( format ! ( "note open {}" , note. title) ) ,
166177 ) ,
167178 }
168179 }
@@ -181,13 +192,49 @@ impl RecentNotesWidget {
181192 clean. to_string ( )
182193 }
183194 }
195+
196+ fn refresh_cache ( & mut self , ctx : & DashboardContext < ' _ > ) {
197+ if self . last_notes_version == ctx. notes_version {
198+ return ;
199+ }
200+
201+ let snapshot = ctx. data_cache . snapshot ( ) ;
202+ let mut notes_with_ts: Vec < ( u64 , Note ) > = snapshot
203+ . notes
204+ . as_ref ( )
205+ . iter ( )
206+ . filter ( |note| {
207+ self . cfg
208+ . filter_tag
209+ . as_ref ( )
210+ . is_none_or ( |tag| note. tags . iter ( ) . any ( |t| t. eq_ignore_ascii_case ( tag) ) )
211+ } )
212+ . map ( |note| ( Self :: modified_ts ( note) , note. clone ( ) ) )
213+ . collect ( ) ;
214+
215+ notes_with_ts. sort_by ( |a, b| b. 0 . cmp ( & a. 0 ) ) ;
216+ notes_with_ts. truncate ( self . cfg . count ) ;
217+
218+ self . cached = notes_with_ts
219+ . into_iter ( )
220+ . map ( |( _, note) | {
221+ let snippet = Self :: snippet ( & note) ;
222+ CachedRecentNote {
223+ title : note. alias . as_ref ( ) . unwrap_or ( & note. title ) . clone ( ) ,
224+ slug : note. slug ,
225+ tags : note. tags ,
226+ snippet,
227+ }
228+ } )
229+ . collect ( ) ;
230+
231+ self . last_notes_version = ctx. notes_version ;
232+ }
184233}
185234
186235impl Default for RecentNotesWidget {
187236 fn default ( ) -> Self {
188- Self {
189- cfg : RecentNotesConfig :: default ( ) ,
190- }
237+ Self :: new ( RecentNotesConfig :: default ( ) )
191238 }
192239}
193240
@@ -198,15 +245,9 @@ impl Widget for RecentNotesWidget {
198245 ctx : & DashboardContext < ' _ > ,
199246 _activation : WidgetActivation ,
200247 ) -> Option < WidgetAction > {
201- let snapshot = ctx. data_cache . snapshot ( ) ;
202- let mut notes: Vec < Note > = snapshot. notes . as_ref ( ) . clone ( ) ;
203- if let Some ( tag) = & self . cfg . filter_tag {
204- notes. retain ( |n| n. tags . iter ( ) . any ( |t| t. eq_ignore_ascii_case ( tag) ) ) ;
205- }
206- notes. sort_by ( |a, b| Self :: modified_ts ( b) . cmp ( & Self :: modified_ts ( a) ) ) ;
207- notes. truncate ( self . cfg . count ) ;
248+ self . refresh_cache ( ctx) ;
208249
209- if notes . is_empty ( ) {
250+ if self . cached . is_empty ( ) {
210251 ui. label ( "No notes found" ) ;
211252 return None ;
212253 }
@@ -224,16 +265,15 @@ impl Widget for RecentNotesWidget {
224265 egui:: ScrollArea :: both ( )
225266 . id_source ( scroll_id)
226267 . auto_shrink ( [ false ; 2 ] )
227- . show_rows ( ui, row_height, notes. len ( ) , |ui, range| {
228- for note in & notes[ range] {
229- let display = note. alias . as_ref ( ) . unwrap_or ( & note. title ) ;
230- let ( action, query_override) = self . build_action ( note) ;
268+ . show_rows ( ui, row_height, self . cached . len ( ) , |ui, range| {
269+ for note in & self . cached [ range] {
270+ let ( action, query_override) = self . build_cached_action ( note) ;
231271 let mut clicked_row = false ;
232272 ui. vertical ( |ui| {
233- clicked_row |= ui. add ( egui:: Button :: new ( display ) . wrap ( false ) ) . clicked ( ) ;
273+ clicked_row |= ui. add ( egui:: Button :: new ( & note . title ) . wrap ( false ) ) . clicked ( ) ;
234274 if self . cfg . show_snippet {
235275 ui. add (
236- egui:: Label :: new ( egui:: RichText :: new ( Self :: snippet ( note) ) . small ( ) )
276+ egui:: Label :: new ( egui:: RichText :: new ( & note. snippet ) . small ( ) )
237277 . wrap ( false ) ,
238278 ) ;
239279 }
@@ -259,4 +299,11 @@ impl Widget for RecentNotesWidget {
259299
260300 clicked
261301 }
302+
303+ fn on_config_updated ( & mut self , settings : & serde_json:: Value ) {
304+ if let Ok ( cfg) = serde_json:: from_value :: < RecentNotesConfig > ( settings. clone ( ) ) {
305+ self . cfg = cfg;
306+ self . last_notes_version = u64:: MAX ;
307+ }
308+ }
262309}
0 commit comments