Compare commits

..

No commits in common. "99ab6695a95aaa6a6d3d53c0ab98551649d5c219" and "9ac74625236a0df15c05689c588164415eb93c71" have entirely different histories.

19 changed files with 158 additions and 1974 deletions

View File

@ -1,102 +1,20 @@
class JavaScriptString {
///
static String clickEventJSString =
static String clickEventkJSString =
'''document.addEventListener('click', function(event) {
var x = event.clientX;
var y = event.clientY;
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) {
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) {
return '''
@ -106,7 +24,7 @@ var inputEvent = new Event('input', {
cancelable: true,
});
var inputElement = document.querySelector(".input");
var inputElement = document.querySelector(".bet-money");
inputElement.value = "$value";

View File

@ -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);
});
}
}

View File

@ -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;
}
}

View File

@ -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,
),
),
),
),
],
);
}
}

View File

@ -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,
);
}
}

View File

@ -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:web_synchronization_tool/login/login_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();
});
import 'package:web_synchronization_tool/main_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
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;
}
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
@ -56,10 +17,7 @@ class _MyAppState extends State<MyApp> {
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
// home: const MainPage(),
home: const LoginPage(),
navigatorObservers: [FlutterSmartDialog.observer],
builder: FlutterSmartDialog.init(),
home: const MainPage(),
);
}
}

View File

