@@ -13,13 +13,22 @@ use gtk::subclass::prelude::*;
1313use log:: { debug, error, info} ;
1414use once_cell:: sync:: Lazy ;
1515use std:: cell:: RefCell ;
16+ use std:: marker:: PhantomData ;
17+ use std:: pin:: Pin ;
18+ use std:: rc:: Rc ;
1619use url:: Url ;
1720
1821use crate :: common;
1922use crate :: common:: { glibctx, HistoryItem , LossyTextRead , PageElement , RequestCtx } ;
2023use crate :: draw_ctx:: DrawCtx ;
2124use crate :: gemini;
2225
26+ #[ derive( Clone , glib:: Boxed , Default ) ]
27+ #[ boxed_type( name = "GeopardHistoryStatus" ) ]
28+ pub struct HistoryStatus {
29+ current : usize ,
30+ available : usize ,
31+ }
2332pub mod imp {
2433
2534 pub use super :: * ;
@@ -28,11 +37,14 @@ pub mod imp {
2837 pub ( crate ) gemini_client : RefCell < gemini:: Client > ,
2938 pub ( crate ) draw_ctx : RefCell < Option < DrawCtx > > ,
3039 pub ( crate ) history : RefCell < Vec < HistoryItem > > ,
40+ pub ( crate ) current_hi : RefCell < Option < usize > > ,
3141 pub ( crate ) scroll_win : gtk:: ScrolledWindow ,
3242 pub ( crate ) clamp : adw:: Clamp ,
3343 pub ( crate ) left_click_ctrl : RefCell < Option < gtk:: GestureClick > > ,
3444 pub ( crate ) right_click_ctrl : RefCell < Option < gtk:: GestureClick > > ,
3545 pub ( crate ) req_handle : RefCell < Option < RemoteHandle < ( ) > > > ,
46+ #[ prop( get = Self :: history_status, builder( HistoryStatus :: static_type( ) ) ) ]
47+ pub ( crate ) history_status : PhantomData < HistoryStatus > ,
3648 #[ prop( get, set) ]
3749 pub ( crate ) progress : RefCell < f64 > ,
3850 #[ prop( get) ]
@@ -107,6 +119,14 @@ pub mod imp {
107119 self . derived_property ( obj, id, pspec) . unwrap ( )
108120 }
109121 }
122+ impl Tab {
123+ fn history_status ( & self ) -> HistoryStatus {
124+ HistoryStatus {
125+ current : self . current_hi . borrow ( ) . unwrap_or ( 0 ) ,
126+ available : self . history . borrow ( ) . len ( ) ,
127+ }
128+ }
129+ }
110130 impl WidgetImpl for Tab { }
111131}
112132glib:: wrapper! {
@@ -142,7 +162,7 @@ impl Tab {
142162 let imp = self . imp ( ) ;
143163 & imp. scroll_win
144164 }
145- pub fn build_request_ctx ( & self , url : Url ) -> RequestCtx {
165+ fn build_request_ctx ( & self , url : Url ) -> RequestCtx {
146166 let imp = self . imp ( ) ;
147167 RequestCtx {
148168 draw_ctx : imp. draw_ctx . borrow ( ) . clone ( ) . unwrap ( ) ,
@@ -160,12 +180,6 @@ impl Tab {
160180 . url
161181 . clone ( ) )
162182 }
163- pub fn add_cache ( & self , cache : Vec < u8 > ) {
164- let imp = self . imp ( ) ;
165- if let Some ( item) = imp. history . borrow_mut ( ) . last_mut ( ) {
166- item. cache = Some ( cache)
167- }
168- }
169183 pub fn handle_click ( & self , x : f64 , y : f64 ) -> Result < ( ) > {
170184 let imp = self . imp ( ) ;
171185 let draw_ctx = imp. draw_ctx . borrow ( ) ;
@@ -200,12 +214,41 @@ impl Tab {
200214 text_view. set_extra_menu ( Some ( & menu) ) ;
201215 Ok ( ( ) )
202216 }
217+ pub fn spawn_open_url ( & self , url : Url ) {
218+ let i = self . add_to_history ( HistoryItem {
219+ url : url. clone ( ) ,
220+ cache : Default :: default ( ) ,
221+ scroll_progress : 0.0 ,
222+ } ) ;
223+ let cache_space = Rc :: downgrade ( & self . imp ( ) . history . borrow ( ) [ i] . cache ) ;
224+ let this = self . clone ( ) ;
225+ let fut = async move {
226+ let cache = this. open_url ( url) . await ;
227+ cache_space. upgrade ( ) . map ( |rc| rc. replace ( cache) ) ;
228+ } ;
229+ self . spawn_request ( fut) ;
230+ }
231+ fn add_to_history ( & self , item : HistoryItem ) -> usize {
232+ let imp = self . imp ( ) ;
233+ let mut history = imp. history . borrow_mut ( ) ;
234+ let i = * imp. current_hi . borrow ( ) ;
235+ if let Some ( i) = i {
236+ let scroll_progress = imp. scroll_win . vadjustment ( ) . value ( ) ;
237+ history[ i] . scroll_progress = scroll_progress;
238+ history. truncate ( i + 1 ) ;
239+ } ;
240+ history. push ( item) ;
241+ let i = history. len ( ) - 1 ;
242+ imp. current_hi . replace ( Some ( i) ) ;
243+ self . log_history_position ( ) ;
244+ i
245+ }
203246 fn spawn_request ( & self , fut : impl Future < Output = ( ) > + ' static ) {
204247 let imp = self . imp ( ) ;
205248 imp. req_handle
206249 . replace ( Some ( glibctx ( ) . spawn_local_with_handle ( fut) . unwrap ( ) ) ) ;
207250 }
208- pub fn spawn_open_url ( & self , url : Url ) {
251+ fn open_url ( & self , url : Url ) -> impl Future < Output = Option < Vec < u8 > > > {
209252 let imp = self . imp ( ) ;
210253
211254 self . set_progress ( 0.0 ) ;
@@ -214,89 +257,95 @@ impl Tab {
214257 * imp. url . borrow_mut ( ) = url. to_string ( ) ;
215258 self . notify ( "url" ) ;
216259
217- let scroll_progress = imp. scroll_win . vadjustment ( ) . value ( ) ;
218- let mut history = imp. history . borrow_mut ( ) ;
219- if let Some ( item) = history. last_mut ( ) {
220- item. scroll_progress = scroll_progress;
221- }
222- history. push ( HistoryItem {
223- url : url. clone ( ) ,
224- cache : None ,
225- scroll_progress : 0.0 ,
226- } ) ;
227260 let mut req_ctx = self . build_request_ctx ( url. clone ( ) ) ;
228261
229262 let this = self . clone ( ) ;
230263 let fut = async move {
231- match Self :: send_request ( & mut req_ctx) . await {
264+ let cache = match Self :: send_request ( & mut req_ctx) . await {
232265 Ok ( Some ( cache) ) => {
233- this . add_cache ( cache ) ;
234- info ! ( "Page loaded and cached ({})" , url . clone ( ) ) ;
266+ info ! ( "Page loaded, can be cached ({})" , url . clone ( ) ) ;
267+ Some ( cache )
235268 }
236269 Ok ( _) => {
237270 info ! ( "Page loaded ({})" , url. clone( ) ) ;
271+ None
238272 }
239273 Err ( e) => {
240274 Self :: display_error ( & mut req_ctx. draw_ctx , e) ;
275+ None
241276 }
242- }
277+ } ;
243278 this. set_progress ( 1.0 ) ;
279+ cache
244280 } ;
245281 self . set_progress ( 0.3 ) ;
246- self . spawn_request ( fut) ;
282+ fut
247283 }
248- fn spawn_open_history ( & self , item : HistoryItem ) {
284+ fn open_history ( & self , item : HistoryItem ) -> Pin < Box < dyn Future < Output = ( ) > > > {
249285 let HistoryItem { url, cache, .. } = item;
250- match cache {
251- Some ( cache) => self . spawn_open_cached ( url, cache) ,
252- None => self . spawn_open_url ( url) ,
286+ let cache = cache. borrow ( ) ;
287+ match & * cache {
288+ Some ( cache) => Box :: pin ( self . open_cached ( url, cache. clone ( ) ) ) ,
289+ None => Box :: pin ( self . open_url ( url) . map ( |_| { } ) ) ,
253290 }
254291 }
255- fn spawn_open_cached ( & self , url : Url , cache : Vec < u8 > ) {
292+ fn open_cached ( & self , url : Url , cache : Vec < u8 > ) -> impl Future < Output = ( ) > {
256293 let imp = self . imp ( ) ;
257- imp. history . borrow_mut ( ) . push ( HistoryItem {
258- url : url. clone ( ) ,
259- cache : None ,
260- scroll_progress : 0.0 ,
261- } ) ;
262-
263294 let mut draw_ctx = imp. draw_ctx . borrow ( ) . clone ( ) . unwrap ( ) ;
264- let this = self . clone ( ) ;
295+
265296 * self . imp ( ) . title . borrow_mut ( ) = url. to_string ( ) ;
266297 self . notify ( "title" ) ;
267298
268299 * self . imp ( ) . url . borrow_mut ( ) = url. to_string ( ) ;
269300 self . notify ( "url" ) ;
270301
271- let fut = async move {
272- let buf = BufReader :: new ( cache. as_slice ( ) ) ;
302+ async move {
303+ let buf = BufReader :: new ( & * cache) ;
273304 draw_ctx. clear ( ) ;
274305 let res = Self :: display_gemini ( & mut draw_ctx, buf) . await ;
275306 match res {
276- Ok ( cache ) => {
307+ Ok ( _ ) => {
277308 info ! ( "Loaded {} from cache" , & url) ;
278- this. add_cache ( cache) ;
279309 }
280310 Err ( e) => Self :: display_error ( & mut draw_ctx, e) ,
281311 }
312+ }
313+ }
314+ fn log_history_position ( & self ) {
315+ let i = self . imp ( ) . current_hi . borrow ( ) ;
316+ info ! ( "history position: {i:?}" ) ;
317+ }
318+ pub fn previous ( & self ) -> Result < ( ) > {
319+ let imp = self . imp ( ) ;
320+ let i = {
321+ imp. current_hi
322+ . borrow ( )
323+ . map ( |i| i. checked_sub ( 1 ) )
324+ . flatten ( )
325+ . context ( "going back in history" ) ?
282326 } ;
283- self . spawn_request ( fut) ;
327+ imp. current_hi . replace ( Some ( i) ) ;
328+ self . log_history_position ( ) ;
329+
330+ let h = { imp. history . borrow_mut ( ) . get ( i) . cloned ( ) } ;
331+ h. map ( |x| self . spawn_request ( self . open_history ( x) ) )
332+ . context ( "retrieving previous item from history" )
284333 }
285- pub fn back ( & self ) -> Result < ( ) > {
334+ pub fn next ( & self ) -> Result < ( ) > {
286335 let imp = self . imp ( ) ;
287- let item = {
288- let mut history = imp. history . borrow_mut ( ) ;
289- if history. len ( ) <= 1 {
290- bail ! ( "Already at last item in history" ) ;
291- }
292- history. pop ( ) ;
293- history. pop ( )
336+ let i = {
337+ imp. current_hi
338+ . borrow ( )
339+ . map ( |i| i + 1 )
340+ . filter ( |i| * i < imp. history . borrow ( ) . len ( ) )
341+ . context ( "going forward in history" ) ?
294342 } ;
295- match item {
296- Some ( item) => self . spawn_open_history ( item) ,
297- None => unreachable ! ( ) ,
298- }
299- Ok ( ( ) )
343+ imp. current_hi . replace ( Some ( i) ) ;
344+ self . log_history_position ( ) ;
345+
346+ let h = { imp. history . borrow_mut ( ) . get ( i) . cloned ( ) } ;
347+ h. map ( |x| self . spawn_request ( self . open_history ( x) ) )
348+ . context ( "retrieving previous item from history" )
300349 }
301350 pub fn display_error ( ctx : & mut DrawCtx , error : anyhow:: Error ) {
302351 error ! ( "{:?}" , error) ;
0 commit comments