From abf35ac5c3d7a7eca0b3a9f9adb4f6d17242ea12 Mon Sep 17 00:00:00 2001 From: csf Date: Sat, 19 Mar 2022 23:28:29 +0800 Subject: [PATCH] optimize cm for android service --- .../com/carriez/flutter_hbb/MainService.kt | 23 +-- lib/models/model.dart | 126 +++------------ lib/models/server_model.dart | 139 +++++++++++++++++ lib/pages/file_manager_page.dart | 2 +- lib/pages/remote_page.dart | 2 +- lib/pages/server_page.dart | 145 +++++++----------- 6 files changed, 216 insertions(+), 221 deletions(-) create mode 100644 lib/models/server_model.dart diff --git a/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt b/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt index e7701d0e4..457080c3e 100644 --- a/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt +++ b/android/app/src/main/kotlin/com/carriez/flutter_hbb/MainService.kt @@ -95,42 +95,21 @@ class MainService : Service() { fun rustSetByName(name: String, arg1: String, arg2: String) { when (name) { "try_start_without_auth" -> { - // TODO 改成 json 三个参数 类型 name id - // to UI - Log.d(logTag, "from rust:got try_start_without_auth") - Handler(Looper.getMainLooper()).post { - MainActivity.flutterMethodChannel.invokeMethod( - name, - mapOf("peerID" to arg1, "name" to arg2) - ) - Log.d(logTag, "activity.runOnUiThread invokeMethod try_start_without_auth,done") - } // TODO notify + } "start_capture" -> { Log.d(logTag, "from rust:start_capture") - Handler(Looper.getMainLooper()).post { - MainActivity.flutterMethodChannel.invokeMethod( - name, - mapOf("peerID" to arg1, "name" to arg2) - ) - Log.d(logTag, "activity.runOnUiThread invokeMethod start_capture,done") - } if (isStart) { Log.d(logTag, "正在录制") return } - // 1.开始捕捉音视频 2.通知栏 startCapture() // TODO notify } "stop_capture" -> { Log.d(logTag, "from rust:stop_capture") stopCapture() - Handler(Looper.getMainLooper()).post { - MainActivity.flutterMethodChannel.invokeMethod(name, null) - Log.d(logTag, "activity.runOnUiThread invokeMethod stop_capture,done") - } } else -> {} } diff --git a/lib/models/model.dart b/lib/models/model.dart index 42f2c0c49..2db0dbaa7 100644 --- a/lib/models/model.dart +++ b/lib/models/model.dart @@ -2,6 +2,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_hbb/models/chat_model.dart'; import 'package:flutter_hbb/models/file_model.dart'; +import 'package:flutter_hbb/models/server_model.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'dart:math'; import 'dart:convert'; @@ -13,6 +14,8 @@ import 'dart:async'; import '../common.dart'; import 'native_model.dart' if (dart.library.html) 'web_model.dart'; +typedef HandleMsgBox = void Function(Map evt, String id); + class FfiModel with ChangeNotifier { PeerInfo _pi = PeerInfo(); Display _display = Display(); @@ -100,23 +103,17 @@ class FfiModel with ChangeNotifier { _permissions.clear(); } - void update( - String id, - BuildContext context, - void Function( - Map evt, - String id, - ) - handleMsgBox) { + void update(String peerId,HandleMsgBox handleMsgBox) { var pos; for (;;) { var evt = FFI.popEvent(); if (evt == null) break; var name = evt['name']; + debugPrint("got message:$name"); if (name == 'msgbox') { - handleMsgBox(evt, id); + handleMsgBox(evt, peerId); } else if (name == 'peer_info') { - handlePeerInfo(evt, context); + handlePeerInfo(evt); } else if (name == 'connection_ready') { FFI.ffiModel.setConnectionType( evt['secure'] == 'true', evt['direct'] == 'true'); @@ -135,14 +132,19 @@ class FfiModel with ChangeNotifier { } else if (name == 'chat') { FFI.chatModel.receive(evt['text'] ?? ""); } else if (name == 'file_dir') { - // FFI.fileModel.fileFetcher.tryCompleteTask(evt['value'],evt['is_local']); FFI.fileModel.receiveFileDir(evt); - } else if (name == 'job_progress'){ + } else if (name == 'job_progress') { FFI.fileModel.tryUpdateJobProgress(evt); - } else if (name == 'job_done'){ + } else if (name == 'job_done') { FFI.fileModel.jobDone(evt); - } else if (name == 'job_error'){ + } else if (name == 'job_error') { FFI.fileModel.jobError(evt); + } else if (name == 'try_start_without_auth') { + FFI.serverModel.loginRequest(evt); + } else if (name == 'on_client_logon') { + + } else if (name == 'on_client_remove') { + FFI.serverModel.onClientRemove(evt); } } if (pos != null) FFI.cursorModel.updateCursorPosition(pos); @@ -184,7 +186,7 @@ class FfiModel with ChangeNotifier { notifyListeners(); } - void handlePeerInfo(Map evt, BuildContext context) { + void handlePeerInfo(Map evt) { EasyLoading.dismiss(); DialogManager.reset(); _pi.version = evt['version']; @@ -195,9 +197,9 @@ class FfiModel with ChangeNotifier { _pi.currentDisplay = int.parse(evt['current_display']); _pi.homeDir = evt['home_dir']; - if(evt['is_file_transfer'] == "true"){ + if (evt['is_file_transfer'] == "true") { FFI.fileModel.onReady(); - }else{ + } else { _pi.displays = []; List displays = json.decode(evt['displays']); for (int i = 0; i < displays.length; ++i) { @@ -591,96 +593,6 @@ class CursorModel with ChangeNotifier { } } -class ClientState { - bool isStart = false; - bool isFileTransfer = false; - String name = ""; - String peerId = ""; - - ClientState(this.isStart, this.isFileTransfer, this.name, this.peerId); - - ClientState.fromJson(Map json) { - isStart = json['is_start']; - isFileTransfer = json['is_file_transfer']; - name = json['name']; - peerId = json['peer_id']; - } - - Map toJson() { - final Map data = new Map(); - data['is_start'] = this.isStart; - data['is_file_transfer'] = this.isFileTransfer; - data['name'] = this.name; - data['peer_id'] = this.peerId; - return data; - } -} - -class ServerModel with ChangeNotifier { - bool _mediaOk = false; - bool _inputOk = false; - bool _isPeerStart = false; - bool _isFileTransfer = false; - String _peerName = ""; - String _peerID = ""; - - bool get mediaOk => _mediaOk; - - bool get inputOk => _inputOk; - - bool get isPeerStart => _isPeerStart; - - bool get isFileTransfer => _isFileTransfer; - - String get peerName => _peerName; - - String get peerID => _peerID; - - ServerModel(); - - changeStatue(String name, bool value) { - switch (name) { - case "media": - _mediaOk = value; - break; - case "input": - _inputOk = value; - break; - default: - return; - } - notifyListeners(); - } - - setPeer(bool enabled, {String name = "", String id = ""}) { - _isPeerStart = enabled; - if (name != "") _peerName = name; - if (id != "") _peerID = id; - notifyListeners(); - } - - updateClientState() { - var res = FFI.getByName("client_state"); - debugPrint("getByName client_state string:$res"); - try { - var clientState = ClientState.fromJson(jsonDecode(res)); - _isPeerStart = clientState.isStart; - _isFileTransfer = clientState.isFileTransfer; - _peerName = clientState.name; - _peerID = clientState.peerId; - debugPrint("updateClientState:${clientState.toJson()}"); - } catch (e) {} - notifyListeners(); - } - - clearPeer() { - _isPeerStart = false; - _peerName = ""; - _peerID = ""; - notifyListeners(); - } -} - enum MouseButtons { left, right, wheel } extension ToString on MouseButtons { diff --git a/lib/models/server_model.dart b/lib/models/server_model.dart new file mode 100644 index 000000000..13ce9d67b --- /dev/null +++ b/lib/models/server_model.dart @@ -0,0 +1,139 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import '../common.dart'; +import '../pages/server_page.dart'; +import 'model.dart'; + +class ServerModel with ChangeNotifier { + bool _mediaOk = false; + bool _inputOk = false; + List _clients = []; + + bool get mediaOk => _mediaOk; + + bool get inputOk => _inputOk; + + List get clients => _clients; + + ServerModel(); + + changeStatue(String name, bool value) { + switch (name) { + case "media": + _mediaOk = value; + break; + case "input": + _inputOk = value; + break; + default: + return; + } + notifyListeners(); + } + + updateClientState() { + var res = FFI.getByName("clients_state"); + debugPrint("getByName clients_state string:$res"); + try { + final List clientsJson = jsonDecode(res); + _clients = clientsJson.map((clientJson) => Client.fromJson(jsonDecode(res))).toList(); + debugPrint("updateClientState:${_clients.toString()}"); + notifyListeners(); + } catch (e) {} + } + + loginRequest(Map evt){ + try{ + final client = Client.fromJson(jsonDecode(evt["client"])); + final Map response = Map(); + response["id"] = client.id; + DialogManager.show((setState, close) => CustomAlertDialog( + title: Text("Control Request"), + content: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(translate("Do you accept?")), + SizedBox(height: 20), + clientInfo(client), + ], + ), + actions: [ + TextButton( + child: Text(translate("Dismiss")), + onPressed: () { + response["res"] = false; + FFI.setByName("login_res", jsonEncode(response)); + close(); + }), + ElevatedButton( + child: Text(translate("Accept")), + onPressed: () async { + response["res"] = true; + FFI.setByName("login_res", jsonEncode(response)); + if (!client.isFileTransfer) { + bool res = await FFI.invokeMethod("start_capture"); // to Android service + debugPrint("_toAndroidStartCapture:$res"); + } + _clients.add(client); + notifyListeners(); + close(); + }), + + ])); + }catch (e){ + debugPrint("loginRequest failed,error:$e"); + } + } + + void onClientLogin(Map evt){ + + } + + void onClientRemove(Map evt) { + try{ + final id = int.parse(evt['id'] as String); + Client client = _clients.singleWhere((c) => c.id == id); + _clients.remove(client); + notifyListeners(); + }catch(e){ + debugPrint("onClientRemove failed,error:$e"); + } + } + + closeAll(){ + _clients.forEach((client) { + FFI.setByName("close_conn",client.id.toString()); + }); + } +} + +class Client { + int id = 0; // for client connections inner count id + bool authorized = false; + bool isFileTransfer = false; + String name = ""; + String peerId = ""; // for peer user's id,show at app + + Client(this.authorized, this.isFileTransfer, this.name, this.peerId); + + Client.fromJson(Map json) { + id = json['id']; + authorized = json['authorized']; + isFileTransfer = json['is_file_transfer']; + name = json['name']; + peerId = json['peer_id']; + } + + Map toJson() { + final Map data = new Map(); + data['id'] = this.id; + data['is_start'] = this.authorized; + data['is_file_transfer'] = this.isFileTransfer; + data['name'] = this.name; + data['peer_id'] = this.peerId; + return data; + } +} + diff --git a/lib/pages/file_manager_page.dart b/lib/pages/file_manager_page.dart index f39817d4e..aeaa9543b 100644 --- a/lib/pages/file_manager_page.dart +++ b/lib/pages/file_manager_page.dart @@ -32,7 +32,7 @@ class _FileManagerPageState extends State { FFI.connect(widget.id, isFileTransfer: true); _interval = Timer.periodic(Duration(milliseconds: 30), - (timer) => FFI.ffiModel.update(widget.id, context, handleMsgBox)); + (timer) => FFI.ffiModel.update(widget.id, handleMsgBox)); } @override diff --git a/lib/pages/remote_page.dart b/lib/pages/remote_page.dart index ae9e79d72..09ae6a4e0 100644 --- a/lib/pages/remote_page.dart +++ b/lib/pages/remote_page.dart @@ -86,7 +86,7 @@ class _RemotePageState extends State { } }); } - FFI.ffiModel.update(widget.id, context, handleMsgBox); + FFI.ffiModel.update(widget.id, handleMsgBox); } void interval() { diff --git a/lib/pages/server_page.dart b/lib/pages/server_page.dart index eb407bdac..dfd23da28 100644 --- a/lib/pages/server_page.dart +++ b/lib/pages/server_page.dart @@ -1,10 +1,10 @@ import 'dart:async'; import 'package:flutter/material.dart'; -import 'package:flutter_hbb/main.dart'; import 'package:flutter_hbb/models/model.dart'; import 'package:provider/provider.dart'; import '../common.dart'; +import '../models/server_model.dart'; import 'home_page.dart'; import '../models/model.dart'; @@ -70,6 +70,7 @@ class ServerInfo extends StatefulWidget { class _ServerInfoState extends State { var _passwdShow = false; + Timer? _interval; // TODO set ID / PASSWORD var _serverId = TextEditingController(text: ""); @@ -80,6 +81,13 @@ class _ServerInfoState extends State { void initState() { super.initState(); var id = FFI.getByName("server_id"); + + // TODO 需要重新优化开启监听 开启监听服务后再开始pop_event + FFI.setByName("ensure_init_event_queue"); + _interval = Timer.periodic(Duration(milliseconds: 30), + (timer) { + FFI.ffiModel.update("", (_, __) {});}); + _serverId.text = id == "" ? _emptyIdShow : id; _serverPasswd.text = FFI.getByName("server_password"); if (_serverId.text == _emptyIdShow || _serverPasswd.text == "") { @@ -87,6 +95,12 @@ class _ServerInfoState extends State { } } + @override + void dispose() { + _interval?.cancel(); + super.dispose(); + } + @override Widget build(BuildContext context) { return myCard(Column( @@ -189,66 +203,6 @@ class _PermissionCheckerState extends State { } } -Widget getConnInfo(String name, String peerID) { - return Row( - children: [ - CircleAvatar(child: Text(name[0]), backgroundColor: MyTheme.border), - SizedBox(width: 12), - Text(name, style: TextStyle(color: MyTheme.idColor)), - SizedBox(width: 8), - Text(peerID, style: TextStyle(color: MyTheme.idColor)) - ], - ); -} - -void showLoginReqAlert(String peerID, String name) async { - if (globalKey.currentContext == null) return; - await showDialog( - barrierDismissible: false, - context: globalKey.currentContext!, - builder: (alertContext) { - DialogManager.reset(); - DialogManager.register(alertContext); - return WillPopScope( - onWillPop: () async { - return false; - }, - child: AlertDialog( - title: Text("Control Request"), - content: Container( - height: 100, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(translate("Do you accept?")), - SizedBox(height: 20), - getConnInfo(name, peerID), - ], - )), - actions: [ - TextButton( - child: Text(translate("Dismiss")), - onPressed: () { - FFI.setByName("login_res", "false"); - DialogManager.reset(); - }), - ElevatedButton( - child: Text(translate("Accept")), - onPressed: () { - FFI.setByName("login_res", "true"); - if (!FFI.serverModel.isFileTransfer) { - _toAndroidStartCapture(); - } - FFI.serverModel.setPeer(true); - DialogManager.reset(); - }), - ], - )); - }); - DialogManager.drop(); -} - class PermissionRow extends StatelessWidget { PermissionRow(this.name, this.isOk, this.onPressed); @@ -291,28 +245,28 @@ class ConnectionManager extends StatelessWidget { @override Widget build(BuildContext context) { final serverModel = Provider.of(context); - return serverModel.isPeerStart - ? myCard(Column( + return Column( + children: serverModel.clients.map((client) => + myCard(Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - cardTitle(translate("Connection")), // TODO t + cardTitle(translate("Connection")), Padding( padding: EdgeInsets.symmetric(vertical: 5.0), - child: getConnInfo(serverModel.peerName, serverModel.peerID), + child: clientInfo(client), ), ElevatedButton.icon( style: ButtonStyle( backgroundColor: MaterialStateProperty.all(Colors.red)), icon: Icon(Icons.close), onPressed: () { - FFI.setByName("close_conn"); - // _toAndroidStopCapture(); - serverModel.setPeer(false); + FFI.setByName("close_conn",client.id.toString()); }, label: Text(translate("Close"))) ], )) - : SizedBox.shrink(); + ).toList() + ); } } @@ -342,16 +296,28 @@ Widget myCard(Widget child) { )); } +Widget clientInfo(Client client) { + return Row( + children: [ + CircleAvatar(child: Text(client.name[0]), backgroundColor: MyTheme.border), + SizedBox(width: 12), + Text(client.name, style: TextStyle(color: MyTheme.idColor)), + SizedBox(width: 8), + Text(client.peerId, style: TextStyle(color: MyTheme.idColor)) + ], + ); +} + Future _toAndroidInitService() async { bool res = await FFI.invokeMethod("init_service"); FFI.setByName("start_service"); debugPrint("_toAndroidInitService:$res"); } -Future _toAndroidStartCapture() async { - bool res = await FFI.invokeMethod("start_capture"); - debugPrint("_toAndroidStartCapture:$res"); -} +// Future _toAndroidStartCapture() async { +// bool res = await FFI.invokeMethod("start_capture"); +// debugPrint("_toAndroidStartCapture:$res"); +// } // Future _toAndroidStopCapture() async { // bool res = await FFI.invokeMethod("stop_capture"); @@ -359,8 +325,7 @@ Future _toAndroidStartCapture() async { // } Future _toAndroidStopService() async { - FFI.setByName("close_conn"); - FFI.serverModel.setPeer(false); + FFI.serverModel.closeAll(); bool res = await FFI.invokeMethod("stop_service"); FFI.setByName("stop_service"); @@ -415,27 +380,27 @@ void toAndroidChannelInit() { debugPrint("flutter got android msg,$method,$arguments"); try { switch (method) { - case "try_start_without_auth": - { - FFI.serverModel.updateClientState(); - debugPrint( - "pre show loginAlert:${FFI.serverModel.isFileTransfer.toString()}"); - showLoginReqAlert(FFI.serverModel.peerID, FFI.serverModel.peerName); - debugPrint("from jvm:try_start_without_auth done"); - break; - } + // case "try_start_without_auth": + // { + // FFI.serverModel.updateClientState(); + // debugPrint( + // "pre show loginAlert:${FFI.serverModel.isFileTransfer.toString()}"); + // showLoginReqAlert(FFI.serverModel.peerID, FFI.serverModel.peerName); + // debugPrint("from jvm:try_start_without_auth done"); + // break; + // } case "start_capture": { DialogManager.reset(); FFI.serverModel.updateClientState(); break; } - case "stop_capture": - { - DialogManager.reset(); - FFI.serverModel.setPeer(false); - break; - } + // case "stop_capture": + // { + // DialogManager.reset(); + // FFI.serverModel.setPeer(false); + // break; + // } case "on_permission_changed": { var name = arguments["name"] as String;