@ -1,145 +1,116 @@
//
// import 'package:flutter/material.dart';
// import 'package:flutter_inappwebview/flutter_inappwebview.dart';
// import 'package:web_synchronization_tool/web_widget.dart';
//
// import 'JavaScriptString.dart';
//
// class MainPage extends StatefulWidget {
// const MainPage({super.key});
//
// @override
// State<MainPage> createState() => _MainPageState();
// }
//
// class _MainPageState extends State<MainPage> {
//
// late InAppWebViewController mainController;
// late InAppWebViewController controller;
//
// bool asyncState = false;
//
// @override
// void initState() {
// super.initState();
//
// }
//
// @override
// void dispose() {
// super.dispose();
//
// WebStorageManager.instance().deleteAllData();
// }
//
// ///
// addTouchendEventJS(){
//
// final clickJsUS = UserScript(groupName: 'touchend',source: JavaScriptString.touchendEventJSString, injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START);
// mainController.addUserScript(userScript: clickJsUS);
//
// mainController.addJavaScriptHandler(handlerName: 'touchend', callback: (args){
// if (asyncState){
// int x = double.parse(args.first.toString()).toInt();
// int y = double.parse(args.last.toString()).toInt();
// controller.evaluateJavascript(source: JavaScriptString.clickJSString(x, y) );
// // controller.evaluateJavascript(source: JavaScriptString.touchendJsString(x, y) );
// // controller.evaluateJavascript(source: JavaScriptString.getClassTouchendJsString(x, y) );
// }
// });
//
// }
//
// @override
// Widget build(BuildContext context) {
// return Scaffold(
// body: Column(
// crossAxisAlignment: CrossAxisAlignment.stretch,
// children: [
// Container(
// height: 50,
// color: Colors.white,
// padding: const EdgeInsets.symmetric(horizontal: 50),
// child: Row(
// children: [
// TextButton(
// onPressed: () {
// controller.evaluateJavascript(source: JavaScriptString.clickJSString(50, 100) );
// },
// child: const Text('模拟点击测试')),
// TextButton(
// onPressed: () {
// mainController.evaluateJavascript(source: JavaScriptString.inputJsString(45) );
// controller.evaluateJavascript(source: JavaScriptString.inputJsString(45) );
// },
// child: const Text('模拟输入测试')),
// Row(
// children: [
// const Text('同步'),
// Switch(value: asyncState, onChanged: (value){
// setState(() {
// asyncState = value;
// });
// })
// ],
// )
// ],
// ),
// ),
// Expanded(child: pageViewWidget()),
// ],
// ),
// );
// }
//
// Widget pageViewWidget() {
// return Row(
// children: <Widget>[
// Expanded(
// child: Container(
// color: Colors.yellow,
// child: KeepAlivePage(
// child: WebWidget(controlerCallBack: (_mainController) {
// mainController = _mainController;
//
// addTouchendEventJS();
//
// }),
// ),
// ),
// ),
// Expanded(
// child: Container(
// color: Colors.blue,
// child: KeepAlivePage(
// 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;
// }
// }
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:web_synchronization_tool/web_widget.dart';
import 'JavaScriptString.dart';
class MainPage extends StatefulWidget {
const MainPage({super.key});
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
late InAppWebViewController mainController;
late InAppWebViewController controller;
@override
void initState() {
super.initState();
}
///
addClickEventJS(){
final clickJsUS = UserScript(groupName: 'click',source: JavaScriptString.clickEventkJSString, injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START);
mainController.addUserScript(userScript: clickJsUS);
mainController.addJavaScriptHandler(handlerName: 'Click', callback: (args){
controller.evaluateJavascript(source: JavaScriptString.clickJSString(args.first, args.last) );
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Container(
height: 50,
color: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 50),
child: Row(
children: [
TextButton(
onPressed: () {
controller.evaluateJavascript(source: JavaScriptString.clickJSString(600, 280) );
},
child: const Text('模拟点击测试')),
TextButton(
onPressed: () {
mainController.evaluateJavascript(source: JavaScriptString.inputJsString(45) );
controller.evaluateJavascript(source: JavaScriptString.inputJsString(45) );
},
child: const Text('模拟输入测试')),
const SizedBox(
width: 50,
child: TextField(
keyboardType: TextInputType.number,
decoration: InputDecoration(prefixText: '网页数量'),
),
)
],
),
),
Expanded(child: pageViewWidget()),
],
),
);
}
Widget pageViewWidget() {
return PageView(
children: <Widget>[
KeepAlivePage(
child: WebWidget(controlerCallBack: (_mainController) {
mainController = _mainController;
addClickEventJS();
}),
),
KeepAlivePage(
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;
}
}

View File

@ -1,42 +1,31 @@
// import 'package:flutter/material.dart';
// import 'package:flutter_inappwebview/flutter_inappwebview.dart';
// import 'package:web_synchronization_tool/JavaScriptString.dart';
//
// class WebWidget extends StatefulWidget {
// WebWidget({super.key, required this.controlerCallBack});
//
// final Function(InAppWebViewController) controlerCallBack;
//
// @override
// State<WebWidget> createState() => _WebWidgetState();
// }
//
// class _WebWidgetState extends State<WebWidget> {
// @override
// void initState() {
// super.initState();
// }
//
// @override
// Widget build(BuildContext context) {
// return InAppWebView(
// initialUrlRequest:
// URLRequest(url: WebUri('http://www.df6831.com/mobile')),//
// initialSettings: InAppWebViewSettings(
// // initialScale: 180,
// loadWithOverviewMode: false,
// useWideViewPort: false,
// // preferredContentMode: UserPreferredContentMode.MOBILE,
// // cacheEnabled: false, //
// // clearSessionCache: true,//
// // databaseEnabled:false, //
// // domStorageEnabled: false,// dom
// incognito: true, //
// sharedCookiesEnabled: false, // Cookie
// ),
// onWebViewCreated: (_controller) {
// widget.controlerCallBack(_controller);
// },
// );
// }
// }
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:web_synchronization_tool/JavaScriptString.dart';
class WebWidget extends StatefulWidget {
WebWidget({super.key, required this.controlerCallBack});
final Function(InAppWebViewController) controlerCallBack;
@override
State<WebWidget> createState() => _WebWidgetState();
}
class _WebWidgetState extends State<WebWidget> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return InAppWebView(
initialUrlRequest:
URLRequest(url: WebUri('http://www.df6831.com/game/')),
initialSettings: InAppWebViewSettings(initialScale: 200,loadWithOverviewMode: false,useWideViewPort: false),
onWebViewCreated: (_controller) {
widget.controlerCallBack(_controller);
},
);
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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); // 0base之间的随机整数
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;
}
}

View File

@ -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(
// 01
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;
}
}

View File

@ -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;
}
}

View File

@ -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]));
}
}
}

View File

@ -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),
))
],
);
}
}

View File

@ -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});';
}

View File

@ -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')],
),
),
],
),
);
}
}

View File

@ -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!;
}
}

View File

@ -11,13 +11,9 @@ dependencies:
flutter:
sdk: flutter
common:
path: E:\Code\FlutterProjectCode\common
webview_windows:
path: ../flutter-webview-windows-main
bitsdojo_window: ^0.1.6
window_manager: ^0.3.7
device_info_plus: ^9.1.2
cupertino_icons: ^1.0.2
flutter_inappwebview: ^6.0.0
webview_dart: ^1.0.1
dev_dependencies:
flutter_test: