Compare commits
	
		
			No commits in common. "99ab6695a95aaa6a6d3d53c0ab98551649d5c219" and "9ac74625236a0df15c05689c588164415eb93c71" have entirely different histories.
		
	
	
		
			99ab6695a9
			...
			9ac7462523
		
	
		|  | @ -1,102 +1,20 @@ | ||||||
| class JavaScriptString { | class JavaScriptString { | ||||||
|   /// 点击监听 |   /// 点击监听 | ||||||
|   static String clickEventJSString = |   static String clickEventkJSString = | ||||||
|       '''document.addEventListener('click', function(event) { |       '''document.addEventListener('click', function(event) { | ||||||
|   var x = event.clientX; |   var x = event.clientX; | ||||||
|   var y = event.clientY; |   var y = event.clientY; | ||||||
| 
 | 
 | ||||||
|   console.log('点击坐标:x=' + x + ', y=' + y); |   console.log('点击坐标:x=' + x + ', y=' + y); | ||||||
|   window.flutter_inappwebview.callHandler('click', x, y); |   window.flutter_inappwebview.callHandler('Click', x, y); | ||||||
|    |    | ||||||
| });'''; | });'''; | ||||||
| 
 | 
 | ||||||
|   /// 触摸监听 |  | ||||||
|   static String touchendEventJSString = |  | ||||||
|       '''document.addEventListener('touchend', function(event) { |  | ||||||
|   var x = event.changedTouches[0].clientX; |  | ||||||
|   var y = event.changedTouches[0].clientY; |  | ||||||
|    |  | ||||||
|   // 获取目标元素 |  | ||||||
|     var target = event.target; |  | ||||||
|      |  | ||||||
|     // 获取目标元素的class和id |  | ||||||
|     var targetClass = target.className; |  | ||||||
|     var targetId = target.id; |  | ||||||
|      |  | ||||||
|     console.log('Class: ' + targetClass); |  | ||||||
|     console.log('Id: ' + targetId); |  | ||||||
| 
 |  | ||||||
|   console.log('触摸坐标:x=' + x + ', y=' + y); |  | ||||||
|   window.flutter_inappwebview.callHandler('touchend', x, y); |  | ||||||
|    |  | ||||||
| });'''; |  | ||||||
| 
 |  | ||||||
|   /// 退出登录 |  | ||||||
|   static String loginOutJsString = ''' |  | ||||||
|         \$.ajax({ |  | ||||||
|             type: "GET", |  | ||||||
|             url: "/api/logout.do", |  | ||||||
|             success: function(t) { |  | ||||||
|                 "index.html" != location.pathname ? window.location.href = "index.html" : location.reload() |  | ||||||
|             }, |  | ||||||
|             error: function(t) { |  | ||||||
|                 var e = \$.parseJSON(t.responseText + ""); |  | ||||||
|                 alert(e.msg, 2) |  | ||||||
|             } |  | ||||||
|         }) |  | ||||||
|     '''; |  | ||||||
| 
 |  | ||||||
|   /// 模拟点击 |   /// 模拟点击 | ||||||
|   static String clickJSString(int x, int y) { |   static String clickJSString(int x, int y) { | ||||||
|     return 'document.elementFromPoint($x, $y).click();'; |     return 'document.elementFromPoint($x, $y).click();'; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /// 模拟触摸 |  | ||||||
|   static String touchendJsString(int x, int y) { |  | ||||||
|     return ''' |  | ||||||
|      |  | ||||||
|     '''; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 模拟触摸 |  | ||||||
|   static String getClassTouchendJsString(int x, int y) { |  | ||||||
|     return ''' |  | ||||||
|     try{ |  | ||||||
|     // 获取鼠标点击位置的坐标 |  | ||||||
| var x = $x; |  | ||||||
| var y = $y; |  | ||||||
| 
 |  | ||||||
| // 创建一个touchstart事件 |  | ||||||
| var touchstartEvent = new TouchEvent('touchstart', { |  | ||||||
|   bubbles: true, |  | ||||||
|   cancelable: true, |  | ||||||
|   view: window, |  | ||||||
|   changedTouches: [new Touch({ identifier: Date.now(), target: document.body, clientX: x, clientY: y })], |  | ||||||
|   targetTouches: [new Touch({ identifier: Date.now(), target: document.body, clientX: x, clientY: y })] |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| // touchstartEvent |  | ||||||
| document.body.dispatchEvent(touchstartEvent); |  | ||||||
| 
 |  | ||||||
| // 创建一个touchend事件 |  | ||||||
| var touchendEvent = new TouchEvent('touchend', { |  | ||||||
|   bubbles: true, |  | ||||||
|   cancelable: true, |  | ||||||
|   view: window, |  | ||||||
|   changedTouches: [new Touch({ identifier: Date.now(), target: document.body, clientX: x, clientY: y })], |  | ||||||
|   targetTouches: [new Touch({ identifier: Date.now(), target: document.body, clientX: x, clientY: y })] |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| // 触发touchend事件 |  | ||||||
| document.body.dispatchEvent(touchendEvent); |  | ||||||
| 
 |  | ||||||
| } catch (t) { |  | ||||||
|                 console.log('模拟触摸错误 -- ' + t); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|     '''; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 输入 |   /// 输入 | ||||||
|   static String inputJsString(int value) { |   static String inputJsString(int value) { | ||||||
|     return ''' |     return ''' | ||||||
|  | @ -106,7 +24,7 @@ var inputEvent = new Event('input', { | ||||||
|   cancelable: true, |   cancelable: true, | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| var inputElement = document.querySelector(".input"); | var inputElement = document.querySelector(".bet-money"); | ||||||
| 
 | 
 | ||||||
| inputElement.value = "$value"; | inputElement.value = "$value"; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,96 +0,0 @@ | ||||||
| 
 |  | ||||||
| import 'package:bitsdojo_window/bitsdojo_window.dart'; |  | ||||||
| import 'package:common/utils/platform_utils.dart'; |  | ||||||
| import 'package:common/utils/toast_utils.dart'; |  | ||||||
| import 'package:flutter/material.dart'; |  | ||||||
| import 'package:web_synchronization_tool/login/login_socket_utils.dart'; |  | ||||||
| import 'package:web_synchronization_tool/login/widget/account_number_login_widget.dart'; |  | ||||||
| import 'package:web_synchronization_tool/windows/windows_main_page.dart'; |  | ||||||
| import 'package:window_manager/window_manager.dart'; |  | ||||||
| 
 |  | ||||||
| import '../windows/socket_tool.dart'; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class LoginPage extends StatefulWidget { |  | ||||||
|   const LoginPage({super.key}); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   State<LoginPage> createState() => _LoginPageState(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class _LoginPageState extends State<LoginPage> { |  | ||||||
|   @override |  | ||||||
|   void initState() { |  | ||||||
|     super.initState(); |  | ||||||
| 
 |  | ||||||
|     initWindow(); |  | ||||||
| 
 |  | ||||||
|     LoginSocketUtils.getInstance().connect(); |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   initWindow(){ |  | ||||||
|     //允许调整窗口大小 |  | ||||||
|     windowManager.setResizable(false); |  | ||||||
| 
 |  | ||||||
|     const double width = 800; |  | ||||||
|     const double height = 600; |  | ||||||
|     //设置最小大小 |  | ||||||
|     const windowSize = Size(width, height); |  | ||||||
|     windowManager.setSize(windowSize); |  | ||||||
|     appWindow.minSize = windowSize; |  | ||||||
|     windowManager.center(); |  | ||||||
|     windowManager.focus(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
| 
 |  | ||||||
|     return Scaffold( |  | ||||||
|       backgroundColor: const Color(0xff272b38), |  | ||||||
|       body: Padding( |  | ||||||
|         padding: const EdgeInsets.all( 140 ), |  | ||||||
|         child: Row( |  | ||||||
|           mainAxisAlignment: MainAxisAlignment.center, |  | ||||||
|           children: [ |  | ||||||
|               SizedBox( |  | ||||||
|                 width: PlatformUtils.isPhoneWeb(context) ? MediaQuery.of(context).size.width - 40 : 400, |  | ||||||
|                 child: AccountNumberLoginWidget( |  | ||||||
|                   loginTap: Login, |  | ||||||
|                 ), |  | ||||||
|               ), |  | ||||||
|           ], |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 登录 |  | ||||||
|   Login(String account, String password) { |  | ||||||
| 
 |  | ||||||
|     ToastUtils.showLoading(); |  | ||||||
| 
 |  | ||||||
|     /// 发送登录消息 |  | ||||||
|     LoginSocketUtils.getInstance().login(account, password,(data){ |  | ||||||
|       ToastUtils.dismissLoading(); |  | ||||||
| 
 |  | ||||||
|       if(data['err'] == 1){ |  | ||||||
|         ToastUtils.showToast('登录失败!请检查账号和密码'); |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       /// 登录服务心跳 |  | ||||||
|       LoginSocketUtils.getInstance().heartbeat(); |  | ||||||
|       /// 同步socket |  | ||||||
|       SocketUtils.getInstance().connect(); |  | ||||||
|       SocketUtils.getInstance().heartbeat(); |  | ||||||
| 
 |  | ||||||
|       Navigator.pushAndRemoveUntil( |  | ||||||
|           context, |  | ||||||
|           MaterialPageRoute(builder: (_) => const WindowsPage()), |  | ||||||
|               (route) => false); |  | ||||||
| 
 |  | ||||||
|     }); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,168 +0,0 @@ | ||||||
| 
 |  | ||||||
| import 'dart:async'; |  | ||||||
| import 'dart:convert'; |  | ||||||
| import 'dart:ffi'; |  | ||||||
| import 'dart:io'; |  | ||||||
| import 'dart:typed_data'; |  | ||||||
| 
 |  | ||||||
| import 'package:common/utils/toast_utils.dart'; |  | ||||||
| import 'package:web_synchronization_tool/windows/little_extension.dart'; |  | ||||||
| import 'package:web_synchronization_tool/windows/socket_tool.dart'; |  | ||||||
| 
 |  | ||||||
| import '../windows/code.dart'; |  | ||||||
| 
 |  | ||||||
| class LoginSocketUtils extends LoginSocket { |  | ||||||
| 
 |  | ||||||
|   // 私有构造函数 |  | ||||||
|   LoginSocketUtils._(); |  | ||||||
|   // 私有静态变量,保存类的唯一实例 |  | ||||||
|   static LoginSocketUtils? _instance; |  | ||||||
| 
 |  | ||||||
|   // 公开的静态方法,返回类的唯一实例 |  | ||||||
|   static LoginSocketUtils getInstance() { |  | ||||||
|     _instance ??= LoginSocketUtils._(); |  | ||||||
|     return _instance!; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| typedef loginBlockFun = Function(Map); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class LoginSocket{ |  | ||||||
| 
 |  | ||||||
|   String url = '110.42.251.214'; |  | ||||||
|   static int port = 37785; |  | ||||||
| 
 |  | ||||||
|   String uuid = ''; |  | ||||||
| 
 |  | ||||||
|   Socket? socket; |  | ||||||
| 
 |  | ||||||
|   int heartTime = 0; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   connect() async { |  | ||||||
|     socket?.close(); |  | ||||||
|     socket = await Socket.connect(url, port, timeout: const Duration(seconds: 30)); |  | ||||||
|     heartTime = DateTime.now().millisecondsSinceEpoch; |  | ||||||
| 
 |  | ||||||
|     socket?.listen((event) { |  | ||||||
| 
 |  | ||||||
|       Map data = dataCute(event); |  | ||||||
| 
 |  | ||||||
|       // 登录结果 |  | ||||||
|       if (data['op'] == 2){ |  | ||||||
|         loginBlock(data); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       // 服务器心跳 |  | ||||||
|       if (data['op'] == 4){ |  | ||||||
|         try{ |  | ||||||
| 
 |  | ||||||
|           // 更新上次心跳时间 |  | ||||||
|           heartTime = DateTime.now().millisecondsSinceEpoch; |  | ||||||
| 
 |  | ||||||
|           // 心跳回报时间是否超时 |  | ||||||
|           int time = data['time']; |  | ||||||
|           time = DateTime.now().millisecondsSinceEpoch - time; |  | ||||||
|           if(time> (3 * 60 * 1000) ){ // 时间戳 > 3分钟 |  | ||||||
|             socketError(); |  | ||||||
|           } |  | ||||||
|         }catch(e){ |  | ||||||
|           socketError(); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|     },onDone: (){ |  | ||||||
|     },onError: (error){ |  | ||||||
|       // 连接断开 |  | ||||||
|       socketError(); |  | ||||||
|       socket?.destroy(); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   socketError(){ |  | ||||||
|     /// 任何错误都显示这个 |  | ||||||
|     ToastUtils.showLoading(msg: '重连中'); |  | ||||||
|     /// 关闭同步 socket |  | ||||||
|     SocketUtils.getInstance().socket?.close(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   late loginBlockFun loginBlock; |  | ||||||
| 
 |  | ||||||
|   // 登录 |  | ||||||
|   login(String account,String passwoord,loginBlockFun blockFun){ |  | ||||||
| 
 |  | ||||||
|     loginBlock = blockFun; |  | ||||||
| 
 |  | ||||||
|     Map map = { |  | ||||||
|       'op':1, |  | ||||||
|       'account':account, |  | ||||||
|       'password':passwoord, |  | ||||||
|       'uuid':uuid |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     final dd = dataMake(map); |  | ||||||
|     socket?.add(dd); |  | ||||||
|     socket?.flush(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 心跳 |  | ||||||
|   heartbeat(){ |  | ||||||
| 
 |  | ||||||
|     Timer(const Duration(seconds: 20), () async { |  | ||||||
| 
 |  | ||||||
|       final time = DateTime.now().millisecondsSinceEpoch - heartTime; |  | ||||||
|       if(time > (3 * 60 * 1000) ){ // 时间戳 > 3分钟 |  | ||||||
|         socketError(); |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       heartbeat(); |  | ||||||
| 
 |  | ||||||
|       Map map =   { |  | ||||||
|         "op": 3, |  | ||||||
|       }; |  | ||||||
| 
 |  | ||||||
|       socket?.add(dataMake(map)); |  | ||||||
|       socket?.flush(); |  | ||||||
| 
 |  | ||||||
|     }); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   /// 发送数据的处理 |  | ||||||
|   List<int> dataMake(Map map){ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     // 将Map对象转换为JSON字符串 |  | ||||||
|     String json = jsonEncode(map); |  | ||||||
|     // 加密 |  | ||||||
|     String ps = makecode(json, skey); |  | ||||||
| 
 |  | ||||||
|     List<int> bytes = ps.codeUnits; // 将字符串转换为字节数组 |  | ||||||
| 
 |  | ||||||
|     return bytes.toLittle(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 接收数据处理 |  | ||||||
|   Map dataCute(Uint8List data){ |  | ||||||
| 
 |  | ||||||
|     if (data.length <= 4) return {}; |  | ||||||
| 
 |  | ||||||
|     Uint8List pData = data.sublist(4,data.length); |  | ||||||
| 
 |  | ||||||
|     String str = cutecode(pData); |  | ||||||
| 
 |  | ||||||
|     Map map = json.decode(str); |  | ||||||
| 
 |  | ||||||
|     return map; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
|  | @ -1,106 +0,0 @@ | ||||||
| 
 |  | ||||||
| import 'package:common/utils/toast_utils.dart'; |  | ||||||
| import 'login_text_field_widget.dart'; |  | ||||||
| import 'package:flutter/material.dart'; |  | ||||||
| import 'package:common/utils/widget_utils.dart'; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class LoginController{ |  | ||||||
| 
 |  | ||||||
|   set name(String newText) { |  | ||||||
|     if (nameChang != null){ |  | ||||||
|       nameChang!(newText); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   Function(String name)? nameChang; |  | ||||||
| 
 |  | ||||||
|   set password(String newText) { |  | ||||||
|     if (passwordChang != null){ |  | ||||||
|       passwordChang!(newText); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   Function(String password)? passwordChang; |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class AccountNumberLoginWidget extends StatefulWidget { |  | ||||||
|   const AccountNumberLoginWidget({Key? key, required this.loginTap, this.controller }) : super(key: key); |  | ||||||
| 
 |  | ||||||
|   final LoginController? controller; |  | ||||||
|   final Function(String,String) loginTap; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   State<AccountNumberLoginWidget> createState() => |  | ||||||
|       _AccountNumberLoginWidgetState(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class _AccountNumberLoginWidgetState extends State<AccountNumberLoginWidget> { |  | ||||||
|   TextEditingController phoneController = TextEditingController(); |  | ||||||
|   TextEditingController passwordController = TextEditingController(); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   _login() { |  | ||||||
| 
 |  | ||||||
|     if (phoneController.text.isEmpty || passwordController.text.isEmpty){ |  | ||||||
|       ToastUtils.showToast('请输入账号和密码'); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     widget.loginTap(phoneController.text,passwordController.text); |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   void initState()  { |  | ||||||
|     super.initState(); |  | ||||||
| 
 |  | ||||||
|     widget.controller?.nameChang = (name){ |  | ||||||
|       phoneController.text = name; |  | ||||||
|     }; |  | ||||||
|     widget.controller?.passwordChang = (password){ |  | ||||||
|       passwordController.text = password; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|    |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
|     return Column( |  | ||||||
|       mainAxisAlignment: MainAxisAlignment.center, |  | ||||||
|       crossAxisAlignment: CrossAxisAlignment.stretch, |  | ||||||
|       children: [ |  | ||||||
|         LoginPhoneTextField(controller: phoneController), |  | ||||||
|         WidgetUtils.spacer(height: 15), |  | ||||||
|         LoginPasswordTextField(controller: passwordController,onSubmitted: (_){ |  | ||||||
|           _login(); |  | ||||||
|         },), |  | ||||||
|         WidgetUtils.spacer(height: 15), |  | ||||||
|         TextButton( |  | ||||||
|           onPressed: _login, |  | ||||||
|           style: TextButton.styleFrom(padding: EdgeInsets.zero), |  | ||||||
|           child: Container( |  | ||||||
|             height: 40, |  | ||||||
|             alignment: Alignment.center, |  | ||||||
|             decoration: const BoxDecoration( |  | ||||||
|                 color: Colors.blue, |  | ||||||
|                 borderRadius: BorderRadius.all(Radius.circular(5))), |  | ||||||
|             child: const Text( |  | ||||||
|               '登录', |  | ||||||
|               style: TextStyle( |  | ||||||
|                 fontSize: 16, |  | ||||||
|                 color: Colors.white, |  | ||||||
|               ), |  | ||||||
|             ), |  | ||||||
|           ), |  | ||||||
|         ), |  | ||||||
|       ], |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  | @ -1,210 +0,0 @@ | ||||||
| 
 |  | ||||||
| import 'package:flutter/material.dart'; |  | ||||||
| import 'package:flutter/services.dart'; |  | ||||||
| 
 |  | ||||||
| class LoginPhoneTextField extends StatelessWidget { |  | ||||||
|   const LoginPhoneTextField( |  | ||||||
|       {Key? key, required this.controller, this.helperText, this.rightWidget}) |  | ||||||
|       : super(key: key); |  | ||||||
| 
 |  | ||||||
|   final TextEditingController controller; |  | ||||||
|   final String? helperText; |  | ||||||
|   final Widget? rightWidget; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
|     Widget textField = SizedBox( |  | ||||||
|       height: 40, |  | ||||||
|       child: TextFieldBase( |  | ||||||
|         keyboardType: TextInputType.number, |  | ||||||
|         leftWidget: const Padding( |  | ||||||
|           padding: EdgeInsets.only(left: 10), |  | ||||||
|           child: Icon( |  | ||||||
|             Icons.perm_contact_calendar_sharp, |  | ||||||
|             color: Colors.grey, |  | ||||||
|             size: 20, |  | ||||||
|           ), |  | ||||||
|         ), |  | ||||||
|         rightWidget: rightWidget, |  | ||||||
|         hintText: '请输入账号', |  | ||||||
|         style: const TextStyle(color: Colors.white), |  | ||||||
|         controller: controller, |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     return helperText == null |  | ||||||
|         ? textField |  | ||||||
|         : Column( |  | ||||||
|             crossAxisAlignment: CrossAxisAlignment.start, |  | ||||||
|             children: [ |  | ||||||
|               textField, |  | ||||||
|               Padding( |  | ||||||
|                 padding: const EdgeInsets.only(top: 5), |  | ||||||
|                 child: Text( |  | ||||||
|                   helperText!, |  | ||||||
|                   style: const TextStyle(fontSize: 12, color: Colors.grey), |  | ||||||
|                 ), |  | ||||||
|               ) |  | ||||||
|             ], |  | ||||||
|           ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class LoginPasswordTextField extends StatefulWidget { |  | ||||||
|   const LoginPasswordTextField( |  | ||||||
|       {Key? key, |  | ||||||
|       required this.controller, |  | ||||||
|       this.hintText = '请输入密码', |  | ||||||
|       this.onSubmitted}) |  | ||||||
|       : super(key: key); |  | ||||||
| 
 |  | ||||||
|   final TextEditingController controller; |  | ||||||
|   final String hintText; |  | ||||||
|   final ValueChanged<String>? onSubmitted; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   State<LoginPasswordTextField> createState() => _LoginPasswordTextFieldState(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class _LoginPasswordTextFieldState extends State<LoginPasswordTextField> { |  | ||||||
|   bool hideCancel = true; |  | ||||||
|   bool obsureText = true; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
|     Widget cancel = Offstage( |  | ||||||
|       offstage: hideCancel, |  | ||||||
|       child: TextButton( |  | ||||||
|         style: ButtonStyle( |  | ||||||
|           overlayColor: MaterialStateProperty.all(Colors.transparent), |  | ||||||
|         ), |  | ||||||
|         onPressed: () { |  | ||||||
|           setState(() { |  | ||||||
|             obsureText = !obsureText; |  | ||||||
|           }); |  | ||||||
|         }, |  | ||||||
|         child: Icon( |  | ||||||
|           Icons.remove_red_eye_rounded, |  | ||||||
|           color: Colors.grey, |  | ||||||
|           size: 20, |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     widget.controller.addListener(() { |  | ||||||
|       setState(() { |  | ||||||
|         hideCancel = !widget.controller.text.isNotEmpty; |  | ||||||
|       }); |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|     return SizedBox( |  | ||||||
|       height: 40, |  | ||||||
|       child: TextFieldBase( |  | ||||||
|         hintText: widget.hintText, |  | ||||||
|         controller: widget.controller, |  | ||||||
|         obsureText: obsureText, |  | ||||||
|         onSubmitted: widget.onSubmitted, |  | ||||||
|         leftWidget: const Padding( |  | ||||||
|           padding: EdgeInsets.only(left: 10), |  | ||||||
|           child: Icon( |  | ||||||
|             Icons.lock_sharp, |  | ||||||
|             color: Colors.grey, |  | ||||||
|             size: 20, |  | ||||||
|           ), |  | ||||||
|         ), |  | ||||||
|         style: const TextStyle(color: Colors.white), |  | ||||||
|         rightWidget: cancel, |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class TextFieldBase extends StatefulWidget { |  | ||||||
|   const TextFieldBase( |  | ||||||
|       {Key? key, |  | ||||||
|       this.leftWidget, |  | ||||||
|       this.rightWidget, |  | ||||||
|       this.hintText = '', |  | ||||||
|       required this.controller, |  | ||||||
|       this.obsureText = false, |  | ||||||
|       this.keyboardType, |  | ||||||
|       this.textAlign = TextAlign.start, |  | ||||||
|       this.onChanged, |  | ||||||
|       this.onSubmitted, |  | ||||||
|       this.inputFormatters, |  | ||||||
|       this.focusNode, |  | ||||||
|       this.decoration, |  | ||||||
|       this.style, |  | ||||||
|       this.noFocusSubmitted = false}) |  | ||||||
|       : super(key: key); |  | ||||||
| 
 |  | ||||||
|   final TextEditingController controller; |  | ||||||
|   final FocusNode? focusNode; |  | ||||||
|   final Widget? leftWidget; |  | ||||||
|   final Widget? rightWidget; |  | ||||||
|   final InputDecoration? decoration; |  | ||||||
|   final TextStyle? style; |  | ||||||
|   final TextInputType? keyboardType; |  | ||||||
|   final String hintText; |  | ||||||
|   /// 暗文 |  | ||||||
|   final bool obsureText; |  | ||||||
|   final TextAlign textAlign; |  | ||||||
|   final List<TextInputFormatter>? inputFormatters; |  | ||||||
|   /// 失去焦点是否回调 |  | ||||||
|   final bool noFocusSubmitted; |  | ||||||
|   final ValueChanged<String>? onChanged; |  | ||||||
|   final ValueChanged<String>? onSubmitted; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   State<TextFieldBase> createState() => _TextFieldBaseState(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class _TextFieldBaseState extends State<TextFieldBase> { |  | ||||||
|   late FocusNode focusNode; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   void initState() { |  | ||||||
|     super.initState(); |  | ||||||
| 
 |  | ||||||
|     focusNode = widget.focusNode ?? FocusNode(); |  | ||||||
| 
 |  | ||||||
|     if (widget.onSubmitted != null && widget.noFocusSubmitted){ |  | ||||||
|       focusNode.addListener(() { |  | ||||||
|         if (focusNode.hasFocus == false){ |  | ||||||
|           widget.onSubmitted!(widget.controller.text); |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
|     final decoration = widget.decoration ?? |  | ||||||
|         InputDecoration( |  | ||||||
|           prefixIcon: widget.leftWidget, |  | ||||||
|           prefixIconConstraints: const BoxConstraints(minWidth: 4), |  | ||||||
|           suffixIcon: widget.rightWidget, |  | ||||||
|           hintText: widget.hintText, |  | ||||||
|           hintStyle: const TextStyle(color: Colors.grey), |  | ||||||
|           border: MaterialStateOutlineInputBorder.resolveWith((states) => |  | ||||||
|               const OutlineInputBorder( |  | ||||||
|                   borderSide: BorderSide(color: Colors.grey))), |  | ||||||
|           contentPadding: |  | ||||||
|           const EdgeInsets.only(left: 0, top: 0, bottom: 0, right: 15), |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|     return TextField( |  | ||||||
|       focusNode: focusNode, |  | ||||||
|       controller: widget.controller, |  | ||||||
|       inputFormatters: widget.inputFormatters, |  | ||||||
|       style: widget.style ?? const TextStyle(fontSize: 14), |  | ||||||
|       keyboardType: widget.keyboardType, |  | ||||||
|       obscureText: widget.obsureText, |  | ||||||
|       textAlign: widget.textAlign, |  | ||||||
|       cursorColor: Colors.blue, |  | ||||||
|       onChanged: widget.onChanged, |  | ||||||
|       onSubmitted: widget.onSubmitted, |  | ||||||
|       decoration: decoration, |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  | @ -1,53 +1,14 @@ | ||||||
| 
 |  | ||||||
| import 'package:common/utils/toast_utils.dart'; |  | ||||||
| import 'package:device_info_plus/device_info_plus.dart'; |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:web_synchronization_tool/login/login_page.dart'; | import 'package:web_synchronization_tool/main_page.dart'; | ||||||
| import 'package:web_synchronization_tool/login/login_socket_utils.dart'; |  | ||||||
| import 'package:window_manager/window_manager.dart'; |  | ||||||
| 
 |  | ||||||
| void main() async { |  | ||||||
|   WidgetsFlutterBinding.ensureInitialized(); |  | ||||||
|   await windowManager.ensureInitialized(); |  | ||||||
| 
 |  | ||||||
|   WindowOptions windowOptions = const WindowOptions( |  | ||||||
|       center: true, backgroundColor: Colors.white,// fullScreen: true,//, title: '赢佳' |  | ||||||
|       // skipTaskbar: true, //跳过任务栏,任务栏无显示 |  | ||||||
|       // titleBarStyle: TitleBarStyle.hidden, //隐藏顶部标题栏 |  | ||||||
|       ); |  | ||||||
|   windowManager.waitUntilReadyToShow(windowOptions, () async { |  | ||||||
|     await windowManager.show(); |  | ||||||
|     await windowManager.focus(); |  | ||||||
|   }); |  | ||||||
| 
 | 
 | ||||||
|  | void main() { | ||||||
|   runApp(const MyApp()); |   runApp(const MyApp()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class MyApp extends StatefulWidget { | class MyApp extends StatelessWidget { | ||||||
|   const MyApp({super.key}); |   const MyApp({super.key}); | ||||||
| 
 | 
 | ||||||
|   @override |   // This widget is the root of your application. | ||||||
|   State<MyApp> createState() => _MyAppState(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class _MyAppState extends State<MyApp> { |  | ||||||
|   @override |  | ||||||
|   void initState() { |  | ||||||
|     super.initState(); |  | ||||||
| 
 |  | ||||||
|     info(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   info() async { |  | ||||||
|     final deviceInfo = await DeviceInfoPlugin().deviceInfo; |  | ||||||
|     String uuid = deviceInfo.data['deviceId']; |  | ||||||
|     uuid = uuid.replaceAll('{', ''); |  | ||||||
|     uuid = uuid.replaceAll('}', ''); |  | ||||||
|     LoginSocketUtils.getInstance().uuid = uuid; |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return MaterialApp( |     return MaterialApp( | ||||||
|  | @ -56,10 +17,7 @@ class _MyAppState extends State<MyApp> { | ||||||
|         colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), |         colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), | ||||||
|         useMaterial3: true, |         useMaterial3: true, | ||||||
|       ), |       ), | ||||||
|       // home: const MainPage(), |       home: const MainPage(), | ||||||
|       home: const LoginPage(), |  | ||||||
|       navigatorObservers: [FlutterSmartDialog.observer], |  | ||||||
|       builder: FlutterSmartDialog.init(), |  | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,145 +1,116 @@ | ||||||
| // | import 'package:flutter/material.dart'; | ||||||
| // import 'package:flutter/material.dart'; | import 'package:flutter_inappwebview/flutter_inappwebview.dart'; | ||||||
| // import 'package:flutter_inappwebview/flutter_inappwebview.dart'; | import 'package:web_synchronization_tool/web_widget.dart'; | ||||||
| // import 'package:web_synchronization_tool/web_widget.dart'; | 
 | ||||||
| // | import 'JavaScriptString.dart'; | ||||||
| // import 'JavaScriptString.dart'; | 
 | ||||||
| // | class MainPage extends StatefulWidget { | ||||||
| // class MainPage extends StatefulWidget { |   const MainPage({super.key}); | ||||||
| //   const MainPage({super.key}); | 
 | ||||||
| // |   @override | ||||||
| //   @override |   State<MainPage> createState() => _MainPageState(); | ||||||
| //   State<MainPage> createState() => _MainPageState(); | } | ||||||
| // } | 
 | ||||||
| // | class _MainPageState extends State<MainPage> { | ||||||
| // class _MainPageState extends State<MainPage> { | 
 | ||||||
| // |   late InAppWebViewController mainController; | ||||||
| //   late InAppWebViewController mainController; |   late InAppWebViewController controller; | ||||||
| //   late InAppWebViewController controller; | 
 | ||||||
| // |   @override | ||||||
| //   bool asyncState = false; |   void initState() { | ||||||
| // |     super.initState(); | ||||||
| //   @override | 
 | ||||||
| //   void initState() { | 
 | ||||||
| //     super.initState(); |   } | ||||||
| // | 
 | ||||||
| //   } |   /// 注入点击监听 | ||||||
| // |   addClickEventJS(){ | ||||||
| //   @override | 
 | ||||||
| //   void dispose() { |     final clickJsUS = UserScript(groupName: 'click',source: JavaScriptString.clickEventkJSString, injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START); | ||||||
| //     super.dispose(); | 
 | ||||||
| // |     mainController.addUserScript(userScript: clickJsUS); | ||||||
| //     WebStorageManager.instance().deleteAllData(); | 
 | ||||||
| //   } |     mainController.addJavaScriptHandler(handlerName: 'Click', callback: (args){ | ||||||
| // |       controller.evaluateJavascript(source: JavaScriptString.clickJSString(args.first, args.last) ); | ||||||
| //   /// 注入触摸监听 |     }); | ||||||
| //   addTouchendEventJS(){ | 
 | ||||||
| // |   } | ||||||
| //     final clickJsUS = UserScript(groupName: 'touchend',source: JavaScriptString.touchendEventJSString, injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START); | 
 | ||||||
| //     mainController.addUserScript(userScript: clickJsUS); |   @override | ||||||
| // |   Widget build(BuildContext context) { | ||||||
| //     mainController.addJavaScriptHandler(handlerName: 'touchend', callback: (args){ |     return Scaffold( | ||||||
| //       if (asyncState){ |       body: Column( | ||||||
| //         int x = double.parse(args.first.toString()).toInt(); |         children: [ | ||||||
| //         int y = double.parse(args.last.toString()).toInt(); |           Container( | ||||||
| //         controller.evaluateJavascript(source: JavaScriptString.clickJSString(x, y) ); |             height: 50, | ||||||
| //         // controller.evaluateJavascript(source: JavaScriptString.touchendJsString(x, y) ); |             color: Colors.white, | ||||||
| //         // controller.evaluateJavascript(source: JavaScriptString.getClassTouchendJsString(x, y) ); |             padding: const EdgeInsets.symmetric(horizontal: 50), | ||||||
| //       } |             child: Row( | ||||||
| //     }); |               children: [ | ||||||
| // |                 TextButton( | ||||||
| //   } |                     onPressed: () { | ||||||
| // |                       controller.evaluateJavascript(source: JavaScriptString.clickJSString(600, 280) ); | ||||||
| //   @override |                     }, | ||||||
| //   Widget build(BuildContext context) { |                     child: const Text('模拟点击测试')), | ||||||
| //     return Scaffold( |                 TextButton( | ||||||
| //       body: Column( |                     onPressed: () { | ||||||
| //         crossAxisAlignment: CrossAxisAlignment.stretch, |                       mainController.evaluateJavascript(source: JavaScriptString.inputJsString(45) ); | ||||||
| //         children: [ |                       controller.evaluateJavascript(source: JavaScriptString.inputJsString(45) ); | ||||||
| //           Container( |                     }, | ||||||
| //             height: 50, |                     child: const Text('模拟输入测试')), | ||||||
| //             color: Colors.white, |                 const SizedBox( | ||||||
| //             padding: const EdgeInsets.symmetric(horizontal: 50), |                   width: 50, | ||||||
| //             child: Row( |                   child: TextField( | ||||||
| //               children: [ |                     keyboardType: TextInputType.number, | ||||||
| //                 TextButton( |                     decoration: InputDecoration(prefixText: '网页数量'), | ||||||
| //                     onPressed: () { |                   ), | ||||||
| //                       controller.evaluateJavascript(source: JavaScriptString.clickJSString(50, 100) ); |                 ) | ||||||
| //                     }, |               ], | ||||||
| //                     child: const Text('模拟点击测试')), |             ), | ||||||
| //                 TextButton( |           ), | ||||||
| //                     onPressed: () { |           Expanded(child: pageViewWidget()), | ||||||
| //                       mainController.evaluateJavascript(source: JavaScriptString.inputJsString(45) ); |         ], | ||||||
| //                       controller.evaluateJavascript(source: JavaScriptString.inputJsString(45) ); |       ), | ||||||
| //                     }, |     ); | ||||||
| //                     child: const Text('模拟输入测试')), |   } | ||||||
| //                 Row( | 
 | ||||||
| //                   children: [ |   Widget pageViewWidget() { | ||||||
| //                     const Text('同步'), |     return PageView( | ||||||
| //                     Switch(value: asyncState, onChanged: (value){ |       children: <Widget>[ | ||||||
| //                       setState(() { |         KeepAlivePage( | ||||||
| //                         asyncState = value; |           child: WebWidget(controlerCallBack: (_mainController) { | ||||||
| //                       }); |             mainController = _mainController; | ||||||
| //                     }) |            | ||||||
| //                   ], |             addClickEventJS(); | ||||||
| //                 ) |           }), | ||||||
| //               ], |         ), | ||||||
| //             ), |         KeepAlivePage( | ||||||
| //           ), |           child: WebWidget(controlerCallBack: (_controller) { | ||||||
| //           Expanded(child: pageViewWidget()), |             controller = _controller; | ||||||
| //         ], |           }), | ||||||
| //       ), |         ) | ||||||
| //     ); |       ], | ||||||
| //   } |     ); | ||||||
| // |   } | ||||||
| //   Widget pageViewWidget() { | 
 | ||||||
| //     return Row( | } | ||||||
| //       children: <Widget>[ | 
 | ||||||
| //         Expanded( | class KeepAlivePage extends StatefulWidget { | ||||||
| //           child: Container( |   final Widget child; | ||||||
| //             color: Colors.yellow, | 
 | ||||||
| //             child: KeepAlivePage( |   KeepAlivePage({super.key , required this.child}); | ||||||
| //               child: WebWidget(controlerCallBack: (_mainController) { | 
 | ||||||
| //                 mainController = _mainController; |   @override | ||||||
| // |   _KeepAlivePageState createState() => _KeepAlivePageState(); | ||||||
| //                 addTouchendEventJS(); | } | ||||||
| // | 
 | ||||||
| //               }), | class _KeepAlivePageState extends State<KeepAlivePage> with AutomaticKeepAliveClientMixin { | ||||||
| //             ), |   @override | ||||||
| //           ), |   bool get wantKeepAlive => true; | ||||||
| //         ), | 
 | ||||||
| //         Expanded( |   @override | ||||||
| //           child: Container( |   Widget build(BuildContext context) { | ||||||
| //             color: Colors.blue, |     super.build(context); | ||||||
| //             child: KeepAlivePage( |     return widget.child; | ||||||
| //               child: WebWidget(controlerCallBack: (_controller) { |   } | ||||||
| //                 controller = _controller; | } | ||||||
| //               }), |  | ||||||
| //             ), |  | ||||||
| //           ), |  | ||||||
| //         ) |  | ||||||
| //       ], |  | ||||||
| //     ); |  | ||||||
| //   } |  | ||||||
| // |  | ||||||
| // } |  | ||||||
| // |  | ||||||
| // class KeepAlivePage extends StatefulWidget { |  | ||||||
| //   final Widget child; |  | ||||||
| // |  | ||||||
| //   KeepAlivePage({super.key , required this.child}); |  | ||||||
| // |  | ||||||
| //   @override |  | ||||||
| //   _KeepAlivePageState createState() => _KeepAlivePageState(); |  | ||||||
| // } |  | ||||||
| // |  | ||||||
| // class _KeepAlivePageState extends State<KeepAlivePage> with AutomaticKeepAliveClientMixin { |  | ||||||
| //   @override |  | ||||||
| //   bool get wantKeepAlive => true; |  | ||||||
| // |  | ||||||
| //   @override |  | ||||||
| //   Widget build(BuildContext context) { |  | ||||||
| //     super.build(context); |  | ||||||
| //     return widget.child; |  | ||||||
| //   } |  | ||||||
| // } |  | ||||||
|  |  | ||||||
|  | @ -1,42 +1,31 @@ | ||||||
| // import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| // import 'package:flutter_inappwebview/flutter_inappwebview.dart'; | import 'package:flutter_inappwebview/flutter_inappwebview.dart'; | ||||||
| // import 'package:web_synchronization_tool/JavaScriptString.dart'; | import 'package:web_synchronization_tool/JavaScriptString.dart'; | ||||||
| // | 
 | ||||||
| // class WebWidget extends StatefulWidget { | class WebWidget extends StatefulWidget { | ||||||
| //   WebWidget({super.key, required this.controlerCallBack}); |   WebWidget({super.key, required this.controlerCallBack}); | ||||||
| // | 
 | ||||||
| //   final Function(InAppWebViewController) controlerCallBack; |   final Function(InAppWebViewController) controlerCallBack; | ||||||
| // | 
 | ||||||
| //   @override |   @override | ||||||
| //   State<WebWidget> createState() => _WebWidgetState(); |   State<WebWidget> createState() => _WebWidgetState(); | ||||||
| // } | } | ||||||
| // | 
 | ||||||
| // class _WebWidgetState extends State<WebWidget> { | class _WebWidgetState extends State<WebWidget> { | ||||||
| //   @override |   @override | ||||||
| //   void initState() { |   void initState() { | ||||||
| //     super.initState(); |     super.initState(); | ||||||
| //   } |   } | ||||||
| // | 
 | ||||||
| //   @override |   @override | ||||||
| //   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
| //     return InAppWebView( |     return InAppWebView( | ||||||
| //       initialUrlRequest: |       initialUrlRequest: | ||||||
| //       URLRequest(url: WebUri('http://www.df6831.com/mobile')),// |           URLRequest(url: WebUri('http://www.df6831.com/game/')), | ||||||
| //       initialSettings: InAppWebViewSettings( |       initialSettings: InAppWebViewSettings(initialScale: 200,loadWithOverviewMode: false,useWideViewPort: false), | ||||||
| //         // initialScale: 180, |       onWebViewCreated: (_controller) { | ||||||
| //         loadWithOverviewMode: false, |         widget.controlerCallBack(_controller); | ||||||
| //         useWideViewPort: false, |       }, | ||||||
| //         // preferredContentMode: UserPreferredContentMode.MOBILE, |     ); | ||||||
| //         // cacheEnabled: false, //启用缓存 |   } | ||||||
| //         // clearSessionCache: true,//清除会话缓存 | } | ||||||
| //         // databaseEnabled:false, // 启用数据库 |  | ||||||
| //         // domStorageEnabled: false,//启用 dom 存储 |  | ||||||
| //         incognito: true, //隐身模式 |  | ||||||
| //         sharedCookiesEnabled: false, // 共享Cookie |  | ||||||
| //       ), |  | ||||||
| //       onWebViewCreated: (_controller) { |  | ||||||
| //         widget.controlerCallBack(_controller); |  | ||||||
| //       }, |  | ||||||
| //     ); |  | ||||||
| //   } |  | ||||||
| // } |  | ||||||
|  |  | ||||||
|  | @ -1,37 +0,0 @@ | ||||||
| // 定义密钥 |  | ||||||
| import 'dart:convert'; |  | ||||||
| 
 |  | ||||||
| List skey = [8, 1, 2, 5, 4]; |  | ||||||
| 
 |  | ||||||
| // 单个字符异或运算 |  | ||||||
| String makecodeChar(String c, int key, int key2) { |  | ||||||
|   int charCode = c.codeUnitAt(0); |  | ||||||
|   charCode = (((charCode + key) ^ key2) ^ key) + 1; |  | ||||||
|   return String.fromCharCode(charCode); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // 单个字符解密 |  | ||||||
| String cutcodeChar(String c, int key, int key2) { |  | ||||||
|   int charCode = c.codeUnitAt(0); |  | ||||||
|   int decryptedCharCode = (((charCode - 1) ^ key) ^ key2) - key; |  | ||||||
|   return String.fromCharCode(decryptedCharCode); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // 加密 |  | ||||||
| String makecode(String pstr, List pkey) { |  | ||||||
|   String pp = pstr; |  | ||||||
|   for (int i = 0; i < pp.length; i++) { |  | ||||||
|     pp = pp.replaceRange(i, i + 1, makecodeChar(pp[i], pkey[i % 5], pkey[(i + 18) % 5])); |  | ||||||
|   } |  | ||||||
|   return pp; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // 解密 |  | ||||||
| String cutecode(List<int> pstr) { |  | ||||||
|   int len = pstr.length; |  | ||||||
|   for (int i = 0; i < len; i++) { |  | ||||||
|     pstr[i] = cutcodeChar(String.fromCharCode(pstr[i]) |  | ||||||
|         , skey[i % 5], skey[(i + 18) % 5]).codeUnitAt(0); |  | ||||||
|   } |  | ||||||
|   return String.fromCharCodes(pstr); |  | ||||||
| } |  | ||||||
|  | @ -1,97 +0,0 @@ | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| import 'dart:convert'; |  | ||||||
| import 'dart:typed_data'; |  | ||||||
| 
 |  | ||||||
| /// 添加小端序头 |  | ||||||
| extension MapLittle on Map { |  | ||||||
| 
 |  | ||||||
|   /// 在转成 Uint8List 的数据前面添加 小端序 |  | ||||||
|   Uint8List toLittle({dynamic value = 0, int length = 4}){ |  | ||||||
| 
 |  | ||||||
|     /// map 转 json |  | ||||||
|     String mapJson = jsonEncode(this); |  | ||||||
|     /// json 转 Uint8List |  | ||||||
|     final mapData = utf8.encode(mapJson); |  | ||||||
| 
 |  | ||||||
|     /// 添加小端序 |  | ||||||
|     final data = mapData.toLittle(value: value,length: length); |  | ||||||
| 
 |  | ||||||
|     return data; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| extension ListIntLittle on List<int> { |  | ||||||
| 
 |  | ||||||
|   List<int> toLittle({int? value, int length = 4}){ |  | ||||||
| 
 |  | ||||||
|     List<int> ret = []; |  | ||||||
|     /// 初始化 定义数据长度 |  | ||||||
|     final little = ByteData(4); |  | ||||||
|     /// 设置小端序数据 |  | ||||||
|     little.setInt32(0, value ?? this.length, Endian.little); |  | ||||||
| 
 |  | ||||||
|     for (int i = 0; i < little.lengthInBytes; i++) { |  | ||||||
|       ret.add(little.getUint8(i)); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     ret.addAll(this); |  | ||||||
| 
 |  | ||||||
|     return ret; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| extension Uint8ListLittle on Uint8List { |  | ||||||
| 
 |  | ||||||
|   /// 在转成 Uint8List 的数据前面添加 小端序 |  | ||||||
|   Uint8List toLittle({dynamic value = 0, int length = 4}){ |  | ||||||
| 
 |  | ||||||
|     var mapData = this; |  | ||||||
| 
 |  | ||||||
|     /// 初始化 定义数据长度 |  | ||||||
|     final little = ByteData(length); |  | ||||||
|     /// 设置小端序数据 |  | ||||||
|     little.setInt32(0, value,Endian.little); |  | ||||||
|     /// 小端序 转 Uint8List |  | ||||||
|     var littleData = little.buffer.asUint8List(); |  | ||||||
| 
 |  | ||||||
|     /// 初始化 Uint8List |  | ||||||
|     Uint8List data = Uint8List(littleData.length + mapData.length ); |  | ||||||
| 
 |  | ||||||
|     /// 组装 map Uint8List 和 小端序 Uint8List |  | ||||||
|     data.setRange(0, littleData.length, littleData); |  | ||||||
|     data.setRange(littleData.length, mapData.length + littleData.length, mapData); |  | ||||||
| 
 |  | ||||||
|     /// 返回组合数据 |  | ||||||
|     return data; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // Uint8List转int 从前4位转小端序 |  | ||||||
|   int? fromLittle({int start = 0,int length  = 4}) { |  | ||||||
|     if (this.length < length){ |  | ||||||
|       print('转小端序的数据长度不足'); |  | ||||||
|       return null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     final littleData = sublist(start,start + length); |  | ||||||
|     // 创建ByteData |  | ||||||
|     ByteData byteData = littleData.buffer.asByteData(); |  | ||||||
| 
 |  | ||||||
|     // 读取小端序的32位整数 |  | ||||||
|     int little = byteData.getInt32(0, Endian.little); |  | ||||||
| 
 |  | ||||||
|     return little; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|  | @ -1,48 +0,0 @@ | ||||||
| 
 |  | ||||||
| import 'dart:math'; |  | ||||||
| 
 |  | ||||||
| class NumberTool { |  | ||||||
| 
 |  | ||||||
|   /// 生成随机数 |  | ||||||
|   /// @allNum: 随机数的和 |  | ||||||
|   /// @num: 随机数的数量 |  | ||||||
|   List<int> randomNum(int allNum, {int num = 10}) { |  | ||||||
|     Random random = Random(); |  | ||||||
| 
 |  | ||||||
|     // 基础数字 最小值 |  | ||||||
|     int base = allNum ~/ 1.5 ~/ num; |  | ||||||
|     List<int> numbers = List.generate(num, (index) => base); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     for (int i = 0; i < num - 1; i++) { |  | ||||||
|       int randomNumber = random.nextInt(base); // 生成0到base之间的随机整数 |  | ||||||
|       numbers[i] += randomNumber; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     int sum = numbers.reduce((a, b) => a + b) ; |  | ||||||
|     int lastNumber = allNum - sum; |  | ||||||
| 
 |  | ||||||
|     // 将最后一个数 /2  再/数量 取整数 |  | ||||||
|     base = (lastNumber / 2) ~/ (num); |  | ||||||
|     for (int i = 0; i < num - 1; i++) { |  | ||||||
|       numbers[i] += base; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     sum = numbers.reduce((a, b) => a + b); |  | ||||||
|     lastNumber = allNum - sum; |  | ||||||
| 
 |  | ||||||
|     // 将最后一个数 切一半 随机加到数组中 |  | ||||||
|     base = lastNumber ~/ 2; |  | ||||||
|     numbers[ random.nextInt(num - 1)] = base; |  | ||||||
|     sum = numbers.reduce((a, b) => a + b); |  | ||||||
|     lastNumber = allNum - sum; |  | ||||||
| 
 |  | ||||||
|     numbers.add(lastNumber); |  | ||||||
| 
 |  | ||||||
|     // 打乱顺序 |  | ||||||
|     numbers.shuffle(); |  | ||||||
| 
 |  | ||||||
|     return numbers; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,147 +0,0 @@ | ||||||
| 
 |  | ||||||
| import 'package:flutter/material.dart'; |  | ||||||
| 
 |  | ||||||
| enum TransitionType { |  | ||||||
|   ///左侧弹出 |  | ||||||
|   inFromLeft, |  | ||||||
|   ///右侧弹出 |  | ||||||
|   inFromRight, |  | ||||||
|   ///顶部弹出 |  | ||||||
|   inFromTop, |  | ||||||
|   ///底部弹出 |  | ||||||
|   inFromBottom, |  | ||||||
|   ///缩放 |  | ||||||
|   scale, |  | ||||||
|   ///渐变 |  | ||||||
|   fade, |  | ||||||
|   ///旋转缩放 |  | ||||||
|   rotation, |  | ||||||
|   ///放大 |  | ||||||
|   size, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   //弹出动画 |  | ||||||
|   // barrierDismissible:点击背景是否消失 |  | ||||||
|   // child,builder:子 widget |  | ||||||
|   // useRootNavigator: 是否推入传入 context的 导航器 |  | ||||||
|   // routeSettings: 弹窗路由设置 |  | ||||||
|   Future<T?> showAnimationDialog<T>({ |  | ||||||
|     required BuildContext context, |  | ||||||
|     bool barrierDismissible = true, |  | ||||||
|     Widget? child, |  | ||||||
|     WidgetBuilder? builder, |  | ||||||
|     bool useRootNavigator = true, |  | ||||||
|     RouteSettings? routeSettings, |  | ||||||
|     TransitionType? transitionType, |  | ||||||
|   }) { |  | ||||||
|     assert(child == null || builder == null); |  | ||||||
|     assert(debugCheckHasMaterialLocalizations(context)); |  | ||||||
| 
 |  | ||||||
|     final ThemeData theme = Theme.of(context); |  | ||||||
|     return showGeneralDialog( |  | ||||||
|       context: context, |  | ||||||
|       pageBuilder: (BuildContext buildContext, Animation<double> animation, Animation<double> secondaryAnimation) { |  | ||||||
|         final Widget pageChild = child ?? Builder(builder: builder!); |  | ||||||
|         return SafeArea( |  | ||||||
|           child: Builder(builder: (BuildContext context) { |  | ||||||
|             return Theme(data: theme, child: pageChild); |  | ||||||
|           }), |  | ||||||
|         ); |  | ||||||
|       }, |  | ||||||
|       barrierDismissible: barrierDismissible, ///点击背景是否消失 |  | ||||||
|       barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, |  | ||||||
|       barrierColor: Colors.black38, ///背景色 |  | ||||||
|       transitionDuration: const Duration(milliseconds: 200),///动画时间 |  | ||||||
|       transitionBuilder: (context, animation1, animation2, child) { ///动画效果 |  | ||||||
|         return _buildDialogTransitions(context, animation1, animation2, child, transitionType?? TransitionType.inFromBottom); |  | ||||||
|       }, |  | ||||||
|       useRootNavigator: useRootNavigator, |  | ||||||
|       routeSettings: routeSettings, |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   ///返回动画效果 |  | ||||||
|   Widget _buildDialogTransitions( |  | ||||||
|       BuildContext context, Animation<double> animaton1, Animation<double> secondaryAnimation, Widget child, TransitionType type) { |  | ||||||
| 
 |  | ||||||
|     /// 渐变效果 |  | ||||||
|     if (type == TransitionType.fade) { |  | ||||||
|       return FadeTransition( |  | ||||||
|         // 从0开始到1 |  | ||||||
|         opacity: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation( |  | ||||||
|           // 传入设置的动画 |  | ||||||
|           parent: animaton1, |  | ||||||
|           // 设置效果,快进漫出   这里有很多内置的效果 |  | ||||||
|           curve: Curves.fastOutSlowIn, |  | ||||||
|         )), |  | ||||||
|         child: child, |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|       ///缩放 |  | ||||||
|     } else if (type == TransitionType.scale) { |  | ||||||
|       return ScaleTransition( |  | ||||||
|         scale: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: animaton1, curve: Curves.easeOutBack)),//Curves.easeOutBack |  | ||||||
|         child: child, |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|       /// 旋转加缩放动画效果 |  | ||||||
|     } else if (type == TransitionType.rotation) { |  | ||||||
| 
 |  | ||||||
|       return RotationTransition( |  | ||||||
|         turns: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation( |  | ||||||
|           parent: animaton1, |  | ||||||
|           curve: Curves.fastOutSlowIn, |  | ||||||
|         )), |  | ||||||
|         child: ScaleTransition( |  | ||||||
|           scale: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: animaton1, curve: Curves.fastOutSlowIn)), |  | ||||||
|           child: child, |  | ||||||
|         ), |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|       /// 左滑出动画效果 |  | ||||||
|     } else if (type == TransitionType.inFromLeft) { |  | ||||||
| 
 |  | ||||||
|       return SlideTransition( |  | ||||||
|         position: Tween<Offset>(begin: Offset(-1.0, 0.0), end: Offset(0.0, 0.0)) |  | ||||||
|             .animate(CurvedAnimation(parent: animaton1, curve: Curves.fastOutSlowIn)), |  | ||||||
|         child: child, |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|       /// 右滑出动画效果 |  | ||||||
|     } else if (type == TransitionType.inFromRight) { |  | ||||||
|       return SlideTransition( |  | ||||||
|         position: Tween<Offset>(begin: Offset(1.0, 0.0), end: Offset(0.0, 0.0)) |  | ||||||
|             .animate(CurvedAnimation(parent: animaton1, curve: Curves.fastOutSlowIn)), |  | ||||||
|         child: child, |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|       /// 顶部滑出动画效果 |  | ||||||
|     } else if (type == TransitionType.inFromTop) { |  | ||||||
|       return SlideTransition( |  | ||||||
|         position: Tween<Offset>(begin: Offset(0.0, -1.0), end: Offset(0.0, 0.0)) |  | ||||||
|             .animate(CurvedAnimation(parent: animaton1, curve: Curves.fastOutSlowIn)), |  | ||||||
|         child: child, |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|       /// 底部滑出动画效果 |  | ||||||
|     } else if (type == TransitionType.inFromBottom) { |  | ||||||
|       return SlideTransition( |  | ||||||
|         position: Tween<Offset>(begin: Offset(0.0, 1.0), end: Offset(0.0, 0.0)) |  | ||||||
|             .animate(CurvedAnimation(parent: animaton1, curve: Curves.fastOutSlowIn)), |  | ||||||
|         child: child, |  | ||||||
|       ); |  | ||||||
| 
 |  | ||||||
|       /// 放大出显动画效果 |  | ||||||
|     } else if (type == TransitionType.size) { |  | ||||||
|       return ScaleTransition( |  | ||||||
|         child: child, |  | ||||||
|         scale: Tween<double>(begin: 0.0, end: 1.0).animate(CurvedAnimation(parent: animaton1, curve: Curves.fastOutSlowIn)), |  | ||||||
|       ); |  | ||||||
|     } else { |  | ||||||
|       return child; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|  | @ -1,132 +0,0 @@ | ||||||
| import 'dart:async'; |  | ||||||
| import 'dart:convert'; |  | ||||||
| import 'dart:io'; |  | ||||||
| import 'dart:typed_data'; |  | ||||||
| import 'package:web_synchronization_tool/windows/synchronization_web_tool.dart'; |  | ||||||
| 
 |  | ||||||
| import 'little_extension.dart'; |  | ||||||
| import 'code.dart'; |  | ||||||
| import 'number_tool.dart'; |  | ||||||
| 
 |  | ||||||
| class SocketUtils extends SyncSocket{ |  | ||||||
|   // 私有构造函数 |  | ||||||
|   SocketUtils._(); |  | ||||||
|   // 私有静态变量,保存类的唯一实例 |  | ||||||
|   static SocketUtils? _instance; |  | ||||||
| 
 |  | ||||||
|   // 公开的静态方法,返回类的唯一实例 |  | ||||||
|   static SocketUtils getInstance() { |  | ||||||
|     _instance ??= SocketUtils._(); |  | ||||||
|     return _instance!; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class SyncSocket { |  | ||||||
| 
 |  | ||||||
|   String url = '127.0.0.1'; |  | ||||||
|   static int port = 46182; |  | ||||||
| 
 |  | ||||||
|   RawDatagramSocket? socket; |  | ||||||
| 
 |  | ||||||
|   // IC 0主机 1 从机 |  | ||||||
|   int ic = 1; |  | ||||||
| 
 |  | ||||||
|   /// 从机ip |  | ||||||
|   List<String> childrenIp = []; |  | ||||||
| 
 |  | ||||||
|   connect() async { |  | ||||||
|     socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0); |  | ||||||
| 
 |  | ||||||
|     // 发送身份包 |  | ||||||
|     Map data = { |  | ||||||
|       "op": 0, |  | ||||||
|       "IC": ic |  | ||||||
|     }; |  | ||||||
|     socket?.send(dataMake(data), InternetAddress(url), port); |  | ||||||
| 
 |  | ||||||
|     // 监听来自网络的数据包 |  | ||||||
|     socket?.listen((RawSocketEvent e) { |  | ||||||
|       Datagram? d = socket?.receive(); |  | ||||||
|       if (d == null) return; |  | ||||||
| 
 |  | ||||||
|       Map data = dataCute(d.data); |  | ||||||
| 
 |  | ||||||
|       // 收到消息 |  | ||||||
|       if (data['op'] == 2){ |  | ||||||
| 
 |  | ||||||
|         print(data); |  | ||||||
| 
 |  | ||||||
|         //点击 |  | ||||||
|         if (data['click'] != null){ |  | ||||||
|           Map click = data['click']; |  | ||||||
|           int x = click['x'] as int; |  | ||||||
|           int y = click['y'] as int; |  | ||||||
| 
 |  | ||||||
|           SynchronizationWebTool.getInstance().clickSynchronization(x, y); |  | ||||||
|         } |  | ||||||
|         //输入 |  | ||||||
|         if (data['input'] != null){ |  | ||||||
|           int input = data['input']; |  | ||||||
|           List<int> nums = NumberTool().randomNum(input); |  | ||||||
|           SynchronizationWebTool.getInstance().input(nums); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       // 心跳 |  | ||||||
|       if (data['op'] == 11){ |  | ||||||
| 
 |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|     }); |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 心跳 |  | ||||||
|   heartbeat(){ |  | ||||||
|     Timer timer = Timer(const Duration(seconds: 10), () async { |  | ||||||
| 
 |  | ||||||
|       if (socket == null){ |  | ||||||
|         // 重连 |  | ||||||
|         await connect(); |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       Map data =   { |  | ||||||
|         "op": 1, |  | ||||||
|         "IC": ic |  | ||||||
|       }; |  | ||||||
|       socket?.send(dataMake(data), InternetAddress(url), port); |  | ||||||
| 
 |  | ||||||
|       heartbeat(); |  | ||||||
|     }); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 发送数据的处理 |  | ||||||
|   List<int> dataMake(Map map){ |  | ||||||
|     // 将Map对象转换为JSON字符串 |  | ||||||
|     String json = jsonEncode(map); |  | ||||||
|     // 加密 |  | ||||||
|     String ps = makecode(json, skey); |  | ||||||
|     // 转成无符号整数数组 |  | ||||||
|     Uint8List uinData = Uint8List.fromList(ps.codeUnits); |  | ||||||
|     // 在前面添加 4位 表示长度的小端序 |  | ||||||
|     uinData = uinData.toLittle(value: uinData.length); |  | ||||||
|     return uinData.toList(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 接收数据处理 |  | ||||||
|   Map dataCute(Uint8List data){ |  | ||||||
| 
 |  | ||||||
|     if (data.length <= 4) return {}; |  | ||||||
| 
 |  | ||||||
|     Uint8List pData = data.sublist(4,data.length); |  | ||||||
| 
 |  | ||||||
|     String str = cutecode(pData); |  | ||||||
| 
 |  | ||||||
|     Map map = json.decode(str); |  | ||||||
| 
 |  | ||||||
|     return map; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,66 +0,0 @@ | ||||||
| 
 |  | ||||||
| import 'dart:ffi'; |  | ||||||
| 
 |  | ||||||
| import 'package:web_synchronization_tool/windows/socket_tool.dart'; |  | ||||||
| import 'package:web_synchronization_tool/windows/windowsJs.dart'; |  | ||||||
| import 'package:webview_windows/webview_windows.dart'; |  | ||||||
| 
 |  | ||||||
| class SynchronizationWebTool{ |  | ||||||
| 
 |  | ||||||
|   // 私有构造函数 |  | ||||||
|   SynchronizationWebTool._(); |  | ||||||
|   // 私有静态变量,保存类的唯一实例 |  | ||||||
|   static SynchronizationWebTool? _instance; |  | ||||||
| 
 |  | ||||||
|   // 公开的静态方法,返回类的唯一实例 |  | ||||||
|   static SynchronizationWebTool getInstance() { |  | ||||||
|     _instance ??= SynchronizationWebTool._(); |  | ||||||
|     return _instance!; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 受控 |  | ||||||
|   List<WebviewController> _childControllers = []; |  | ||||||
| 
 |  | ||||||
|   /// 设置控制器时 注入js |  | ||||||
|   setChildController(List<WebviewController> childControllers){ |  | ||||||
| 
 |  | ||||||
|     // for (var controller in childControllers) { |  | ||||||
|     //   controller.addScriptToExecuteOnDocumentCreated(WindowsJs.clickEventJs); |  | ||||||
|     //   // controller.addScriptToExecuteOnDocumentCreated(WindowsJs.onloadZoom(90)); |  | ||||||
|     // } |  | ||||||
| 
 |  | ||||||
|     _childControllers = childControllers; |  | ||||||
| 
 |  | ||||||
|     // 滚动监听 |  | ||||||
|     // mainController.addScriptToExecuteOnDocumentCreated(WindowsJs.scrollEventJs); |  | ||||||
| 
 |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   List<WebviewController> get childController{ |  | ||||||
|     return _childControllers; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 点击同步 |  | ||||||
|   clickSynchronization(int x,int y){ |  | ||||||
|     for (var controller in childController) { |  | ||||||
|       controller.executeScript(WindowsJs.clickJs(x, y)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   /// 滚动同步 |  | ||||||
|   scrollSynchronization(int y){ |  | ||||||
|     for (var controller in childController) { |  | ||||||
|       controller.executeScript(WindowsJs.scrollTo(y) ); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 输入 |  | ||||||
|   input(List<int> values){ |  | ||||||
|     for (int i =0;i<childController.length;i++){ |  | ||||||
|       WebviewController controller = childController[i]; |  | ||||||
|       controller.executeScript(WindowsJs.inputJs(values[i])); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,280 +0,0 @@ | ||||||
| import 'package:flutter/material.dart'; |  | ||||||
| import 'package:web_synchronization_tool/windows/socket_tool.dart'; |  | ||||||
| import 'package:web_synchronization_tool/windows/synchronization_web_tool.dart'; |  | ||||||
| import 'package:webview_windows/webview_windows.dart'; |  | ||||||
| 
 |  | ||||||
| class WebGridController { |  | ||||||
|   Function(WebviewController controller)? addWebControllerBlack; |  | ||||||
|   Function? addWebBlack; |  | ||||||
|   Function? addAllWebBlack; |  | ||||||
| 
 |  | ||||||
|   addMainController(WebviewController controller) { |  | ||||||
|     if (addWebControllerBlack != null) { |  | ||||||
|       addWebControllerBlack!(controller); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   addWeb() { |  | ||||||
|     if (addWebBlack != null) { |  | ||||||
|       addWebBlack!(); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   addAllWeb() { |  | ||||||
|     if (addAllWebBlack != null) { |  | ||||||
|       addAllWebBlack!(); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class WebGridWidget extends StatefulWidget { |  | ||||||
|   const WebGridWidget({super.key, required this.controller}); |  | ||||||
| 
 |  | ||||||
|   final WebGridController controller; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   State<WebGridWidget> createState() => _WebGridWidgetState(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class _WebGridWidgetState extends State<WebGridWidget> { |  | ||||||
|   List<WebviewController> controllers = []; |  | ||||||
| 
 |  | ||||||
|   bool initDone = false; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   void initState() { |  | ||||||
|     super.initState(); |  | ||||||
| 
 |  | ||||||
|     widget.controller.addWebBlack = () { |  | ||||||
|       addController(); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     widget.controller.addAllWebBlack = () { |  | ||||||
|       addAllController(); |  | ||||||
|     }; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // 提娜佳一个网页 |  | ||||||
|   addController() async { |  | ||||||
|     if (controllers.length >= 10) return; |  | ||||||
| 
 |  | ||||||
|     var controller = WebviewController(); |  | ||||||
|     await controller.initialize(); |  | ||||||
|     controller.loadUrl('https://www.df6831.com/'); |  | ||||||
| 
 |  | ||||||
|     controllers.add(controller); |  | ||||||
|     SynchronizationWebTool.getInstance().setChildController(controllers); |  | ||||||
|     setState(() {}); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // 将网页加满到10个 |  | ||||||
|   addAllController() async { |  | ||||||
|     final num = 10 - controllers.length; |  | ||||||
|     if (num < 1) return; |  | ||||||
| 
 |  | ||||||
|     for (int i = 0; i < num; i++) { |  | ||||||
|       var controller = WebviewController(); |  | ||||||
|       await controller.initialize(); |  | ||||||
|       controller.loadUrl('https://www.df6831.com/'); |  | ||||||
|       controllers.add(controller); |  | ||||||
|     } |  | ||||||
|     SynchronizationWebTool.getInstance().setChildController(controllers); |  | ||||||
|     setState(() {}); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
|     return Stack( |  | ||||||
|       children: [ |  | ||||||
|         GridView.builder( |  | ||||||
|           gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( |  | ||||||
|               crossAxisCount: 5, // 两列 |  | ||||||
|               crossAxisSpacing: 8.0, // 水平间距 |  | ||||||
|               mainAxisSpacing: 8.0, // 垂直间距 |  | ||||||
|               childAspectRatio: 0.9), |  | ||||||
|           itemBuilder: (BuildContext context, int index) { |  | ||||||
|             return Stack( |  | ||||||
|               children: [ |  | ||||||
|                 Webview(controllers[index]), |  | ||||||
|                 TextButton( |  | ||||||
|                   style: ButtonStyle( |  | ||||||
|                       overlayColor: MaterialStateProperty.resolveWith( |  | ||||||
|                           (states) => Colors.transparent)), |  | ||||||
|                   onPressed: () { |  | ||||||
|                     var controller = controllers[index]; |  | ||||||
|                     // controller.executeScript(WindowsJs.zoom(100)); |  | ||||||
| 
 |  | ||||||
|                     // showAnimationDialog( |  | ||||||
|                     //     context: context, |  | ||||||
|                     //     // barrierDismissible: false, |  | ||||||
|                     //     child: ShowWebWidget(controller: controller,)); |  | ||||||
| 
 |  | ||||||
|                     // Navigator.push(context, MaterialPageRoute(builder: (context)=> ShowWebWidget(controller: controller,) )); |  | ||||||
| 
 |  | ||||||
|                     Navigator.of(context).push(PageRouteBuilder( |  | ||||||
|                       opaque: false, // 设置路由本身透明 |  | ||||||
|                       pageBuilder: (BuildContext context, _, __) => |  | ||||||
|                           ShowWebWidget( |  | ||||||
|                         controller: controller, |  | ||||||
|                         main: index == 0, |  | ||||||
|                         allLoadUrl: (String url) { |  | ||||||
|                           controllers.forEach((controller) { |  | ||||||
|                             controller.loadUrl(url); |  | ||||||
|                           }); |  | ||||||
|                         }, |  | ||||||
|                       ), |  | ||||||
|                     )); |  | ||||||
|                   }, |  | ||||||
|                   child: Container(), |  | ||||||
|                 ), |  | ||||||
|                 Container( |  | ||||||
|                   alignment: Alignment.topRight, |  | ||||||
|                   child: TextButton( |  | ||||||
|                     style: TextButton.styleFrom(padding: const EdgeInsets.all(0)), |  | ||||||
|                     onPressed: () { |  | ||||||
|                       controllers.removeAt(index); |  | ||||||
|                       SynchronizationWebTool.getInstance() |  | ||||||
|                           .setChildController(controllers); |  | ||||||
|                       setState(() {}); |  | ||||||
|                     }, |  | ||||||
|                     child: Container( |  | ||||||
|                         width: 50, |  | ||||||
|                         height: 50, |  | ||||||
|                         color: Colors.blue[100], |  | ||||||
|                         alignment: Alignment.center, |  | ||||||
|                         child: const Icon(Icons.clear)), |  | ||||||
|                   ), |  | ||||||
|                 ) |  | ||||||
|               ], |  | ||||||
|             ); |  | ||||||
|           }, |  | ||||||
|           itemCount: controllers.length, // 生成20个瀑布流瓦片 |  | ||||||
|         ) |  | ||||||
|       ], |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class ShowWebWidget extends StatefulWidget { |  | ||||||
|   const ShowWebWidget( |  | ||||||
|       {super.key, |  | ||||||
|       required this.controller, |  | ||||||
|       this.main = false, |  | ||||||
|       required this.allLoadUrl}); |  | ||||||
| 
 |  | ||||||
|   final WebviewController controller; |  | ||||||
| 
 |  | ||||||
|   final Function(String url) allLoadUrl; |  | ||||||
| 
 |  | ||||||
|   final bool main; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   State<ShowWebWidget> createState() => _ShowWebWidgetState(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class _ShowWebWidgetState extends State<ShowWebWidget> { |  | ||||||
|   /// 网址 |  | ||||||
|   TextEditingController urlController = TextEditingController(); |  | ||||||
| 
 |  | ||||||
|   /// 服务器ip |  | ||||||
|   TextEditingController ipController = TextEditingController(); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   void dispose() { |  | ||||||
|     super.dispose(); |  | ||||||
| 
 |  | ||||||
|     // widget.controller.clearCache(); |  | ||||||
|     // widget.controller.clearCookies(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
|     return Scaffold( |  | ||||||
|       backgroundColor: Colors.transparent, |  | ||||||
|       appBar: AppBar( |  | ||||||
|         title: getTitleWidget(), |  | ||||||
|       ), |  | ||||||
|       body: Center( |  | ||||||
|         child: SizedBox( |  | ||||||
|           width: 1400, |  | ||||||
|           height: 900, |  | ||||||
|           child: Webview(widget.controller), |  | ||||||
|         ), |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   Widget getTitleWidget() { |  | ||||||
|     if (widget.main == false) return input(); |  | ||||||
|     return Row( |  | ||||||
|       children: [ |  | ||||||
|         // TextButton( |  | ||||||
|         //     onPressed: () { |  | ||||||
|         //       widget.controller.openDevTools(); |  | ||||||
|         //     }, |  | ||||||
|         //     child: const Text('开发者')), |  | ||||||
|         input(), |  | ||||||
|         ipSet() |  | ||||||
|       ], |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 跳转网址 |  | ||||||
|   input() { |  | ||||||
|     return Row( |  | ||||||
|       children: [ |  | ||||||
|         SizedBox( |  | ||||||
|             width: 400, |  | ||||||
|             child: TextField( |  | ||||||
|               style: const TextStyle(fontSize: 14), |  | ||||||
|               controller: urlController, |  | ||||||
|             )), |  | ||||||
|         TextButton( |  | ||||||
|             onPressed: () { |  | ||||||
|               String url = urlController.text; |  | ||||||
|               // if (!url.startsWith("https://") ) { |  | ||||||
|               //   url = "https://$url"; |  | ||||||
|               // } |  | ||||||
|               widget.controller.loadUrl(url); |  | ||||||
|             }, |  | ||||||
|             child: const Text( |  | ||||||
|               '跳转', |  | ||||||
|               style: TextStyle(fontSize: 14), |  | ||||||
|             )), |  | ||||||
|         TextButton( |  | ||||||
|             onPressed: () { |  | ||||||
|               String url = urlController.text; |  | ||||||
| 
 |  | ||||||
|               widget.allLoadUrl(url); |  | ||||||
|             }, |  | ||||||
|             child: const Text( |  | ||||||
|               '全部跳转', |  | ||||||
|               style: TextStyle(fontSize: 14), |  | ||||||
|             )), |  | ||||||
|       ], |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   ipSet() { |  | ||||||
|     ipController.text = SocketUtils.getInstance().url; |  | ||||||
|     return Row( |  | ||||||
|       children: [ |  | ||||||
|         SizedBox( |  | ||||||
|             width: 100, |  | ||||||
|             child: TextField( |  | ||||||
|               style: const TextStyle(fontSize: 14), |  | ||||||
|               controller: ipController, |  | ||||||
|             )), |  | ||||||
|         TextButton( |  | ||||||
|             onPressed: () { |  | ||||||
|               SocketUtils.getInstance().url = ipController.text; |  | ||||||
|               SocketUtils.getInstance().connect(); |  | ||||||
|             }, |  | ||||||
|             child: const Text( |  | ||||||
|               '保存服务器ip', |  | ||||||
|               style: TextStyle(fontSize: 14), |  | ||||||
|             )) |  | ||||||
|       ], |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  | @ -1,134 +0,0 @@ | ||||||
| class WindowsJs { |  | ||||||
|   /// 点击监听 |  | ||||||
|   static String clickEventJs = ''' |  | ||||||
| document.addEventListener("click", function (event) { |  | ||||||
|   var x = event.clientX; |  | ||||||
|   var y = event.clientY; |  | ||||||
| 
 |  | ||||||
|   var click = { "x": x, "y": y }; |  | ||||||
|   var value = { click: click }; |  | ||||||
| 
 |  | ||||||
|   // 发送消息 |  | ||||||
|   window.chrome.webview.postMessage(value); |  | ||||||
|    |  | ||||||
|   // window.chrome.webview.postMessage({"text":event.target.textContent,"end":event.target.textContent === "进入游戏"}); |  | ||||||
| 
 |  | ||||||
|   // 检查点击的元素是否有类名为 'btn' |  | ||||||
|   if (event.target.textContent === "进入游戏") { |  | ||||||
|     // 获取按钮上显示的文本内容 |  | ||||||
|     window.chrome.webview.postMessage({ "成功获取到btn": 1 }); |  | ||||||
|     // window.chrome.webview.postMessage({ "btn": event.target.textContent }); |  | ||||||
| 
 |  | ||||||
|     // 阻止默认的链接跳转行为 |  | ||||||
|     event.preventDefault(); |  | ||||||
| 
 |  | ||||||
|     var oldUrl = window.location.href; |  | ||||||
|     var classUrl = event.target.href; |  | ||||||
|      |  | ||||||
|     var str = oldUrl; |  | ||||||
|     var startIndex = str.indexOf('www.'); |  | ||||||
|     var endIndex = str.indexOf('/', startIndex); |  | ||||||
|     var url = str.substring(startIndex, endIndex); |  | ||||||
|     var newUrl = "https://" + url + "/game/"; |  | ||||||
|      |  | ||||||
|     // window.chrome.webview.postMessage({"元素地址": classUrl ,"旧地址":window.location.href ,"截取":url,"新地址": newUrl}); |  | ||||||
|     window.location.href = newUrl; |  | ||||||
|        |  | ||||||
|   } |  | ||||||
| }); |  | ||||||
|   '''; |  | ||||||
| 
 |  | ||||||
|   /// 滚动监听 |  | ||||||
|   static String scrollEventJs = ''' |  | ||||||
|   // window.onscroll = function() { |  | ||||||
|   //    // 获取垂直滚动位置 |  | ||||||
|   //    var scrollTop = window.scrollY; |  | ||||||
|   //    window.chrome.webview.postMessage({"scroll": 1 ,"y": scrollTop }); |  | ||||||
|   // }; |  | ||||||
|   // 轮询检查元素是否存在 |  | ||||||
|   // const checkExist = setInterval(function() { |  | ||||||
|   //   const contentWrap = document.querySelector('content'); |  | ||||||
|   //   const clList = document.querySelector('cl-list'); |  | ||||||
|   //   console.log('轮询'); |  | ||||||
|   //   if (contentWrap && clList) { |  | ||||||
|   //     clearInterval(checkExist); // 停止轮询 |  | ||||||
|   //     console.log('停止轮询'); |  | ||||||
|   //     contentWrap.addEventListener('scroll', function() { |  | ||||||
|   //       console.log('contentWrap position:', element.scrollTop); |  | ||||||
|   //     }); |  | ||||||
|   //     clList.addEventListener('scroll', function() { |  | ||||||
|   //       console.log('clList position:', element.scrollTop); |  | ||||||
|   //     }); |  | ||||||
|   //   } |  | ||||||
|   // }, 500); // 每500毫秒检查一次 |  | ||||||
| 
 |  | ||||||
|   '''; |  | ||||||
| 
 |  | ||||||
|   /// 滚动到 |  | ||||||
|   static String scrollTo(int value){ |  | ||||||
|     return ''' |  | ||||||
|     window.scrollTo({ |  | ||||||
|     top: $value, |  | ||||||
|     behavior: 'smooth'  // 可选,设置滚动行为为平滑滚动 |  | ||||||
|     }); |  | ||||||
|     '''; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 模拟点击 |  | ||||||
|   static String clickJs(int x, int y) { |  | ||||||
|     return 'document.elementFromPoint($x, $y).click();'; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   /// 输入 |  | ||||||
|   static String inputJs(int value) { |  | ||||||
|     return ''' |  | ||||||
|       console.log('输入赋值'); |  | ||||||
|       var inputEvent = new Event('input', { |  | ||||||
|         bubbles: true, |  | ||||||
|         cancelable: true, |  | ||||||
|       }); |  | ||||||
|       var inputElement = document.querySelector(".bet-money"); |  | ||||||
|       inputElement.value = "$value"; |  | ||||||
|       inputElement.dispatchEvent(inputEvent); |  | ||||||
|        |  | ||||||
|       // var inputElements = document.querySelectorAll(".bet-money"); |  | ||||||
|       // inputElements.forEach(function(element) { |  | ||||||
|       //   var inputEvent = new Event('input', { |  | ||||||
|       //     bubbles: true, |  | ||||||
|       //     cancelable: true, |  | ||||||
|       //   }); |  | ||||||
|       //   element.value = "$value"; |  | ||||||
|       //   element.dispatchEvent(inputEvent); |  | ||||||
|       // }); |  | ||||||
|       // const contentWrap = document.querySelector('content'); |  | ||||||
|       // const clList = document.querySelector('cl-list'); |  | ||||||
|       // console.log(contentWrap, clList); |  | ||||||
|     '''; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   /// 监听加载,在加载完成后缩放 |  | ||||||
|   static String onloadZoom(int zoom){ |  | ||||||
|     assert(zoom >= 1 && zoom <= 100, 'zoom 1 到 100'); |  | ||||||
|     return ''' |  | ||||||
| window.onload = function () { |  | ||||||
|   var currentUrl = window.location.href; |  | ||||||
|   if (currentUrl.endsWith('game/')) { |  | ||||||
|      ${WindowsJs.zoom(zoom)} |  | ||||||
|   } |  | ||||||
| }; |  | ||||||
| '''; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   /// 修改缩放 |  | ||||||
|   static String zoom(int zoom){ |  | ||||||
|     assert(zoom >= 1 && zoom <= 100, 'zoom 1 到 100'); |  | ||||||
|     return ''' |  | ||||||
|       document.body.style.zoom = "$zoom%"; |  | ||||||
|     '''; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   static String message = 'window.chrome.webview.postMessage({x:3333});'; |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,97 +0,0 @@ | ||||||
| import 'package:bitsdojo_window/bitsdojo_window.dart'; |  | ||||||
| import 'package:flutter/material.dart'; |  | ||||||
| import 'package:web_synchronization_tool/windows/socket_tool.dart'; |  | ||||||
| import 'package:web_synchronization_tool/windows/web_grid_view.dart'; |  | ||||||
| import 'package:webview_windows/webview_windows.dart'; |  | ||||||
| import 'package:window_manager/window_manager.dart'; |  | ||||||
| 
 |  | ||||||
| class WindowsPage extends StatefulWidget { |  | ||||||
|   const WindowsPage({super.key}); |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   State<WindowsPage> createState() => _WindowsPageState(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class _WindowsPageState extends State<WindowsPage> { |  | ||||||
|   Widget? windowsWebWidget; |  | ||||||
|   WebviewController mainController = WebviewController(); |  | ||||||
|   final gridController = WebGridController(); |  | ||||||
| 
 |  | ||||||
|   bool initDone = false; |  | ||||||
| 
 |  | ||||||
|   String clickId = ''; |  | ||||||
|   String zoomId = ''; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   void initState() { |  | ||||||
|     super.initState(); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     initWindow(); |  | ||||||
|     controllerInit(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   initWindow(){ |  | ||||||
|     //允许调整窗口大小 |  | ||||||
|     windowManager.setResizable(false); |  | ||||||
| 
 |  | ||||||
|     const double width = 1920; |  | ||||||
|     const double height = 1000; |  | ||||||
|     //设置最小大小 |  | ||||||
|     const windowSize = Size(width, height); |  | ||||||
|     windowManager.setSize(windowSize); |  | ||||||
|     appWindow.minSize = windowSize; |  | ||||||
|     windowManager.center(); |  | ||||||
|     windowManager.focus(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|   Future controllerInit() async { |  | ||||||
|     await mainController.initialize(); |  | ||||||
| 
 |  | ||||||
|     mainController.loadUrl('http://www.df6831.com/'); |  | ||||||
| 
 |  | ||||||
|     gridController.addMainController(mainController); |  | ||||||
| 
 |  | ||||||
|     setState(() { |  | ||||||
|       initDone = true; |  | ||||||
|     }); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
|     return Scaffold( |  | ||||||
|       body: WebGridWidget( |  | ||||||
|         controller: gridController, |  | ||||||
|       ), |  | ||||||
|       floatingActionButton: Row( |  | ||||||
|         mainAxisAlignment: MainAxisAlignment.end, |  | ||||||
|         children: [ |  | ||||||
|           FloatingActionButton( |  | ||||||
|             onPressed: (){ |  | ||||||
|               gridController.addWeb(); |  | ||||||
|             }, |  | ||||||
|             heroTag: 1, |  | ||||||
|             tooltip: '添加网页', |  | ||||||
|             child: const Icon(Icons.add), |  | ||||||
|           ), |  | ||||||
|           const SizedBox(width: 20,) |  | ||||||
|           , |  | ||||||
|           FloatingActionButton( |  | ||||||
|             onPressed: (){ |  | ||||||
|               gridController.addAllWeb(); |  | ||||||
|             }, |  | ||||||
|             heroTag: 2, |  | ||||||
|             tooltip: '添加10个网页', |  | ||||||
|             child: const Row( |  | ||||||
|               children: [Icon(Icons.add),Text('10')], |  | ||||||
|             ), |  | ||||||
|           ), |  | ||||||
|         ], |  | ||||||
|       ), |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,30 +0,0 @@ | ||||||
| import 'package:flutter/material.dart'; |  | ||||||
| import 'package:webview_windows/webview_windows.dart'; |  | ||||||
| 
 |  | ||||||
| class WindowsWebWidget extends StatefulWidget { |  | ||||||
|   WindowsWebWidget({super.key, required this.controller}); |  | ||||||
|   final WebviewController controller; |  | ||||||
|   @override |  | ||||||
|   State<WindowsWebWidget> createState() => _WindowsWebWidgetState(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class _WindowsWebWidgetState extends State<WindowsWebWidget> { |  | ||||||
| 
 |  | ||||||
|   Webview? webview; |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   void initState() { |  | ||||||
|     super.initState(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
|     return inWindowsWebView(); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   Widget inWindowsWebView(){ |  | ||||||
|     webview ??= Webview(widget.controller); |  | ||||||
|     return webview!; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
							
								
								
									
										10
									
								
								pubspec.yaml
								
								
								
								
							
							
						
						
									
										10
									
								
								pubspec.yaml
								
								
								
								
							|  | @ -11,13 +11,9 @@ dependencies: | ||||||
|   flutter: |   flutter: | ||||||
|     sdk: flutter |     sdk: flutter | ||||||
| 
 | 
 | ||||||
|   common: |   cupertino_icons: ^1.0.2 | ||||||
|     path: E:\Code\FlutterProjectCode\common |   flutter_inappwebview: ^6.0.0 | ||||||
|   webview_windows: |   webview_dart: ^1.0.1 | ||||||
|     path: ../flutter-webview-windows-main |  | ||||||
|   bitsdojo_window: ^0.1.6 |  | ||||||
|   window_manager: ^0.3.7 |  | ||||||
|   device_info_plus: ^9.1.2 |  | ||||||
| 
 | 
 | ||||||
| dev_dependencies: | dev_dependencies: | ||||||
|   flutter_test: |   flutter_test: | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue