Merge pull request #1429 from 21pages/optimize

Optimize cm display behavior
This commit is contained in:
RustDesk 2022-09-02 11:30:45 +08:00 committed by GitHub
commit 5a8fc529ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 150 additions and 66 deletions

View File

@ -20,7 +20,8 @@ class ConnectionTabPage extends StatefulWidget {
} }
class _ConnectionTabPageState extends State<ConnectionTabPage> { class _ConnectionTabPageState extends State<ConnectionTabPage> {
final tabController = Get.put(DesktopTabController()); final tabController =
Get.put(DesktopTabController(tabType: DesktopTabType.remoteScreen));
static const IconData selectedIcon = Icons.desktop_windows_sharp; static const IconData selectedIcon = Icons.desktop_windows_sharp;
static const IconData unselectedIcon = Icons.desktop_windows_outlined; static const IconData unselectedIcon = Icons.desktop_windows_outlined;
@ -60,6 +61,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
if (call.method == "new_remote_desktop") { if (call.method == "new_remote_desktop") {
final args = jsonDecode(call.arguments); final args = jsonDecode(call.arguments);
final id = args['id']; final id = args['id'];
ConnectionTypeState.init(id);
window_on_top(windowId()); window_on_top(windowId());
ConnectionTypeState.init(id); ConnectionTypeState.init(id);
tabController.add(TabInfo( tabController.add(TabInfo(
@ -94,7 +96,6 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
body: Obx(() => DesktopTab( body: Obx(() => DesktopTab(
controller: tabController, controller: tabController,
theme: theme, theme: theme,
tabType: DesktopTabType.remoteScreen,
showTabBar: fullscreen.isFalse, showTabBar: fullscreen.isFalse,
onClose: () { onClose: () {
tabController.clear(); tabController.clear();

View File

@ -15,7 +15,7 @@ class DesktopTabPage extends StatefulWidget {
} }
class _DesktopTabPageState extends State<DesktopTabPage> { class _DesktopTabPageState extends State<DesktopTabPage> {
final tabController = DesktopTabController(); final tabController = DesktopTabController(tabType: DesktopTabType.main);
@override @override
void initState() { void initState() {
@ -46,7 +46,6 @@ class _DesktopTabPageState extends State<DesktopTabPage> {
body: DesktopTab( body: DesktopTab(
controller: tabController, controller: tabController,
theme: dark ? TarBarTheme.dark() : TarBarTheme.light(), theme: dark ? TarBarTheme.dark() : TarBarTheme.light(),
tabType: DesktopTabType.main,
tail: ActionIcon( tail: ActionIcon(
message: 'Settings', message: 'Settings',
icon: IconFont.menu, icon: IconFont.menu,

View File

@ -25,7 +25,7 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
static final IconData unselectedIcon = Icons.file_copy_outlined; static final IconData unselectedIcon = Icons.file_copy_outlined;
_FileManagerTabPageState(Map<String, dynamic> params) { _FileManagerTabPageState(Map<String, dynamic> params) {
Get.put(DesktopTabController()); Get.put(DesktopTabController(tabType: DesktopTabType.fileTransfer));
tabController.add(TabInfo( tabController.add(TabInfo(
key: params['id'], key: params['id'],
label: params['id'], label: params['id'],
@ -74,7 +74,6 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
body: DesktopTab( body: DesktopTab(
controller: tabController, controller: tabController,
theme: theme, theme: theme,
tabType: DesktopTabType.fileTransfer,
onClose: () { onClose: () {
tabController.clear(); tabController.clear();
}, },

View File

@ -18,7 +18,7 @@ class PortForwardTabPage extends StatefulWidget {
} }
class _PortForwardTabPageState extends State<PortForwardTabPage> { class _PortForwardTabPageState extends State<PortForwardTabPage> {
final tabController = Get.put(DesktopTabController()); late final DesktopTabController tabController;
late final bool isRDP; late final bool isRDP;
static const IconData selectedIcon = Icons.forward_sharp; static const IconData selectedIcon = Icons.forward_sharp;
@ -26,6 +26,8 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
_PortForwardTabPageState(Map<String, dynamic> params) { _PortForwardTabPageState(Map<String, dynamic> params) {
isRDP = params['isRDP']; isRDP = params['isRDP'];
tabController = Get.put(DesktopTabController(
tabType: isRDP ? DesktopTabType.rdp : DesktopTabType.portForward));
tabController.add(TabInfo( tabController.add(TabInfo(
key: params['id'], key: params['id'],
label: params['id'], label: params['id'],
@ -78,7 +80,6 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
body: DesktopTab( body: DesktopTab(
controller: tabController, controller: tabController,
theme: theme, theme: theme,
tabType: isRDP ? DesktopTabType.rdp : DesktopTabType.portForward,
onClose: () { onClose: () {
tabController.clear(); tabController.clear();
}, },

View File

@ -19,10 +19,12 @@ class DesktopServerPage extends StatefulWidget {
class _DesktopServerPageState extends State<DesktopServerPage> class _DesktopServerPageState extends State<DesktopServerPage>
with WindowListener, AutomaticKeepAliveClientMixin { with WindowListener, AutomaticKeepAliveClientMixin {
final tabController = gFFI.serverModel.tabController;
@override @override
void initState() { void initState() {
gFFI.ffiModel.updateEventListener(""); gFFI.ffiModel.updateEventListener("");
windowManager.addListener(this); windowManager.addListener(this);
tabController.onRemove = (_, id) => onRemoveId(id);
super.initState(); super.initState();
} }
@ -39,6 +41,13 @@ class _DesktopServerPageState extends State<DesktopServerPage>
super.onWindowClose(); super.onWindowClose();
} }
void onRemoveId(String id) {
if (tabController.state.value.tabs.isEmpty) {
windowManager.close();
}
}
@override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
return MultiProvider( return MultiProvider(
@ -49,11 +58,13 @@ class _DesktopServerPageState extends State<DesktopServerPage>
child: Consumer<ServerModel>( child: Consumer<ServerModel>(
builder: (context, serverModel, child) => Container( builder: (context, serverModel, child) => Container(
decoration: BoxDecoration( decoration: BoxDecoration(
border: border: Border.all(color: MyTheme.color(context).border!)),
Border.all(color: MyTheme.color(context).border!)),
child: Scaffold( child: Scaffold(
backgroundColor: MyTheme.color(context).bg, backgroundColor: MyTheme.color(context).bg,
body: Center( body: Overlay(initialEntries: [
OverlayEntry(builder: (context) {
gFFI.dialogManager.setOverlayState(Overlay.of(context));
return Center(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
@ -61,9 +72,10 @@ class _DesktopServerPageState extends State<DesktopServerPage>
SizedBox.fromSize(size: Size(0, 15.0)), SizedBox.fromSize(size: Size(0, 15.0)),
], ],
), ),
), );
), })
))); ]),
))));
} }
@override @override
@ -109,9 +121,9 @@ class ConnectionManagerState extends State<ConnectionManager> {
theme: isDarkTheme() ? TarBarTheme.dark() : TarBarTheme.light(), theme: isDarkTheme() ? TarBarTheme.dark() : TarBarTheme.light(),
showTitle: false, showTitle: false,
showMaximize: false, showMaximize: false,
showMinimize: false, showMinimize: true,
showClose: true,
controller: serverModel.tabController, controller: serverModel.tabController,
tabType: DesktopTabType.cm,
pageViewBuilder: (pageView) => Row(children: [ pageViewBuilder: (pageView) => Row(children: [
Expanded(child: pageView), Expanded(child: pageView),
Consumer<ChatModel>( Consumer<ChatModel>(
@ -450,8 +462,10 @@ class _CmControlPanel extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: MyTheme.accent, borderRadius: BorderRadius.circular(10)), color: MyTheme.accent, borderRadius: BorderRadius.circular(10)),
child: InkWell( child: InkWell(
onTap: () => onTap: () => checkClickTime(client.id, () {
checkClickTime(client.id, () => handleAccept(context)), handleAccept(context);
windowManager.minimize();
}),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [

View File

@ -59,13 +59,15 @@ class DesktopTabState {
class DesktopTabController { class DesktopTabController {
final state = DesktopTabState().obs; final state = DesktopTabState().obs;
final DesktopTabType tabType;
/// index, key /// index, key
Function(int, String)? onRemove; Function(int, String)? onRemove;
Function(int)? onSelected; Function(int)? onSelected;
void add(TabInfo tab) { DesktopTabController({required this.tabType});
void add(TabInfo tab, {bool authorized = false}) {
if (!isDesktop) return; if (!isDesktop) return;
final index = state.value.tabs.indexWhere((e) => e.key == tab.key); final index = state.value.tabs.indexWhere((e) => e.key == tab.key);
int toIndex; int toIndex;
@ -79,6 +81,16 @@ class DesktopTabController {
toIndex = state.value.tabs.length - 1; toIndex = state.value.tabs.length - 1;
assert(toIndex >= 0); assert(toIndex >= 0);
} }
if (tabType == DesktopTabType.cm) {
Future.delayed(Duration.zero, () async {
window_on_top(null);
});
if (authorized) {
Future.delayed(const Duration(seconds: 3), () {
windowManager.minimize();
});
}
}
try { try {
jumpTo(toIndex); jumpTo(toIndex);
} catch (e) { } catch (e) {
@ -106,6 +118,7 @@ class DesktopTabController {
} }
void jumpTo(int index) { void jumpTo(int index) {
if (!isDesktop || index < 0) return;
state.update((val) { state.update((val) {
val!.selected = index; val!.selected = index;
Future.delayed(Duration.zero, (() { Future.delayed(Duration.zero, (() {
@ -114,13 +127,15 @@ class DesktopTabController {
} }
if (val.scrollController.hasClients && if (val.scrollController.hasClients &&
val.scrollController.canScroll && val.scrollController.canScroll &&
val.scrollController.itemCount >= index) { val.scrollController.itemCount > index) {
val.scrollController.scrollToItem(index, center: true, animate: true); val.scrollController.scrollToItem(index, center: true, animate: true);
} }
})); }));
}); });
if (state.value.tabs.length > index) {
onSelected?.call(index); onSelected?.call(index);
} }
}
void closeBy(String? key) { void closeBy(String? key) {
if (!isDesktop) return; if (!isDesktop) return;
@ -154,8 +169,6 @@ typedef LabelGetter = Rx<String> Function(String key);
class DesktopTab extends StatelessWidget { class DesktopTab extends StatelessWidget {
final Function(String)? onTabClose; final Function(String)? onTabClose;
final TarBarTheme theme; final TarBarTheme theme;
final DesktopTabType tabType;
final bool isMainWindow;
final bool showTabBar; final bool showTabBar;
final bool showLogo; final bool showLogo;
final bool showTitle; final bool showTitle;
@ -170,10 +183,12 @@ class DesktopTab extends StatelessWidget {
final DesktopTabController controller; final DesktopTabController controller;
Rx<DesktopTabState> get state => controller.state; Rx<DesktopTabState> get state => controller.state;
late final DesktopTabType tabType;
late final bool isMainWindow;
const DesktopTab({ DesktopTab({
Key? key,
required this.controller, required this.controller,
required this.tabType,
this.theme = const TarBarTheme.light(), this.theme = const TarBarTheme.light(),
this.onTabClose, this.onTabClose,
this.showTabBar = true, this.showTabBar = true,
@ -187,8 +202,11 @@ class DesktopTab extends StatelessWidget {
this.onClose, this.onClose,
this.tabBuilder, this.tabBuilder,
this.labelGetter, this.labelGetter,
}) : isMainWindow = }) : super(key: key) {
tabType = controller.tabType;
isMainWindow =
tabType == DesktopTabType.main || tabType == DesktopTabType.cm; tabType == DesktopTabType.main || tabType == DesktopTabType.cm;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -314,6 +332,8 @@ class DesktopTab extends StatelessWidget {
Offstage(offstage: tail == null, child: tail), Offstage(offstage: tail == null, child: tail),
WindowActionPanel( WindowActionPanel(
mainTab: isMainWindow, mainTab: isMainWindow,
tabType: tabType,
state: state,
theme: theme, theme: theme,
showMinimize: showMinimize, showMinimize: showMinimize,
showMaximize: showMaximize, showMaximize: showMaximize,
@ -327,6 +347,8 @@ class DesktopTab extends StatelessWidget {
class WindowActionPanel extends StatelessWidget { class WindowActionPanel extends StatelessWidget {
final bool mainTab; final bool mainTab;
final DesktopTabType tabType;
final Rx<DesktopTabState> state;
final TarBarTheme theme; final TarBarTheme theme;
final bool showMinimize; final bool showMinimize;
@ -337,6 +359,8 @@ class WindowActionPanel extends StatelessWidget {
const WindowActionPanel( const WindowActionPanel(
{Key? key, {Key? key,
required this.mainTab, required this.mainTab,
required this.tabType,
required this.state,
required this.theme, required this.theme,
this.showMinimize = true, this.showMinimize = true,
this.showMaximize = true, this.showMaximize = true,
@ -411,7 +435,8 @@ class WindowActionPanel extends StatelessWidget {
message: 'Close', message: 'Close',
icon: IconFont.close, icon: IconFont.close,
theme: theme, theme: theme,
onTap: () { onTap: () async {
action() {
if (mainTab) { if (mainTab) {
windowManager.close(); windowManager.close();
} else { } else {
@ -421,12 +446,42 @@ class WindowActionPanel extends StatelessWidget {
}); });
} }
onClose?.call(); onClose?.call();
}
if (tabType != DesktopTabType.main &&
state.value.tabs.length > 1) {
closeConfirmDialog(action);
} else {
action();
}
}, },
is_close: true, is_close: true,
)), )),
], ],
); );
} }
closeConfirmDialog(Function() callback) async {
final res = await gFFI.dialogManager
.show<bool>((setState, close) => CustomAlertDialog(
title: Row(children: [
Icon(Icons.warning_amber_sharp,
color: Colors.redAccent, size: 28),
SizedBox(width: 10),
Text(translate("Warning")),
]),
content: Text(translate("Disconnect all devices?")),
actions: [
TextButton(
onPressed: () => close(), child: Text(translate("Cancel"))),
ElevatedButton(
onPressed: () => close(true), child: Text(translate("OK"))),
],
));
if (res == true) {
callback();
}
}
} }
// ignore: must_be_immutable // ignore: must_be_immutable

View File

@ -165,6 +165,7 @@ void runConnectionManagerScreen() async {
await windowManager.setAlignment(Alignment.topRight); await windowManager.setAlignment(Alignment.topRight);
await windowManager.show(); await windowManager.show();
await windowManager.focus(); await windowManager.focus();
await windowManager.setAlignment(Alignment.topRight); // ensure
}) })
]); ]);
runApp(GetMaterialApp( runApp(GetMaterialApp(

View File

@ -59,6 +59,7 @@ class ChatPage extends StatelessWidget implements PageShape {
messages: chatModel messages: chatModel
.messages[chatModel.currentID]?.chatMessages ?? .messages[chatModel.currentID]?.chatMessages ??
[], [],
inputOptions: const InputOptions(sendOnEnter: true),
messageOptions: MessageOptions( messageOptions: MessageOptions(
showOtherUsersAvatar: false, showOtherUsersAvatar: false,
showTime: true, showTime: true,

View File

@ -209,10 +209,19 @@ class ChatModel with ChangeNotifier {
id: await bind.mainGetLastRemoteId(), id: await bind.mainGetLastRemoteId(),
); );
} else { } else {
final client = _ffi.target?.serverModel.clients[id]; final client = _ffi.target?.serverModel.clients
.firstWhere((client) => client.id == id);
if (client == null) { if (client == null) {
return debugPrint("Failed to receive msg,user doesn't exist"); return debugPrint("Failed to receive msg,user doesn't exist");
} }
if (isDesktop) {
window_on_top(null);
var index = _ffi.target?.serverModel.clients
.indexWhere((client) => client.id == id);
if (index != null && index >= 0) {
gFFI.serverModel.tabController.jumpTo(index);
}
}
chatUser = ChatUser(id: client.peerId, firstName: client.name); chatUser = ChatUser(id: client.peerId, firstName: client.name);
} }

View File

@ -32,7 +32,7 @@ class ServerModel with ChangeNotifier {
late final TextEditingController _serverId; late final TextEditingController _serverId;
final _serverPasswd = TextEditingController(text: ""); final _serverPasswd = TextEditingController(text: "");
final tabController = DesktopTabController(); final tabController = DesktopTabController(tabType: DesktopTabType.cm);
List<Client> _clients = []; List<Client> _clients = [];
@ -347,20 +347,18 @@ class ServerModel with ChangeNotifier {
var res = await bind.mainGetClientsState(); var res = await bind.mainGetClientsState();
try { try {
final List clientsJson = jsonDecode(res); final List clientsJson = jsonDecode(res);
if (isDesktop && clientsJson.isEmpty && _clients.isNotEmpty) {
// exit cm when >1 peers to no peers
exit(0);
}
_clients.clear(); _clients.clear();
tabController.state.value.tabs.clear(); tabController.state.value.tabs.clear();
for (var clientJson in clientsJson) { for (var clientJson in clientsJson) {
final client = Client.fromJson(clientJson); final client = Client.fromJson(clientJson);
_clients.add(client); _clients.add(client);
tabController.add(TabInfo( tabController.add(
TabInfo(
key: client.id.toString(), key: client.id.toString(),
label: client.name, label: client.name,
closable: false, closable: false,
page: Desktop.buildConnectionCard(client))); page: Desktop.buildConnectionCard(client)),
authorized: client.authorized);
} }
notifyListeners(); notifyListeners();
} catch (e) { } catch (e) {
@ -471,14 +469,18 @@ class ServerModel with ChangeNotifier {
} else { } else {
_clients[index].authorized = true; _clients[index].authorized = true;
} }
tabController.add(TabInfo( tabController.add(
TabInfo(
key: client.id.toString(), key: client.id.toString(),
label: client.name, label: client.name,
closable: false, closable: false,
page: Desktop.buildConnectionCard(client))); page: Desktop.buildConnectionCard(client)),
authorized: true);
scrollToBottom(); scrollToBottom();
notifyListeners(); notifyListeners();
} catch (e) {} } catch (e) {
debugPrint("onClientAuthorized:$e");
}
} }
void onClientRemove(Map<String, dynamic> evt) { void onClientRemove(Map<String, dynamic> evt) {
@ -486,8 +488,10 @@ class ServerModel with ChangeNotifier {
final id = int.parse(evt['id'] as String); final id = int.parse(evt['id'] as String);
if (_clients.any((c) => c.id == id)) { if (_clients.any((c) => c.id == id)) {
final index = _clients.indexWhere((client) => client.id == id); final index = _clients.indexWhere((client) => client.id == id);
if (index >= 0) {
_clients.removeAt(index); _clients.removeAt(index);
tabController.remove(index); tabController.remove(index);
}
parent.target?.dialogManager.dismissByTag(getLoginDialogTag(id)); parent.target?.dialogManager.dismissByTag(getLoginDialogTag(id));
parent.target?.invokeMethod("cancel_notification", id); parent.target?.invokeMethod("cancel_notification", id);
} }