Просмотр исходного кода

wallet: load pages on demand when scrolling up and limit scroll when you reach the end of the current buffer

darkfi 2 лет назад
Родитель
Сommit
6659eb0f7e
1 измененных файлов с 79 добавлено и 31 удалено
  1. 79 31
      bin/darkwallet/src/ui/chatview.rs

+ 79 - 31
bin/darkwallet/src/ui/chatview.rs

@@ -389,8 +389,7 @@ impl ChatView {
         if scroll < 0. {
         if scroll < 0. {
             scroll = 0.;
             scroll = 0.;
         }
         }
-        self.scroll.set(scroll);
-        self.scrollview().await;
+        self.scrollview(scroll).await;
     }
     }
 
 
     async fn handle_mouse_move(&self, mouse_x: f32, mouse_y: f32) {
     async fn handle_mouse_move(&self, mouse_x: f32, mouse_y: f32) {
@@ -427,8 +426,8 @@ impl ChatView {
                 // TODO we are maybe doing too many updates so make a widget to 'slow down'
                 // TODO we are maybe doing too many updates so make a widget to 'slow down'
                 // how often we move to fixed intervals.
                 // how often we move to fixed intervals.
                 // draw a poly shape and eval each line segment.
                 // draw a poly shape and eval each line segment.
-                self.scroll.set(start_scroll + dist);
-                self.scrollview().await;
+                let scroll = start_scroll + dist;
+                self.scrollview(scroll).await;
             }
             }
             TouchPhase::Ended => {
             TouchPhase::Ended => {
                 // Now calculate scroll acceleration
                 // Now calculate scroll acceleration
@@ -437,6 +436,11 @@ impl ChatView {
         }
         }
     }
     }
 
 
