unify tab logic

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2022-08-11 18:08:35 +08:00
parent c799fb1857
commit 94353cf90b
4 changed files with 103 additions and 132 deletions

View File

@ -1,5 +1,4 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:math';
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -25,24 +24,23 @@ class _ConnectionTabPageState extends State<ConnectionTabPage>
with TickerProviderStateMixin { with TickerProviderStateMixin {
// refactor List<int> when using multi-tab // refactor List<int> when using multi-tab
// this singleton is only for test // this singleton is only for test
var connectionIds = RxList<String>.empty(growable: true); RxList<TabInfo> tabs = RxList<TabInfo>.empty(growable: true);
var initialIndex = 0;
late Rx<TabController> tabController; late Rx<TabController> tabController;
static final Rx<int> _selected = 0.obs; static final Rx<int> _selected = 0.obs;
IconData icon = Icons.desktop_windows_sharp;
var connectionMap = RxList<Widget>.empty(growable: true); var connectionMap = RxList<Widget>.empty(growable: true);
_ConnectionTabPageState(Map<String, dynamic> params) { _ConnectionTabPageState(Map<String, dynamic> params) {
if (params['id'] != null) { if (params['id'] != null) {
connectionIds.add(params['id']); tabs.add(TabInfo(label: params['id'], icon: icon));
} }
} }
@override @override
void initState() { void initState() {
super.initState(); super.initState();
tabController = tabController = TabController(length: tabs.length, vsync: this).obs;
TabController(length: connectionIds.length, vsync: this).obs;
rustDeskWinManager.setMethodHandler((call, fromWindowId) async { rustDeskWinManager.setMethodHandler((call, fromWindowId) async {
print( print(
"call ${call.method} with args ${call.arguments} from window ${fromWindowId}"); "call ${call.method} with args ${call.arguments} from window ${fromWindowId}");
@ -51,23 +49,13 @@ class _ConnectionTabPageState extends State<ConnectionTabPage>
final args = jsonDecode(call.arguments); final args = jsonDecode(call.arguments);
final id = args['id']; final id = args['id'];
window_on_top(windowId()); window_on_top(windowId());
final indexOf = connectionIds.indexOf(id); DesktopTabBar.onAdd(this, tabController, tabs, _selected,
if (indexOf >= 0) { TabInfo(label: id, icon: icon));
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;
} else if (call.method == "onDestroy") { } else if (call.method == "onDestroy") {
print("executing onDestroy hook, closing ${connectionIds}"); print(
connectionIds.forEach((id) { "executing onDestroy hook, closing ${tabs.map((tab) => tab.label).toList()}");
final tag = '${id}'; tabs.forEach((tab) {
final tag = '${tab.label}';
ffi(tag).close().then((_) { ffi(tag).close().then((_) {
Get.delete<FFI>(tag: tag); Get.delete<FFI>(tag: tag);
}); });
@ -82,24 +70,21 @@ class _ConnectionTabPageState extends State<ConnectionTabPage>
return Scaffold( return Scaffold(
body: Column( body: Column(
children: [ children: [
Obx(() => DesktopTabBar( DesktopTabBar(
controller: tabController, controller: tabController,
tabs: connectionIds tabs: tabs,
.map((e) => onTabClose: onRemoveId,
TabInfo(label: e, icon: Icons.desktop_windows_sharp)) selected: _selected,
.toList(), dark: isDarkTheme(),
onTabClose: onRemoveId, mainTab: false,
selected: _selected, ),
dark: isDarkTheme(),
mainTab: false,
)),
Expanded( Expanded(
child: Obx(() => TabBarView( child: Obx(() => TabBarView(
controller: tabController.value, controller: tabController.value,
children: connectionIds children: tabs
.map((e) => RemotePage( .map((tab) => RemotePage(
key: ValueKey(e), key: ValueKey(tab.label),
id: e, id: tab.label,
tabBarHeight: kDesktopRemoteTabBarHeight, tabBarHeight: kDesktopRemoteTabBarHeight,
)) //RemotePage(key: ValueKey(e), id: e)) )) //RemotePage(key: ValueKey(e), id: e))
.toList()))), .toList()))),
@ -109,15 +94,8 @@ class _ConnectionTabPageState extends State<ConnectionTabPage>
} }
void onRemoveId(String id) { void onRemoveId(String id) {
final indexOf = connectionIds.indexOf(id); DesktopTabBar.onClose(this, tabController, tabs, id);
if (indexOf == -1) { if (tabs.length == 0) {
return;
}
connectionIds.removeAt(indexOf);
initialIndex = max(0, initialIndex - 1);
tabController.value = TabController(
length: connectionIds.length, vsync: this, initialIndex: initialIndex);
if (connectionIds.length == 0) {
WindowController.fromWindowId(windowId()).close(); WindowController.fromWindowId(windowId()).close();
} }
} }

View File

@ -1,5 +1,3 @@
import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hbb/common.dart'; import 'package:flutter_hbb/common.dart';
import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/consts.dart';
@ -36,15 +34,15 @@ class _DesktopTabPageState extends State<DesktopTabPage>
return Scaffold( return Scaffold(
body: Column( body: Column(
children: [ children: [
Obx((() => DesktopTabBar( DesktopTabBar(
controller: tabController, controller: tabController,
tabs: tabs.toList(), tabs: tabs,
onTabClose: onTabClose, onTabClose: onTabClose,
selected: _selected, selected: _selected,
dark: isDarkTheme(), dark: isDarkTheme(),
mainTab: true, mainTab: true,
onMenu: onTabbarMenu, onAddSetting: onAddSetting,
))), ),
Obx((() => Expanded( Obx((() => Expanded(
child: TabBarView( child: TabBarView(
controller: tabController.value, controller: tabController.value,
@ -65,24 +63,11 @@ class _DesktopTabPageState extends State<DesktopTabPage>
} }
void onTabClose(String label) { void onTabClose(String label) {
tabs.removeWhere((tab) => tab.label == label); DesktopTabBar.onClose(this, tabController, tabs, label);
tabController.value = TabController(
length: tabs.length,
vsync: this,
initialIndex: max(0, tabs.length - 1));
} }
void onTabbarMenu() { void onAddSetting() {
int index = tabs.indexWhere((tab) => tab.label == kTabLabelSettingPage); DesktopTabBar.onAdd(this, tabController, tabs, _selected,
if (index >= 0) { TabInfo(label: kTabLabelSettingPage, icon: Icons.settings));
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;
}
} }
} }

View File

@ -1,5 +1,4 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:math';
import 'package:desktop_multi_window/desktop_multi_window.dart'; import 'package:desktop_multi_window/desktop_multi_window.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -24,22 +23,21 @@ class _FileManagerTabPageState extends State<FileManagerTabPage>
with TickerProviderStateMixin { with TickerProviderStateMixin {
// refactor List<int> when using multi-tab // refactor List<int> when using multi-tab
// this singleton is only for test // this singleton is only for test
var connectionIds = List<String>.empty(growable: true).obs; RxList<TabInfo> tabs = List<TabInfo>.empty(growable: true).obs;
var initialIndex = 0;
late Rx<TabController> tabController; late Rx<TabController> tabController;
static final Rx<int> _selected = 0.obs; static final Rx<int> _selected = 0.obs;
IconData icon = Icons.file_copy_sharp;
_FileManagerTabPageState(Map<String, dynamic> params) { _FileManagerTabPageState(Map<String, dynamic> params) {
if (params['id'] != null) { if (params['id'] != null) {
connectionIds.add(params['id']); tabs.add(TabInfo(label: params['id'], icon: icon));
} }
} }
@override @override
void initState() { void initState() {
super.initState(); super.initState();
tabController = tabController = TabController(length: tabs.length, vsync: this).obs;
TabController(length: connectionIds.length, vsync: this).obs;
rustDeskWinManager.setMethodHandler((call, fromWindowId) async { rustDeskWinManager.setMethodHandler((call, fromWindowId) async {
print( print(
"call ${call.method} with args ${call.arguments} from window ${fromWindowId}"); "call ${call.method} with args ${call.arguments} from window ${fromWindowId}");
@ -48,23 +46,13 @@ class _FileManagerTabPageState extends State<FileManagerTabPage>
final args = jsonDecode(call.arguments); final args = jsonDecode(call.arguments);
final id = args['id']; final id = args['id'];
window_on_top(windowId()); window_on_top(windowId());
final indexOf = connectionIds.indexOf(id); DesktopTabBar.onAdd(this, tabController, tabs, _selected,
if (indexOf >= 0) { TabInfo(label: id, icon: icon));
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;
} else if (call.method == "onDestroy") { } else if (call.method == "onDestroy") {
print("executing onDestroy hook, closing ${connectionIds}"); print(
connectionIds.forEach((id) { "executing onDestroy hook, closing ${tabs.map((tab) => tab.label).toList()}");
final tag = 'ft_${id}'; tabs.forEach((tab) {
final tag = 'ft_${tab.label}';
ffi(tag).close().then((_) { ffi(tag).close().then((_) {
Get.delete<FFI>(tag: tag); Get.delete<FFI>(tag: tag);
}); });
@ -79,26 +67,22 @@ class _FileManagerTabPageState extends State<FileManagerTabPage>
return Scaffold( return Scaffold(
body: Column( body: Column(
children: [ children: [
Obx( DesktopTabBar(
() => DesktopTabBar( controller: tabController,
controller: tabController, tabs: tabs,
tabs: connectionIds onTabClose: onRemoveId,
.map((e) => TabInfo(label: e, icon: Icons.file_copy_sharp)) selected: _selected,
.toList(), dark: isDarkTheme(),
onTabClose: onRemoveId, mainTab: false,
selected: _selected,
dark: isDarkTheme(),
mainTab: false,
),
), ),
Expanded( Expanded(
child: Obx( child: Obx(
() => TabBarView( () => TabBarView(
controller: tabController.value, controller: tabController.value,
children: connectionIds children: tabs
.map((e) => FileManagerPage( .map((tab) => FileManagerPage(
key: ValueKey(e), key: ValueKey(tab.label),
id: e)) //RemotePage(key: ValueKey(e), id: e)) id: tab.label)) //RemotePage(key: ValueKey(e), id: e))
.toList()), .toList()),
), ),
) )
@ -108,15 +92,8 @@ class _FileManagerTabPageState extends State<FileManagerTabPage>
} }
void onRemoveId(String id) { void onRemoveId(String id) {
final indexOf = connectionIds.indexOf(id); DesktopTabBar.onClose(this, tabController, tabs, id);
if (indexOf == -1) { if (tabs.length == 0) {
return;
}
connectionIds.removeAt(indexOf);
initialIndex = max(0, initialIndex - 1);
tabController.value = TabController(
length: connectionIds.length, initialIndex: initialIndex, vsync: this);
if (connectionIds.length == 0) {
WindowController.fromWindowId(windowId()).close(); WindowController.fromWindowId(windowId()).close();
} }
} }

View File

@ -22,13 +22,13 @@ class TabInfo {
class DesktopTabBar extends StatelessWidget { class DesktopTabBar extends StatelessWidget {
late final Rx<TabController> controller; late final Rx<TabController> controller;
late final List<TabInfo> tabs; late final RxList<TabInfo> tabs;
late final Function(String) onTabClose; late final Function(String) onTabClose;
late final Rx<int> selected; late final Rx<int> selected;
late final bool dark; late final bool dark;
late final _Theme _theme; late final _Theme _theme;
late final bool mainTab; late final bool mainTab;
late final Function()? onMenu; late final Function()? onAddSetting;
DesktopTabBar({ DesktopTabBar({
Key? key, Key? key,
@ -38,7 +38,7 @@ class DesktopTabBar extends StatelessWidget {
required this.selected, required this.selected,
required this.dark, required this.dark,
required this.mainTab, required this.mainTab,
this.onMenu, this.onAddSetting,
}) : _theme = dark ? _Theme.dark() : _Theme.light(), }) : _theme = dark ? _Theme.dark() : _Theme.light(),
super(key: key); super(key: key);
@ -105,19 +105,50 @@ class DesktopTabBar extends StatelessWidget {
), ),
), ),
Offstage( Offstage(
offstage: onMenu == null, offstage: onAddSetting == null,
child: InkWell( child: Tooltip(
child: Icon( message: translate("Settings"),
Icons.menu, child: InkWell(
color: _theme.unSelectedIconColor, child: Icon(
), Icons.menu,
onTap: () => onMenu?.call(), color: _theme.unSelectedIconColor,
).paddingOnly(right: 10), ),
onTap: () => onAddSetting?.call(),
).paddingOnly(right: 10),
),
) )
], ],
), ),
); );
} }
static onClose(
TickerProvider vsync,
Rx<TabController> controller,
RxList<TabInfo> 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<TabController> controller,
RxList<TabInfo> tabs, Rx<int> 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 { class _Tab extends StatelessWidget {
@ -169,7 +200,7 @@ class _Tab extends StatelessWidget {
).paddingSymmetric(horizontal: 5), ).paddingSymmetric(horizontal: 5),
Expanded( Expanded(
child: Text( child: Text(
label, translate(label),
style: TextStyle( style: TextStyle(
color: is_selected color: is_selected
? theme.selectedTextColor ? theme.selectedTextColor