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

app: add gesture stub submod to window, and make sure app compiles/runs when enable-plugins feature is disabled

jkds 3 месяцев назад
Родитель
Сommit
9f16bed6fe

+ 1 - 0
bin/app/Cargo.lock

@@ -1461,6 +1461,7 @@ name = "darkfi"
 version = "0.5.0"
 dependencies = [
  "arti-client",
+ "async-std",
  "async-trait",
  "blake3",
  "bs58",

+ 11 - 20
bin/app/src/app/mod.rs

@@ -26,13 +26,14 @@ use crate::android;
 use crate::{
     error::Error,
     gfx::{gfxtag, EpochIndex, GraphicsEventPublisherPtr, Renderer},
-    plugin::PluginSettings,
     prop::{PropertyAtomicGuard, PropertyValue, Role},
     scene::{Pimpl, SceneNode, SceneNodePtr, SceneNodeType},
     ui::Window,
     util::i18n::I18nBabelFish,
     ExecutorPtr,
 };
+#[cfg(feature = "enable-plugins")]
+use crate::plugin::PluginSettings;
 
 pub mod locale;
 use locale::read_locale_ftl;
@@ -82,11 +83,17 @@ impl App {
         let setting_root = SceneNode::new("setting", SceneNodeType::SettingRoot);
         let setting_root = setting_root.setup_null();
         let settings_tree = db.open_tree("settings").unwrap();
+        // Commenting this out since it doesnt compile when enable-plugins isnt enabled.
+        /*
         let settings = Arc::new(PluginSettings {
             setting_root: setting_root.clone(),
             sled_tree: settings_tree,
         });
+        */
 
+        let i18n_fish = self.setup_locale();
+
+        let window = create_window("window");
         #[cfg(target_os = "android")]
         let window_scale = {
             let screen_density = android::get_screen_density();
@@ -97,31 +104,15 @@ impl App {
         let window_scale = 1.;
 
         d!("Setting window scale to {window_scale}");
+        let prop = window.get_property("scale").unwrap();
+        let atom = &mut PropertyAtomicGuard::none();
+        prop.set_f32(atom, Role::App, 0, window_scale).unwrap();
 
-        settings.add_setting("scale", PropertyValue::Float32(window_scale));
-        //settings.load_settings();
-
-        // Save app settings in sled when they change
-        for setting_node in settings.setting_root.get_children().iter() {
-            let setting_sub = setting_node.get_property("value").unwrap().subscribe_modify();
-            let settings2 = settings.clone();
-            let setting_task = self.ex.spawn(async move {
-                while let Ok(_) = setting_sub.receive().await {
-                    settings2.save_settings();
-                }
-            });
-            self.tasks.lock().unwrap().push(setting_task);
-        }
-
-        let i18n_fish = self.setup_locale();
-
-        let window = create_window("window");
         #[cfg(target_os = "android")]
         {
             let insets = android::insets::get_insets();
             d!("Setting window insets to {insets:?}");
             let prop = window.get_property("insets").unwrap();
-            let atom = &mut PropertyAtomicGuard::none();
             for i in 0..4 {
                 prop.set_f32(atom, Role::App, i, insets[i]).unwrap();
             }

+ 5 - 0
bin/app/src/app/node.rs

@@ -41,6 +41,11 @@ pub fn create_window(name: &str) -> SceneNode {
     prop.set_defaults_f32(vec![0., 0., 0., 0.]).unwrap();
     node.add_property(prop).unwrap();
 
+    let mut prop = Property::new("scale", PropertyType::Float32, PropertySubType::Null);
+    prop.set_ui_text("Scale", "Window scale factor for DPI scaling");
+    prop.set_defaults_f32(vec![1.0]).unwrap();
+    node.add_property(prop).unwrap();
+
     node.add_signal("start", "App UI started", vec![]).unwrap();
     node.add_signal("stop", "App UI stopped", vec![]).unwrap();
 

+ 13 - 17
bin/app/src/app/schema/chat.rs

@@ -30,7 +30,6 @@ use crate::{
     },
     expr::{self, Compiler},
     gfx::gfxtag,
-    plugin::darkirc,
     prop::{
         Property, PropertyAtomicGuard, PropertyBool, PropertyFloat32, PropertyStr, PropertySubType,
         PropertyType, Role,
@@ -43,6 +42,8 @@ use crate::{
     },
     util::{i18n::I18nBabelFish, unixtime},
 };
+#[cfg(feature = "enable-plugins")]
+use crate::plugin::darkirc;
 
 use super::{ColorScheme, COLOR_SCHEME};
 
@@ -187,9 +188,9 @@ pub async fn make(
     is_first_time: bool,
 ) {
     let window_scale = PropertyFloat32::wrap(
-        &app.sg_root.lookup_node("/setting/scale").unwrap(),
+        &app.sg_root.lookup_node("/window").unwrap(),
         Role::Internal,
-        "value",
+        "scale",
         0,
     )
     .unwrap();
@@ -955,20 +956,15 @@ pub async fn make(
 
             let timest = UNIX_EPOCH.elapsed().unwrap().as_millis() as u64;
             let nick = darkirc.get_property_str("nick").unwrap();
-            let msg = darkirc::Privmsg::new(channel, nick, text);
-
-            //let mut data = vec![];
-            //timest.encode(&mut data).unwrap();
-            //msg.msg_id(timest).encode(&mut data).unwrap();
-            //msg.nick.encode(&mut data).unwrap();
-            //msg.msg.encode(&mut data).unwrap();
-            //chatview_node.call_method("insert_unconf_line", data).await.unwrap();
-
-            let mut data = vec![];
-            timest.encode(&mut data).unwrap();
-            msg.channel.encode(&mut data).unwrap();
-            msg.msg.encode(&mut data).unwrap();
-            darkirc.call_method("send", data).await.unwrap();
+            #[cfg(feature = "enable-plugins")]
+            {
+                let msg = darkirc::Privmsg::new(channel, nick, text);
+                let mut data = vec![];
+                timest.encode(&mut data).unwrap();
+                msg.channel.encode(&mut data).unwrap();
+                msg.msg.encode(&mut data).unwrap();
+                darkirc.call_method("send", data).await.unwrap();
+            }
         }
     };
 

+ 2 - 2
bin/app/src/app/schema/menu/mod.rs

@@ -86,9 +86,9 @@ mod edit_switch;
 
 pub async fn make(app: &App, content: SceneNodePtr, i18n_fish: &I18nBabelFish) {
     let window_scale = PropertyFloat32::wrap(
-        &app.sg_root.lookup_node("/setting/scale").unwrap(),
+        &app.sg_root.lookup_node("/window").unwrap(),
         Role::Internal,
-        "value",
+        "scale",
         0,
     )
     .unwrap();

+ 1 - 0
bin/app/src/main.rs

@@ -38,6 +38,7 @@ mod logger;
 mod mesh;
 #[cfg(feature = "enable-netdebug")]
 mod net;
+#[cfg(feature = "enable-plugins")]
 mod plugin;
 mod prop;
 mod pubsub;

+ 0 - 1
bin/app/src/plugin/mod.rs

@@ -25,7 +25,6 @@ pub use darkirc::DarkIrcPtr;
 pub mod fud;
 pub use fud::FudPluginPtr as FudPtr;
 
-#[cfg(feature = "enable-plugins")]
 pub use {darkirc::DarkIrc, fud::FudPlugin};
 
 use darkfi::net::Settings as NetSettings;

+ 4 - 1
bin/app/src/scene.rs

@@ -31,11 +31,12 @@ use std::{
 
 use crate::{
     error::{Error, Result},
-    plugin,
     prop::{Property, PropertyAtomicGuard, PropertyPtr, Role},
     pubsub::{Publisher, PublisherPtr, Subscription},
     ui,
 };
+#[cfg(feature = "enable-plugins")]
+use crate::plugin;
 
 macro_rules! t { ($($arg:tt)*) => { trace!(target: "scene", $($arg)*); } }
 
@@ -580,7 +581,9 @@ pub enum Pimpl {
     Gesture(ui::GesturePtr),
     EmojiPicker(ui::EmojiPickerPtr),
     Menu(ui::MenuPtr),
+    #[cfg(feature = "enable-plugins")]
     DarkIrc(plugin::DarkIrcPtr),
+    #[cfg(feature = "enable-plugins")]
     Fud(plugin::FudPtr),
 }
 

+ 4 - 1
bin/app/src/ui/mod.rs

@@ -61,7 +61,7 @@ pub use menu::{Menu, MenuPtr};
 mod text;
 pub use text::{Text, TextPtr};
 mod win;
-pub use win::{Window, WindowPtr};
+pub use win::{GestureEvent, GestureType, Window, WindowPtr};
 
 macro_rules! e { ($($arg:tt)*) => { error!(target: "scene::on_modify", $($arg)*); } }
 macro_rules! t { ($($arg:tt)*) => { trace!(target: "scene::on_modify", $($arg)*); } }
@@ -111,6 +111,9 @@ pub trait UIObject: Sync {
     async fn handle_touch(&self, _phase: TouchPhase, _id: u64, _touch_pos: Point) -> bool {
         false
     }
+    async fn handle_gesture(&self, _gesture: GestureEvent) -> bool {
+        false
+    }
 
     fn handle_touch_sync(
         &self,

+ 150 - 0
bin/app/src/ui/win/gesture.rs

@@ -0,0 +1,150 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2026 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/>.
+ */
+
+use miniquad::TouchPhase;
+
+use crate::gfx::Point;
+
+/// Maximum number of simultaneous touch points to track
+const MAX_TOUCH_POINTS: usize = 10;
+
+/// Gesture recognition thresholds
+const TAP_MAX_MOVEMENT: f32 = 10.0;
+const TAP_MAX_DURATION: u64 = 300;
+const DRAG_MIN_MOVEMENT: f32 = 15.0;
+const FLICK_MIN_VELOCITY: f32 = 500.0;
+const LONG_PRESS_MIN_DURATION: u64 = 500;
+const LONG_PRESS_MAX_MOVEMENT: f32 = 20.0;
+
+/// Types of gestures that can be recognized
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum GestureType {
+    /// A quick tap without significant movement
+    Tap,
+    /// Continuous drag gesture
+    Drag,
+    /// Quick flick with velocity
+    Flick,
+    /// Long press without movement
+    LongPress,
+}
+
+/// High-level gesture event with relevant data
+#[derive(Debug, Clone)]
+pub struct GestureEvent {
+    /// Type of gesture recognized
+    pub gesture_type: GestureType,
+    /// Touch ID that generated this gesture
+    pub touch_id: u64,
+    /// Current position of the gesture
+    pub position: Point,
+    /// Starting position (for drag/flick)
+    pub start_position: Point,
+    /// Time elapsed since touch started (milliseconds)
+    pub duration_ms: u64,
+    /// Velocity in pixels per second (for flick)
+    pub velocity: Option<Point>,
+    /// Total displacement from start (for drag)
+    pub displacement: Option<Point>,
+}
+
+/// State for tracking a single touch point
+#[derive(Debug, Clone)]
+struct TouchTracker {
+    /// Start position
+    start_pos: Point,
+    /// Current position
+    curr_pos: Point,
+    /// Previous position (for velocity calculation)
+    prev_pos: Option<Point>,
+    /// Start timestamp
+    start_instant: std::time::Instant,
+    /// Last update timestamp
+    last_update: std::time::Instant,
+    /// Current phase
+    phase: TouchPhase,
+    /// Gesture recognized for this touch
+    recognized_gesture: Option<GestureType>,
+}
+
+/// Main gesture processor maintaining state for all touch points
+pub struct GestureProcessor {
+    /// Active touch trackers
+    touches: [Option<TouchTracker>; MAX_TOUCH_POINTS],
+}
+
+impl GestureProcessor {
+    /// Create a new gesture processor with default thresholds
+    pub fn new() -> Self {
+        Self {
+            touches: Default::default(),
+        }
+    }
+
+    /// Process a raw touch event and return gesture event if recognized
+    /// Returns None if no gesture recognized yet, or if should fall back to raw touch
+    pub fn process_touch_event(
+        &mut self,
+        phase: TouchPhase,
+        id: u64,
+        pos: Point,
+    ) -> Option<GestureEvent> {
+        // STUB: Route to appropriate handler based on phase
+        // TODO: Implement in next phase
+        match phase {
+            TouchPhase::Started => self.handle_touch_started(id as usize, pos),
+            TouchPhase::Moved => self.handle_touch_moved(id as usize, pos),
+            TouchPhase::Ended => self.handle_touch_ended(id as usize, pos),
+            TouchPhase::Cancelled => self.handle_touch_cancelled(id as usize),
+        }
+    }
+
+    /// Handle touch start - initialize tracker
+    fn handle_touch_started(&mut self, id: usize, pos: Point) -> Option<GestureEvent> {
+        // STUB: Initialize touch tracker
+        // TODO: Implement in next phase
+        None
+    }
+
+    /// Handle touch move - update tracker, check for gesture recognition
+    fn handle_touch_moved(&mut self, id: usize, pos: Point) -> Option<GestureEvent> {
+        // STUB: Update position, calculate displacement/velocity
+        // TODO: Implement gesture recognition logic in next phase
+        None
+    }
+
+    /// Handle touch end - finalize gesture
+    fn handle_touch_ended(&mut self, id: usize, pos: Point) -> Option<GestureEvent> {
+        // STUB: Check final gesture state
+        // TODO: Implement final gesture determination in next phase
+        None
+    }
+
+    /// Handle touch cancel - clean up
+    fn handle_touch_cancelled(&mut self, id: usize) -> Option<GestureEvent> {
+        // STUB: Clean up touch tracker
+        // TODO: Implement cleanup in next phase
+        None
+    }
+}
+
+impl Default for GestureProcessor {
+    fn default() -> Self {
+        Self::new()
+    }
+}

+ 33 - 8
bin/app/src/ui/win.rs → bin/app/src/ui/win/mod.rs

@@ -42,6 +42,9 @@ use crate::{android, prop::PropertyRect};
 
 use super::{get_children_ordered, get_ui_object3, get_ui_object_ptr, OnModify};
 
+mod gesture;
+pub use gesture::{GestureEvent, GestureType, GestureProcessor};
+
 macro_rules! i { ($($arg:tt)*) => { info!(target: "ui::window", $($arg)*); } }
 macro_rules! d { ($($arg:tt)*) => { debug!(target: "ui::window", $($arg)*); } }
 macro_rules! t { ($($arg:tt)*) => { trace!(target: "ui::window", $($arg)*); } }
@@ -65,6 +68,8 @@ pub struct Window {
     scale: PropertyFloat32,
     #[cfg(target_os = "android")]
     insets: PropertyRect,
+    /// Gesture processor for recognizing gestures
+    gesture_proc: SyncMutex<GestureProcessor>,
 }
 
 impl Window {
@@ -72,18 +77,12 @@ impl Window {
         node: SceneNodeWeak,
         renderer: Renderer,
         i18n_fish: I18nBabelFish,
-        setting_root: SceneNodePtr,
+        _setting_root: SceneNodePtr,
     ) -> Pimpl {
         let node_ref = &node.upgrade().unwrap();
         let locale = PropertyStr::wrap(node_ref, Role::Internal, "locale", 0).unwrap();
         let screen_size = PropertyDimension::wrap(node_ref, Role::Internal, "screen_size").unwrap();
-        let scale = PropertyFloat32::wrap(
-            &setting_root.lookup_node("/scale").unwrap(),
-            Role::Internal,
-            "value",
-            0,
-        )
-        .unwrap();
+        let scale = PropertyFloat32::wrap(node_ref, Role::Internal, "scale", 0).unwrap();
 
         let self_ = Arc::new(Self {
             node,
@@ -96,6 +95,7 @@ impl Window {
             scale,
             #[cfg(target_os = "android")]
             insets: PropertyRect::wrap(node_ref, Role::Internal, "insets").unwrap(),
+            gesture_proc: SyncMutex::new(GestureProcessor::new()),
         });
 
         Pimpl::Window(self_)
@@ -459,6 +459,21 @@ impl Window {
 
     async fn handle_touch(&self, phase: TouchPhase, id: u64, mut touch_pos: Point) {
         self.local_scale(&mut touch_pos);
+
+        // Process through gesture recognizer
+        let gesture_event = {
+            let mut gesture_proc = self.gesture_proc.lock();
+            gesture_proc.process_touch_event(phase, id, touch_pos)
+        };
+
+        if let Some(gesture_event) = gesture_event {
+            if self.handle_gesture(gesture_event).await {
+                // Gesture was handled, stop propagation
+                return
+            }
+        }
+
+        // Fallback to raw touch event (backwards compat)
         for child in self.get_children() {
             let obj = get_ui_object3(&child);
             if obj.handle_touch(phase, id, touch_pos).await {
@@ -484,6 +499,16 @@ impl Window {
         false
     }
 
+    async fn handle_gesture(&self, gesture: GestureEvent) -> bool {
+        for child in self.get_children() {
+            let obj = get_ui_object3(&child);
+            if obj.handle_gesture(gesture.clone()).await {
+                return true
+            }
+        }
+        false
+    }
+
     #[instrument(target = "ui::win")]
     pub async fn draw(&self, atom: &mut PropertyAtomicGuard) {
         let virt_size = self.screen_size.get() / self.scale.get();