diff --git a/flutter/lib/desktop/pages/connection_tab_page.dart b/flutter/lib/desktop/pages/connection_tab_page.dart index 5bd7e2469..a86afb683 100644 --- a/flutter/lib/desktop/pages/connection_tab_page.dart +++ b/flutter/lib/desktop/pages/connection_tab_page.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:math'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; @@ -25,24 +24,23 @@ class _ConnectionTabPageState extends State with TickerProviderStateMixin { // refactor List when using multi-tab // this singleton is only for test - var connectionIds = RxList.empty(growable: true); - var initialIndex = 0; + RxList tabs = RxList.empty(growable: true); late Rx tabController; static final Rx _selected = 0.obs; + IconData icon = Icons.desktop_windows_sharp; var connectionMap = RxList.empty(growable: true); _ConnectionTabPageState(Map params) { if (params['id'] != null) { - connectionIds.add(params['id']); + tabs.add(TabInfo(label: params['id'], icon: icon)); } } @override void initState() { super.initState(); - tabController = - TabController(length: connectionIds.length, vsync: this).obs; + tabController = TabController(length: tabs.length, vsync: this).obs; rustDeskWinManager.setMethodHandler((call, fromWindowId) async { print( "call ${call.method} with args ${call.arguments} from window ${fromWindowId}"); @@ -51,23 +49,13 @@ class _ConnectionTabPageState extends State final args = jsonDecode(call.arguments); final id = args['id']; window_on_top(windowId()); - final indexOf = connectionIds.indexOf(id); - if (indexOf >= 0) { - initialIndex = indexOf; - tabController.value.animateTo(initialIndex, duration: Duration.zero); - } else { - connectionIds.add(id); - initialIndex = connectionIds.length - 1; - tabController.value = TabController( - length: connectionIds.length, - vsync: this, - initialIndex: initialIndex); - } - _selected.value = initialIndex; + DesktopTabBar.onAdd(this, tabController, tabs, _selected, + TabInfo(label: id, icon: icon)); } else if (call.method == "onDestroy") { - print("executing onDestroy hook, closing ${connectionIds}"); - connectionIds.forEach((id) { - final tag = '${id}'; + print( + "executing onDestroy hook, closing ${tabs.map((tab) => tab.label).toList()}"); + tabs.forEach((tab) { + final tag = '${tab.label}'; ffi(tag).close().then((_) { Get.delete(tag: tag); }); @@ -82,24 +70,21 @@ class _ConnectionTabPageState extends State return Scaffold( body: Column( children: [ - Obx(() => DesktopTabBar( - controller: tabController, - tabs: connectionIds - .map((e) => - TabInfo(label: e, icon: Icons.desktop_windows_sharp)) - .toList(), - onTabClose: onRemoveId, - selected: _selected, - dark: isDarkTheme(), - mainTab: false, - )), + DesktopTabBar( + controller: tabController, + tabs: tabs, + onTabClose: onRemoveId, + selected: _selected, + dark: isDarkTheme(), + mainTab: false, + ), Expanded( child: Obx(() => TabBarView( controller: tabController.value, - children: connectionIds - .map((e) => RemotePage( - key: ValueKey(e), - id: e, + children: tabs + .map((tab) => RemotePage( + key: ValueKey(tab.label), + id: tab.label, tabBarHeight: kDesktopRemoteTabBarHeight, )) //RemotePage(key: ValueKey(e), id: e)) .toList()))), @@ -109,15 +94,8 @@ class _ConnectionTabPageState extends State } void onRemoveId(String id) { - final indexOf = connectionIds.indexOf(id); - if (indexOf == -1) { - return; - } - connectionIds.removeAt(indexOf); - initialIndex = max(0, initialIndex - 1); - tabController.value = TabController( - length: connectionIds.length, vsync: this, initialIndex: initialIndex); - if (connectionIds.length == 0) { + DesktopTabBar.onClose(this, tabController, tabs, id); + if (tabs.length == 0) { WindowController.fromWindowId(windowId()).close(); } } diff --git a/flutter/lib/desktop/pages/desktop_tab_page.dart b/flutter/lib/desktop/pages/desktop_tab_page.dart index 02ef0fea3..24611e439 100644 --- a/flutter/lib/desktop/pages/desktop_tab_page.dart +++ b/flutter/lib/desktop/pages/desktop_tab_page.dart @@ -1,5 +1,3 @@ -import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/consts.dart'; @@ -36,15 +34,15 @@ class _DesktopTabPageState extends State return Scaffold( body: Column( children: [ - Obx((() => DesktopTabBar( - controller: tabController, - tabs: tabs.toList(), - onTabClose: onTabClose, - selected: _selected, - dark: isDarkTheme(), - mainTab: true, - onMenu: onTabbarMenu, - ))), + DesktopTabBar( + controller: tabController, + tabs: tabs, + onTabClose: onTabClose, + selected: _selected, + dark: isDarkTheme(), + mainTab: true, + onAddSetting: onAddSetting, + ), Obx((() => Expanded( child: TabBarView( controller: tabController.value, @@ -65,24 +63,11 @@ class _DesktopTabPageState extends State } void onTabClose(String label) { - tabs.removeWhere((tab) => tab.label == label); - tabController.value = TabController( - length: tabs.length, - vsync: this, - initialIndex: max(0, tabs.length - 1)); + DesktopTabBar.onClose(this, tabController, tabs, label); } - void onTabbarMenu() { - int index = tabs.indexWhere((tab) => tab.label == kTabLabelSettingPage); - if (index >= 0) { - tabController.value.animateTo(index, duration: Duration.zero); - _selected.value = index; - } else { - tabs.add(TabInfo(label: kTabLabelSettingPage, icon: Icons.settings)); - tabController.value = TabController( - length: tabs.length, vsync: this, initialIndex: tabs.length - 1); - tabController.value.animateTo(tabs.length - 1, duration: Duration.zero); - _selected.value = tabs.length - 1; - } + void onAddSetting() { + DesktopTabBar.onAdd(this, tabController, tabs, _selected, + TabInfo(label: kTabLabelSettingPage, icon: Icons.settings)); } } diff --git a/flutter/lib/desktop/pages/file_manager_tab_page.dart b/flutter/lib/desktop/pages/file_manager_tab_page.dart index c4348fad0..4c2dc3c5e 100644 --- a/flutter/lib/desktop/pages/file_manager_tab_page.dart +++ b/flutter/lib/desktop/pages/file_manager_tab_page.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:math'; import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:flutter/material.dart'; @@ -24,22 +23,21 @@ class _FileManagerTabPageState extends State with TickerProviderStateMixin { // refactor List when using multi-tab // this singleton is only for test - var connectionIds = List.empty(growable: true).obs; - var initialIndex = 0; + RxList tabs = List.empty(growable: true).obs; late Rx tabController; static final Rx _selected = 0.obs; + IconData icon = Icons.file_copy_sharp; _FileManagerTabPageState(Map params) { if (params['id'] != null) { - connectionIds.add(params['id']); + tabs.add(TabInfo(label: params['id'], icon: icon)); } } @override void initState() { super.initState(); - tabController = - TabController(length: connectionIds.length, vsync: this).obs; + tabController = TabController(length: tabs.length, vsync: this).obs; rustDeskWinManager.setMethodHandler((call, fromWindowId) async { print( "call ${call.method} with args ${call.arguments} from window ${fromWindowId}"); @@ -48,23 +46,13 @@ class _FileManagerTabPageState extends State final args = jsonDecode(call.arguments); final id = args['id']; window_on_top(windowId()); - final indexOf = connectionIds.indexOf(id); - if (indexOf >= 0) { - initialIndex = indexOf; - tabController.value.animateTo(initialIndex, duration: Duration.zero); - } else { - connectionIds.add(id); - initialIndex = connectionIds.length - 1; - tabController.value = TabController( - length: connectionIds.length, - initialIndex: initialIndex, - vsync: this); - } - _selected.value = initialIndex; + DesktopTabBar.onAdd(this, tabController, tabs, _selected, + TabInfo(label: id, icon: icon)); } else if (call.method == "onDestroy") { - print("executing onDestroy hook, closing ${connectionIds}"); - connectionIds.forEach((id) { - final tag = 'ft_${id}'; + print( + "executing onDestroy hook, closing ${tabs.map((tab) => tab.label).toList()}"); + tabs.forEach((tab) { + final tag = 'ft_${tab.label}'; ffi(tag).close().then((_) { Get.delete(tag: tag); }); @@ -79,26 +67,22 @@ class _FileManagerTabPageState extends State return Scaffold( body: Column( children: [ - Obx( - () => DesktopTabBar( - controller: tabController, - tabs: connectionIds - .map((e) => TabInfo(label: e, icon: Icons.file_copy_sharp)) - .toList(), - onTabClose: onRemoveId, - selected: _selected, - dark: isDarkTheme(), - mainTab: false, - ), + DesktopTabBar( + controller: tabController, + tabs: tabs, + onTabClose: onRemoveId, + selected: _selected, + dark: isDarkTheme(), + mainTab: false, ), Expanded( child: Obx( () => TabBarView( controller: tabController.value, - children: connectionIds - .map((e) => FileManagerPage( - key: ValueKey(e), - id: e)) //RemotePage(key: ValueKey(e), id: e)) + children: tabs + .map((tab) => FileManagerPage( + key: ValueKey(tab.label), + id: tab.label)) //RemotePage(key: ValueKey(e), id: e)) .toList()), ), ) @@ -108,15 +92,8 @@ class _FileManagerTabPageState extends State } void onRemoveId(String id) { - final indexOf = connectionIds.indexOf(id); - if (indexOf == -1) { - return; - } - connectionIds.removeAt(indexOf); - initialIndex = max(0, initialIndex - 1); - tabController.value = TabController( - length: connectionIds.length, initialIndex: initialIndex, vsync: this); - if (connectionIds.length == 0) { + DesktopTabBar.onClose(this, tabController, tabs, id); + if (tabs.length == 0) { WindowController.fromWindowId(windowId()).close(); } } diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 41dca26c2..7a4f1fc79 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -22,13 +22,13 @@ class TabInfo { class DesktopTabBar extends StatelessWidget { late final Rx controller; - late final List tabs; + late final RxList tabs; late final Function(String) onTabClose; late final Rx selected; late final bool dark; late final _Theme _theme; late final bool mainTab; - late final Function()? onMenu; + late final Function()? onAddSetting; DesktopTabBar({ Key? key, @@ -38,7 +38,7 @@ class DesktopTabBar extends StatelessWidget { required this.selected, required this.dark, required this.mainTab, - this.onMenu, + this.onAddSetting, }) : _theme = dark ? _Theme.dark() : _Theme.light(), super(key: key); @@ -105,19 +105,50 @@ class DesktopTabBar extends StatelessWidget { ), ), Offstage( - offstage: onMenu == null, - child: InkWell( - child: Icon( - Icons.menu, - color: _theme.unSelectedIconColor, - ), - onTap: () => onMenu?.call(), - ).paddingOnly(right: 10), + offstage: onAddSetting == null, + child: Tooltip( + message: translate("Settings"), + child: InkWell( + child: Icon( + Icons.menu, + color: _theme.unSelectedIconColor, + ), + onTap: () => onAddSetting?.call(), + ).paddingOnly(right: 10), + ), ) ], ), ); } + + static onClose( + TickerProvider vsync, + Rx controller, + RxList tabs, + String label, + ) { + tabs.removeWhere((tab) => tab.label == label); + controller.value = TabController( + length: tabs.length, + vsync: vsync, + initialIndex: max(0, tabs.length - 1)); + } + + static onAdd(TickerProvider vsync, Rx controller, + RxList tabs, Rx selected, TabInfo tab) { + int index = tabs.indexWhere((e) => e.label == tab.label); + if (index >= 0) { + controller.value.animateTo(index, duration: Duration.zero); + selected.value = index; + } else { + tabs.add(tab); + controller.value = TabController( + length: tabs.length, vsync: vsync, initialIndex: tabs.length - 1); + controller.value.animateTo(tabs.length - 1, duration: Duration.zero); + selected.value = tabs.length - 1; + } + } } class _Tab extends StatelessWidget { @@ -169,7 +200,7 @@ class _Tab extends StatelessWidget { ).paddingSymmetric(horizontal: 5), Expanded( child: Text( - label, + translate(label), style: TextStyle( color: is_selected ? theme.selectedTextColor