Merge pull request #4279 from Kingtous/feat/plugins
feat: add general ui handler
This commit is contained in:
		
						commit
						092acc49ad
					
				| @ -13,6 +13,7 @@ import 'package:flutter_hbb/desktop/screen/desktop_port_forward_screen.dart'; | ||||
| import 'package:flutter_hbb/desktop/screen/desktop_remote_screen.dart'; | ||||
| import 'package:flutter_hbb/desktop/widgets/refresh_wrapper.dart'; | ||||
| import 'package:flutter_hbb/models/state_model.dart'; | ||||
| import 'package:flutter_hbb/plugin/handlers.dart'; | ||||
| import 'package:flutter_hbb/utils/multi_window_manager.dart'; | ||||
| import 'package:flutter_localizations/flutter_localizations.dart'; | ||||
| import 'package:get/get.dart'; | ||||
| @ -428,4 +429,10 @@ _registerEventHandler() { | ||||
|       reloadAllWindows(); | ||||
|     }); | ||||
|   } | ||||
|   // Register native handlers. | ||||
|   if (isDesktop) { | ||||
|     platformFFI.registerEventHandler('native_ui', 'native_ui', (evt) async { | ||||
|       NativeUiHandler.instance.onEvent(evt); | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										43
									
								
								flutter/lib/plugin/handlers.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								flutter/lib/plugin/handlers.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | ||||
| import 'dart:ffi'; | ||||
| 
 | ||||
| abstract class NativeHandler { | ||||
|   bool onEvent(Map<String, dynamic> evt); | ||||
| } | ||||
| 
 | ||||
| typedef OnSelectPeersCallback = Bool Function(Int returnCode, | ||||
|     Pointer<Void> data, Uint64 dataLength, Pointer<Void> userData); | ||||
| typedef OnSelectPeersCallbackDart = bool Function( | ||||
|     int returnCode, Pointer<Void> data, int dataLength, Pointer<Void> userData); | ||||
| 
 | ||||
| class NativeUiHandler extends NativeHandler { | ||||
|   NativeUiHandler._(); | ||||
| 
 | ||||
|   static NativeUiHandler instance = NativeUiHandler._(); | ||||
| 
 | ||||
|   @override | ||||
|   bool onEvent(Map<String, dynamic> evt) { | ||||
|     final name = evt['name']; | ||||
|     final action = evt['action']; | ||||
|     if (name != "native_ui") { | ||||
|       return false; | ||||
|     } | ||||
|     switch (action) { | ||||
|       case "select_peers": | ||||
|         int cb = evt['cb']; | ||||
|         int userData = evt['user_data'] ?? 0; | ||||
|         final cbFuncNative = Pointer.fromAddress(cb) | ||||
|             .cast<NativeFunction<OnSelectPeersCallback>>(); | ||||
|         final cbFuncDart = cbFuncNative.asFunction<OnSelectPeersCallbackDart>(); | ||||
|         onSelectPeers(cbFuncDart, userData); | ||||
|         break; | ||||
|       default: | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
| 
 | ||||
|   void onSelectPeers(OnSelectPeersCallbackDart cb, int userData) async { | ||||
|     // TODO: design a UI interface to pick peers. | ||||
|     cb(0, Pointer.fromAddress(0), 0, Pointer.fromAddress(userData)); | ||||
|   } | ||||
| } | ||||
| @ -10,12 +10,13 @@ use serde_json::Map; | ||||
| 
 | ||||
| use crate::return_if_not_method; | ||||
| 
 | ||||
| use self::session::PluginNativeSessionHandler; | ||||
| use self::{session::PluginNativeSessionHandler, ui::PluginNativeUIHandler}; | ||||
| 
 | ||||
| use super::cstr_to_string; | ||||
| 
 | ||||
| mod macros; | ||||
| pub mod session; | ||||
| pub mod ui; | ||||
| 
 | ||||
| pub type NR = super::native::NativeReturnValue; | ||||
| pub type PluginNativeHandlerRegistrar = NativeHandlerRegistrar<Box<dyn Callable + Send + Sync>>; | ||||
| @ -33,10 +34,11 @@ pub struct NativeHandlerRegistrar<H> { | ||||
| impl Default for PluginNativeHandlerRegistrar { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             handlers: Arc::new(RwLock::new(vec![Box::new( | ||||
|             handlers: Arc::new(RwLock::new(vec![ | ||||
|                 // Add prebuilt native handlers here.
 | ||||
|                 PluginNativeSessionHandler::default(), | ||||
|             )])), | ||||
|                 Box::new(PluginNativeSessionHandler::default()), | ||||
|                 Box::new(PluginNativeUIHandler::default()), | ||||
|             ])), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
							
								
								
									
										100
									
								
								src/plugin/native_handlers/ui.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/plugin/native_handlers/ui.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,100 @@ | ||||
| use std::{collections::HashMap, ffi::c_void, os::raw::c_int}; | ||||
| 
 | ||||
| use serde_json::json; | ||||
| 
 | ||||
| use crate::{ | ||||
|     define_method_prefix, | ||||
|     flutter::{APP_TYPE_MAIN}, | ||||
| }; | ||||
| 
 | ||||
| use super::PluginNativeHandler; | ||||
| 
 | ||||
| #[derive(Default)] | ||||
| pub struct PluginNativeUIHandler; | ||||
| 
 | ||||
| /// Callback for UI interface.
 | ||||
| ///
 | ||||
| /// [Note]
 | ||||
| /// We will transfer the native callback to u64 and post it to flutter.
 | ||||
| /// The flutter thread will directly call this method.
 | ||||
| ///
 | ||||
| /// an example of `data` is:
 | ||||
| /// ```
 | ||||
| /// {
 | ||||
| ///     "cb": 0x1234567890
 | ||||
| /// }
 | ||||
| /// ```
 | ||||
| /// [Safety]
 | ||||
| /// Please make sure the callback u provided is VALID, or memory or calling issues may occur to cause the program crash!
 | ||||
| pub type OnUIReturnCallback = extern "C" fn(return_code: c_int, data: *const c_void, data_len: u64, user_data: *const c_void); | ||||
| 
 | ||||
| impl PluginNativeHandler for PluginNativeUIHandler { | ||||
|     define_method_prefix!("ui_"); | ||||
| 
 | ||||
|     fn on_message( | ||||
|         &self, | ||||
|         method: &str, | ||||
|         data: &serde_json::Map<String, serde_json::Value>, | ||||
|     ) -> Option<super::NR> { | ||||
|         match method { | ||||
|             "select_peers_async" => { | ||||
|                 if let Some(cb) = data.get("cb") { | ||||
|                     if let Some(cb) = cb.as_u64() { | ||||
|                         let user_data = match data.get("user_data") { | ||||
|                             Some(user_data) => { | ||||
|                                 user_data.as_u64().unwrap_or(0) | ||||
|                             }, | ||||
|                             None => 0, | ||||
|                         }; | ||||
|                         self.select_peers_async(cb, user_data); | ||||
|                         return Some(super::NR { | ||||
|                             return_type: 0, | ||||
|                             data: std::ptr::null(), | ||||
|                         }); | ||||
|                     } | ||||
|                 } | ||||
|                 return Some(super::NR { | ||||
|                     return_type: -1, | ||||
|                     data: "missing cb field message".as_ptr() as _, | ||||
|                 }); | ||||
|             } | ||||
|             _ => {} | ||||
|         } | ||||
|         None | ||||
|     } | ||||
| 
 | ||||
|     fn on_message_raw( | ||||
|         &self, | ||||
|         method: &str, | ||||
|         data: &serde_json::Map<String, serde_json::Value>, | ||||
|         raw: *const std::ffi::c_void, | ||||
|         _raw_len: usize, | ||||
|     ) -> Option<super::NR> { | ||||
|         None | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl PluginNativeUIHandler { | ||||
|     /// Call with method `select_peers_async` and the following json:
 | ||||
|     /// ```json
 | ||||
|     /// {
 | ||||
|     ///     "cb": 0, // The function address
 | ||||
|     ///     "user_data": 0 // An opaque pointer value passed to the callback.
 | ||||
|     /// }
 | ||||
|     /// ```
 | ||||
|     /// 
 | ||||
|     /// [Arguments] 
 | ||||
|     /// @param cb: the function address with type [OnUIReturnCallback].
 | ||||
|     /// @param user_data: the function will be called with this value. 
 | ||||
|     fn select_peers_async(&self, cb: u64, user_data: u64) { | ||||
|         let mut param = HashMap::new(); | ||||
|         param.insert("name", json!("native_ui")); | ||||
|         param.insert("action", json!("select_peers")); | ||||
|         param.insert("cb", json!(cb)); | ||||
|         param.insert("user_data", json!(user_data)); | ||||
|         crate::flutter::push_global_event( | ||||
|             APP_TYPE_MAIN, | ||||
|             serde_json::to_string(¶m).unwrap_or("".to_string()), | ||||
|         ); | ||||
|     } | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user