mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-10 07:08:05 -05:00
wallet: chatview temporary finger scrolling impl
This commit is contained in:
@@ -662,7 +662,11 @@ pub(super) async fn make(app: &App) {
|
||||
#[cfg(target_os = "linux")]
|
||||
node.set_property_f32(Role::App, "mouse_scroll_start_accel", 4.).unwrap();
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
node.set_property_f32(Role::App, "mouse_scroll_decel", 0.9).unwrap();
|
||||
#[cfg(target_os = "linux")]
|
||||
node.set_property_f32(Role::App, "mouse_scroll_decel", 0.5).unwrap();
|
||||
|
||||
node.set_property_f32(Role::App, "mouse_scroll_resist", 0.9).unwrap();
|
||||
|
||||
let prop = node.get_property("timestamp_color").unwrap();
|
||||
|
||||
@@ -44,6 +44,7 @@ mod net;
|
||||
mod prop;
|
||||
mod pubsub;
|
||||
//mod py;
|
||||
mod ringbuf;
|
||||
mod scene;
|
||||
mod text;
|
||||
mod ui;
|
||||
|
||||
62
bin/darkwallet/src/ringbuf.rs
Normal file
62
bin/darkwallet/src/ringbuf.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2024 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RingBuffer<T, const N: usize> {
|
||||
vals: [Option<T>; N],
|
||||
head: i64,
|
||||
tail: i64
|
||||
}
|
||||
|
||||
impl<T, const N: usize> RingBuffer<T, N> {
|
||||
const LEN: usize = N;
|
||||
|
||||
pub fn new() -> Self {
|
||||
Self { vals: [const { None }; N], head: -1, tail: -1 }
|
||||
}
|
||||
|
||||
pub fn push(&mut self, v: T) {
|
||||
let len = Self::LEN as i64;
|
||||
|
||||
self.head = (self.head + 1) % len;
|
||||
if self.head == self.tail {
|
||||
self.tail = (self.tail + 1) % len;
|
||||
}
|
||||
|
||||
if self.tail < 0 {
|
||||
self.tail = 0;
|
||||
}
|
||||
|
||||
let _ = std::mem::replace(&mut self.vals[self.head as usize], Some(v));
|
||||
}
|
||||
|
||||
pub fn head(&self) -> Option<&T> {
|
||||
if self.head < 0 {
|
||||
return None
|
||||
}
|
||||
Some(self.vals[self.head as usize].as_ref().unwrap())
|
||||
}
|
||||
|
||||
pub fn tail(&self) -> Option<&T> {
|
||||
if self.tail < 0 {
|
||||
return None
|
||||
}
|
||||
Some(self.vals[self.tail as usize].as_ref().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ use crate::{
|
||||
mesh::{Color, MeshBuilder, COLOR_BLUE, COLOR_GREEN},
|
||||
prop::{PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyUint32, Role},
|
||||
pubsub::Subscription,
|
||||
ringbuf::RingBuffer,
|
||||
scene::{Pimpl, SceneGraph, SceneGraphPtr2, SceneNodeId},
|
||||
text::{self, Glyph, GlyphPositionIter, TextShaperPtr},
|
||||
util::{enumerate, is_whitespace},
|
||||
@@ -86,6 +87,10 @@ struct TouchInfo {
|
||||
start_scroll: f32,
|
||||
start_y: f32,
|
||||
start_instant: std::time::Instant,
|
||||
|
||||
/// Used for flick scrolling
|
||||
samples: RingBuffer<(std::time::Instant, f32), 2>,
|
||||
|
||||
last_instant: std::time::Instant,
|
||||
last_y: f32,
|
||||
}
|
||||
@@ -96,6 +101,7 @@ impl TouchInfo {
|
||||
start_scroll: 0.,
|
||||
start_y: 0.,
|
||||
start_instant: std::time::Instant::now(),
|
||||
samples: RingBuffer::new(),
|
||||
last_instant: std::time::Instant::now(),
|
||||
last_y: 0.,
|
||||
}
|
||||
@@ -474,6 +480,8 @@ impl ChatView {
|
||||
touch_info.start_scroll = self.scroll.get();
|
||||
touch_info.start_y = touch_y;
|
||||
touch_info.start_instant = std::time::Instant::now();
|
||||
touch_info.samples = RingBuffer::new();
|
||||
touch_info.samples.push((std::time::Instant::now(), touch_y));
|
||||
touch_info.last_instant = std::time::Instant::now();
|
||||
touch_info.last_y = touch_y;
|
||||
}
|
||||
@@ -485,11 +493,19 @@ impl ChatView {
|
||||
let (start_scroll, start_y, do_update) = {
|
||||
let mut touch_info = self.touch_info.lock().unwrap();
|
||||
touch_info.last_y = touch_y;
|
||||
|
||||
let last_sample = touch_info.samples.head().unwrap().0.elapsed().as_millis_f32();
|
||||
// Sample every 10ms
|
||||
if last_sample > 10. {
|
||||
touch_info.samples.push((std::time::Instant::now(), touch_y));
|
||||
}
|
||||
|
||||
let last_elapsed = touch_info.last_instant.elapsed().as_millis_f32();
|
||||
let do_update = last_elapsed > 20.;
|
||||
if do_update {
|
||||
touch_info.last_instant = std::time::Instant::now();
|
||||
}
|
||||
|
||||
(touch_info.start_scroll, touch_info.start_y, do_update)
|
||||
};
|
||||
|
||||
@@ -500,7 +516,7 @@ impl ChatView {
|
||||
// how often we move to fixed intervals.
|
||||
// draw a poly shape and eval each line segment.
|
||||
let scroll = start_scroll + dist;
|
||||
let instant = std::time::Instant::now();
|
||||
|
||||
if do_update {
|
||||
self.scrollview(scroll).await;
|
||||
}
|
||||
@@ -511,10 +527,17 @@ impl ChatView {
|
||||
// Now calculate scroll acceleration
|
||||
let touch_info = self.touch_info.lock().unwrap().clone();
|
||||
|
||||
let time = touch_info.start_instant.elapsed().as_millis_f32();
|
||||
let dist = touch_y - touch_info.start_y;
|
||||
let (oldest_sample, sample_y) = touch_info.samples.head().unwrap();
|
||||
//let Some((oldest_sample, sample_y)) = touch_info.samples.head() else { return };
|
||||
let time = oldest_sample.elapsed().as_millis_f32();
|
||||
let dist = touch_y - sample_y;
|
||||
|
||||
//let speed = dist / time;
|
||||
//self.speed.fetch_add(speed, Ordering::Relaxed);
|
||||
//debug!(target: "ui::chatview", "speed = {dist} / {time} = {speed}");
|
||||
|
||||
let accel = self.mouse_scroll_start_accel.get() * dist / time;
|
||||
debug!(target: "ui::chatview", "accel = {dist} / {time} = {accel}");
|
||||
self.accel.fetch_add(accel, Ordering::Relaxed);
|
||||
self.motion_cv.notify();
|
||||
}
|
||||
@@ -574,17 +597,18 @@ impl ChatView {
|
||||
|
||||
async fn handle_movement(&self) {
|
||||
loop {
|
||||
msleep(20).await;
|
||||
let mut accel = self.accel.load(Ordering::Relaxed);
|
||||
let mut speed = self.speed.fetch_add(accel, Ordering::Relaxed) + accel;
|
||||
|
||||
// Apply resistance to acceleration
|
||||
accel *= self.mouse_scroll_decel.get();
|
||||
if accel.abs() < 0.05 {
|
||||
accel = 0.;
|
||||
}
|
||||
self.accel.store(accel, Ordering::Relaxed);
|
||||
|
||||
// Apply constant decel to speed
|
||||
if is_zero(accel) {
|
||||
// Apply constant decel to speed
|
||||
speed *= self.mouse_scroll_resist.get();
|
||||
if speed.abs() < BIG_EPSILON {
|
||||
speed = 0.;
|
||||
@@ -597,25 +621,22 @@ impl ChatView {
|
||||
return
|
||||
}
|
||||
|
||||
if is_zero(speed) {
|
||||
self.accel.store(0., Ordering::Relaxed);
|
||||
self.speed.store(0., Ordering::Relaxed);
|
||||
return
|
||||
}
|
||||
|
||||
let scroll = self.scroll.get() + speed;
|
||||
let dist = self.scrollview(scroll).await;
|
||||
|
||||
// We reached the end so just stop
|
||||
if is_zero(dist) {
|
||||
self.accel.store(0., Ordering::Relaxed);
|
||||
self.speed.store(0., Ordering::Relaxed);
|
||||
return
|
||||
}
|
||||
|
||||
msleep(20).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_bgload(&self) {
|
||||
debug!(target: "ui::chatview", "ChatView::handle_bgload()");
|
||||
//debug!(target: "ui::chatview", "ChatView::handle_bgload()");
|
||||
// Do we need to load some more?
|
||||
let scroll = self.scroll.get();
|
||||
let mut rect = read_rect(self.rect.clone()).expect("bad rect property");
|
||||
@@ -628,20 +649,20 @@ impl ChatView {
|
||||
let total_height = msgbuf.calc_total_height().await;
|
||||
if total_height > top + preload_height {
|
||||
// Nothing to do here
|
||||
debug!(target: "ui::chatview", "bgloader: buffer is sufficient");
|
||||
//debug!(target: "ui::chatview", "bgloader: buffer is sufficient");
|
||||
return
|
||||
}
|
||||
|
||||
// Keep loading until this is below 0
|
||||
let mut remaining_load_height = top + preload_height - total_height;
|
||||
debug!(target: "ui::chatview", "bgloader: remaining px = {remaining_load_height}");
|
||||
//debug!(target: "ui::chatview", "bgloader: remaining px = {remaining_load_height}");
|
||||
let mut remaining_visible = top - total_height;
|
||||
|
||||
// Get the current earliest timestamp
|
||||
let iter = match msgbuf.oldest_timestamp() {
|
||||
Some(oldest_timest) => {
|
||||
// iterate from there
|
||||
debug!(target: "ui::chatview", "preloading from {oldest_timest}");
|
||||
//debug!(target: "ui::chatview", "preloading from {oldest_timest}");
|
||||
let timest = (oldest_timest - 1).to_be_bytes();
|
||||
let mut key = [0u8; 8 + 32];
|
||||
key[..8].clone_from_slice(×t);
|
||||
@@ -650,7 +671,7 @@ impl ChatView {
|
||||
iter
|
||||
}
|
||||
None => {
|
||||
debug!(target: "ui::chatview", "initial load");
|
||||
//debug!(target: "ui::chatview", "initial load");
|
||||
self.tree.iter().rev()
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user