+    /// Descent = line height - baseline
+    fn descent(&self) -> f32 {
+        self.line_height.get() - self.baseline.get()
+    }
+
     /// Beware of this method. Here be dragons.
     /// Beware of this method. Here be dragons.
     /// Possibly racy so we limit it just to mouse stuff (for now).
     /// Possibly racy so we limit it just to mouse stuff (for now).
     fn cached_rect(&self) -> Option<Rectangle> {
     fn cached_rect(&self) -> Option<Rectangle> {
@@ -472,12 +476,33 @@ impl ChatView {
     }
     }
 
 
     async fn populate(&self) {
     async fn populate(&self) {
-        let mut pages = vec![];
-        let mut pages_len = 0;
+        let iter = self.tree.iter();
+        self.load_n_pages(iter, PRELOAD_PAGES).await;
+    }
+
+    /// Load an extra page
+    async fn preload_pages(&self) -> usize {
+        // Get last page
+        let last_page = self.pages2.lock().unwrap().last().unwrap().clone();
+        // get the current earliest timestamp
+        let last_timest = last_page.msgs.last().unwrap().timest;
 
 
+        // iterate from there
+        let key = last_timest.to_be_bytes();
+        let iter = self.tree.range(..key);
+
+        self.load_n_pages(iter, PRELOAD_PAGES).await
+    }
+
+    async fn load_n_pages<I: Iterator<Item = sled::Result<(sled::IVec, sled::IVec)>>>(
+        &self,
+        iter: I,
+        n: usize,
+    ) -> usize {
+        let mut pages_len = 0;
         let mut msgs = vec![];
         let mut msgs = vec![];
 
 
-        for entry in self.tree.iter().rev() {
+        for entry in iter {
             let Ok((k, v)) = entry else { break };
             let Ok((k, v)) = entry else { break };
             assert_eq!(k.len(), 4);
             assert_eq!(k.len(), 4);
             let key_bytes: [u8; 4] = k.as_ref().try_into().unwrap();
             let key_bytes: [u8; 4] = k.as_ref().try_into().unwrap();
@@ -496,42 +521,34 @@ impl ChatView {
             msgs.push(Message { timest, chatmsg, glyphs });
             msgs.push(Message { timest, chatmsg, glyphs });
 
 
             if msgs.len() >= LINES_PER_PAGE {
             if msgs.len() >= LINES_PER_PAGE {
-                let page = Page2::new(msgs.clone(), &self.render_api).await;
+                let msgs = std::mem::take(&mut msgs);
+                let page = Page2::new(msgs, &self.render_api).await;
 
 
                 self.pages2.lock().unwrap().push(page);
                 self.pages2.lock().unwrap().push(page);
-                pages_len += 1;
 
 
-                if pages_len >= PRELOAD_PAGES {
+                if pages_len >= n {
                     break
                     break
                 }
                 }
             }
             }
         }
         }
-        debug!(target: "ui::chatview", "populated {} pages", pages.len());
-        *self.pages.lock().unwrap() = pages;
+        debug!(target: "ui::chatview", "populated {} pages", pages_len);
+
+        pages_len
     }
     }
 
 
-    async fn draw_cached(&self, mut rect: Rectangle) -> Vec<DrawInstruction> {
+    async fn get_total_height(&self, rect: &Rectangle, pages: &Vec<Page2Ptr>) -> f32 {
         let font_size = self.font_size.get();
         let font_size = self.font_size.get();
         let line_height = self.line_height.get();
         let line_height = self.line_height.get();
         let baseline = self.baseline.get();
         let baseline = self.baseline.get();
-        let scroll = self.scroll.get();
-
-        let mut instrs = vec![];
 
 
         let timest_color = self.timestamp_color.get();
         let timest_color = self.timestamp_color.get();
         let text_color = self.text_color.get();
         let text_color = self.text_color.get();
         let nick_colors = self.read_nick_colors();
         let nick_colors = self.read_nick_colors();
 
 
         // Nudge the bottom line up slightly, otherwise chars like p will cross the bottom.
         // Nudge the bottom line up slightly, otherwise chars like p will cross the bottom.
-        let descent = line_height - baseline;
+        let mut current_height = self.descent();
 
 
-        let pages = self.pages2.lock().unwrap().clone();
-        let mut current_height = descent;
         for page in pages {
         for page in pages {
-            if current_height > scroll + rect.h {
-                break
-            }
-
             let mesh_inf = page.mesh_inf.lock().unwrap().clone();
             let mesh_inf = page.mesh_inf.lock().unwrap().clone();
             let mesh_inf = match mesh_inf {
             let mesh_inf = match mesh_inf {
                 Some(mesh_inf) => mesh_inf,
                 Some(mesh_inf) => mesh_inf,
@@ -553,12 +570,45 @@ impl ChatView {
                 }
                 }
             };
             };
 
 
+            current_height += mesh_inf.px_height;
+        }
+
+        current_height
+    }
+
+    async fn draw_cached(&self, mut rect: Rectangle, scroll: &mut f32) -> Vec<DrawInstruction> {
+        let mut instrs = vec![];
+
+        // Make sure we have enough pages loaded.
+        // If there's no more to load then adjust the scroll.
+        let mut pages = self.pages2.lock().unwrap().clone();
+        while self.get_total_height(&rect, &pages).await < *scroll + rect.h {
+            debug!(target: "ui::chatview", "draw_cached() loading more pages");
+
+            if self.preload_pages().await == 0 {
+                // No more pages available to load
+                pages = self.pages2.lock().unwrap().clone();
+                let new_height = self.get_total_height(&rect, &pages).await;
+                *scroll = new_height - rect.h;
+                break
+            }
+        }
+
+        let mut current_height = self.descent();
+        for page in pages {
+            if current_height > *scroll + rect.h {
+                break
+            }
+
+            let mesh_inf = page.mesh_inf.lock().unwrap().clone();
+            let mesh_inf = mesh_inf.expect("preload above should've regen_mesh()");
+
             // Apply scroll and scissor
             // Apply scroll and scissor
             // We use the scissor for scrolling
             // We use the scissor for scrolling
             // Because we use the scissor, our actual rect is now rect instead of parent_rect
             // Because we use the scissor, our actual rect is now rect instead of parent_rect
             let off_x = 0.;
             let off_x = 0.;
             // This calc decides whether scroll is in terms of pages or pixels
             // This calc decides whether scroll is in terms of pages or pixels
-            let off_y = (scroll - current_height + rect.h) / rect.h;
+            let off_y = (*scroll - current_height + rect.h) / rect.h;
             let scale_x = 1. / rect.w;
             let scale_x = 1. / rect.w;
             let scale_y = 1. / rect.h;
             let scale_y = 1. / rect.h;
             let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
             let model = glam::Mat4::from_translation(glam::Vec3::new(off_x, off_y, 0.)) *
@@ -570,16 +620,12 @@ impl ChatView {
             current_height += mesh_inf.px_height;
             current_height += mesh_inf.px_height;
         }
         }
 
 
-        if current_height < scroll + rect.h {
-            debug!(target: "ui::chatview", "draw_cached() loading more pages");
-        }
-
         instrs
         instrs
     }
     }
 
 
     /// Basically a version of redraw() where regen_mesh() is never called.
     /// Basically a version of redraw() where regen_mesh() is never called.
     /// Instead we use the cached version.
     /// Instead we use the cached version.
-    async fn scrollview(&self) {
+    async fn scrollview(&self, mut scroll: f32) {
         debug!(target: "ui::chatview", "scrollview()");
         debug!(target: "ui::chatview", "scrollview()");
         let sg = self.sg.lock().await;
         let sg = self.sg.lock().await;
         let node = sg.get_node(self.node_id).unwrap();
         let node = sg.get_node(self.node_id).unwrap();
@@ -596,7 +642,7 @@ impl ChatView {
             panic!("Node {:?} bad rect property", node);
             panic!("Node {:?} bad rect property", node);
         };
         };
 
 
-        let mut mesh_instrs = self.draw_cached(rect.clone()).await;
+        let mut mesh_instrs = self.draw_cached(rect.clone(), &mut scroll).await;
         let mut instrs = vec![DrawInstruction::ApplyViewport(rect)];
         let mut instrs = vec![DrawInstruction::ApplyViewport(rect)];
         instrs.append(&mut mesh_instrs);
         instrs.append(&mut mesh_instrs);
 
 
@@ -604,6 +650,8 @@ impl ChatView {
             vec![(self.dc_key, DrawCall { instrs, dcs: vec![], z_index: self.z_index.get() })];
             vec![(self.dc_key, DrawCall { instrs, dcs: vec![], z_index: self.z_index.get() })];
 
 
         self.render_api.replace_draw_calls(draw_calls).await;
         self.render_api.replace_draw_calls(draw_calls).await;
+
+        self.scroll.set(scroll);
     }
     }
 
 
     async fn redraw(&self) {
     async fn redraw(&self) {
@@ -684,7 +732,7 @@ impl ChatView {
 
 
         (instrs, old_drawmesh)
         (instrs, old_drawmesh)
 
 
-            /*
+        /*
         if DEBUG_RENDER {
         if DEBUG_RENDER {
             let mut debug_mesh = MeshBuilder::new();
             let mut debug_mesh = MeshBuilder::new();
             debug_mesh.draw_outline(
             debug_mesh.draw_outline(