refactor tabbar_widget.dart and impl for desktop_tab_page.dart
This commit is contained in:
parent
5f68c099dd
commit
78c79a0e8d
@ -4,7 +4,6 @@ import 'package:flutter_hbb/consts.dart';
|
|||||||
import 'package:flutter_hbb/desktop/pages/desktop_home_page.dart';
|
import 'package:flutter_hbb/desktop/pages/desktop_home_page.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/desktop_setting_page.dart';
|
import 'package:flutter_hbb/desktop/pages/desktop_setting_page.dart';
|
||||||
import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
|
import 'package:flutter_hbb/desktop/widgets/tabbar_widget.dart';
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
class DesktopTabPage extends StatefulWidget {
|
class DesktopTabPage extends StatefulWidget {
|
||||||
@ -15,65 +14,51 @@ class DesktopTabPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _DesktopTabPageState extends State<DesktopTabPage> {
|
class _DesktopTabPageState extends State<DesktopTabPage> {
|
||||||
late RxList<TabInfo> tabs;
|
final tabBarController = DesktopTabBarController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
tabs = RxList.from([
|
tabBarController.state.value.tabs.add(TabInfo(
|
||||||
TabInfo(
|
key: kTabLabelHomePage,
|
||||||
key: kTabLabelHomePage,
|
label: kTabLabelHomePage,
|
||||||
label: kTabLabelHomePage,
|
selectedIcon: Icons.home_sharp,
|
||||||
selectedIcon: Icons.home_sharp,
|
unselectedIcon: Icons.home_outlined,
|
||||||
unselectedIcon: Icons.home_outlined,
|
closable: false,
|
||||||
closable: false)
|
page: DesktopHomePage()));
|
||||||
], growable: true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final dark = isDarkTheme();
|
||||||
return DragToResizeArea(
|
return DragToResizeArea(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(color: MyTheme.color(context).border!)),
|
border: Border.all(color: MyTheme.color(context).border!)),
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: MyTheme.color(context).bg,
|
backgroundColor: MyTheme.color(context).bg,
|
||||||
body: Column(
|
body: DesktopTab(
|
||||||
children: [
|
controller: tabBarController,
|
||||||
DesktopTabBar(
|
theme: dark ? TarBarTheme.dark() : TarBarTheme.light(),
|
||||||
tabs: tabs,
|
isMainWindow: true,
|
||||||
dark: isDarkTheme(),
|
tail: ActionIcon(
|
||||||
mainTab: true,
|
message: 'Settings',
|
||||||
onAddSetting: onAddSetting,
|
icon: IconFont.menu,
|
||||||
|
theme: dark ? TarBarTheme.dark() : TarBarTheme.light(),
|
||||||
|
onTap: onAddSetting,
|
||||||
|
is_close: false,
|
||||||
),
|
),
|
||||||
Obx((() => Expanded(
|
)),
|
||||||
child: PageView(
|
|
||||||
controller: DesktopTabBar.controller.value,
|
|
||||||
children: tabs.map((tab) {
|
|
||||||
switch (tab.label) {
|
|
||||||
case kTabLabelHomePage:
|
|
||||||
return DesktopHomePage(key: ValueKey(tab.label));
|
|
||||||
case kTabLabelSettingPage:
|
|
||||||
return DesktopSettingPage(key: ValueKey(tab.label));
|
|
||||||
default:
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
}).toList()),
|
|
||||||
))),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onAddSetting() {
|
void onAddSetting() {
|
||||||
DesktopTabBar.onAdd(
|
tabBarController.add(TabInfo(
|
||||||
tabs,
|
key: kTabLabelSettingPage,
|
||||||
TabInfo(
|
label: kTabLabelSettingPage,
|
||||||
key: kTabLabelSettingPage,
|
selectedIcon: Icons.build_sharp,
|
||||||
label: kTabLabelSettingPage,
|
unselectedIcon: Icons.build_outlined,
|
||||||
selectedIcon: Icons.build_sharp,
|
page: DesktopSettingPage()));
|
||||||
unselectedIcon: Icons.build_outlined));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,210 +16,216 @@ const double _kDividerIndent = 10;
|
|||||||
const double _kActionIconSize = 12;
|
const double _kActionIconSize = 12;
|
||||||
|
|
||||||
class TabInfo {
|
class TabInfo {
|
||||||
late final String key;
|
final String key;
|
||||||
late final String label;
|
final String label;
|
||||||
late final IconData? selectedIcon;
|
final IconData? selectedIcon;
|
||||||
late final IconData? unselectedIcon;
|
final IconData? unselectedIcon;
|
||||||
late final bool closable;
|
final bool closable;
|
||||||
|
final Widget page;
|
||||||
|
|
||||||
TabInfo(
|
TabInfo(
|
||||||
{required this.key,
|
{required this.key,
|
||||||
required this.label,
|
required this.label,
|
||||||
this.selectedIcon,
|
this.selectedIcon,
|
||||||
this.unselectedIcon,
|
this.unselectedIcon,
|
||||||
this.closable = true});
|
this.closable = true,
|
||||||
|
required this.page});
|
||||||
}
|
}
|
||||||
|
|
||||||
class DesktopTabBar extends StatelessWidget {
|
class DesktopTabBarState {
|
||||||
late final RxList<TabInfo> tabs;
|
final List<TabInfo> tabs = [];
|
||||||
late final Function(String)? onTabClose;
|
|
||||||
late final bool dark;
|
|
||||||
late final _Theme _theme;
|
|
||||||
late final bool mainTab;
|
|
||||||
late final bool showLogo;
|
|
||||||
late final bool showTitle;
|
|
||||||
late final bool showMinimize;
|
|
||||||
late final bool showMaximize;
|
|
||||||
late final bool showClose;
|
|
||||||
late final void Function()? onAddSetting;
|
|
||||||
late final void Function(int)? onSelected;
|
|
||||||
final ScrollPosController scrollController =
|
final ScrollPosController scrollController =
|
||||||
ScrollPosController(itemCount: 0);
|
ScrollPosController(itemCount: 0);
|
||||||
static final Rx<PageController> controller = PageController().obs;
|
final PageController pageController = PageController();
|
||||||
static final Rx<int> selected = 0.obs;
|
int selected = 0;
|
||||||
static final _tabBarListViewKey = GlobalKey();
|
|
||||||
|
|
||||||
DesktopTabBar(
|
DesktopTabBarState() {
|
||||||
{Key? key,
|
scrollController.itemCount = tabs.length;
|
||||||
required this.tabs,
|
// TODO test
|
||||||
|
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
// scrollController.scrollToItem(selected,
|
||||||
|
// center: true, animate: true);
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DesktopTabBarController {
|
||||||
|
final state = DesktopTabBarState().obs;
|
||||||
|
|
||||||
|
void add(TabInfo tab) {
|
||||||
|
if (!isDesktop) return;
|
||||||
|
final index = state.value.tabs.indexWhere((e) => e.key == tab.key);
|
||||||
|
int toIndex;
|
||||||
|
if (index >= 0) {
|
||||||
|
toIndex = index;
|
||||||
|
} else {
|
||||||
|
state.update((val) {
|
||||||
|
val!.tabs.add(tab);
|
||||||
|
});
|
||||||
|
toIndex = state.value.tabs.length - 1;
|
||||||
|
assert(toIndex >= 0);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
jumpTo(toIndex);
|
||||||
|
} catch (e) {
|
||||||
|
// call before binding controller will throw
|
||||||
|
debugPrint("Failed to jumpTo: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(int index) {
|
||||||
|
if (!isDesktop) return;
|
||||||
|
if (index < 0) return;
|
||||||
|
final len = state.value.tabs.length;
|
||||||
|
final currentSelected = state.value.selected;
|
||||||
|
int toIndex = 0;
|
||||||
|
if (index == len - 1) {
|
||||||
|
toIndex = max(0, currentSelected - 1);
|
||||||
|
} else if (index < len - 1 && index < currentSelected) {
|
||||||
|
toIndex = max(0, currentSelected - 1);
|
||||||
|
}
|
||||||
|
state.value.tabs.removeAt(index);
|
||||||
|
state.value.scrollController.itemCount = state.value.tabs.length;
|
||||||
|
jumpTo(toIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void jumpTo(int index) {
|
||||||
|
state.update((val) {
|
||||||
|
val!.selected = index;
|
||||||
|
val.pageController.jumpToPage(index);
|
||||||
|
val.scrollController.scrollToItem(index, center: true, animate: true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// onSelected callback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DesktopTab extends StatelessWidget {
|
||||||
|
final Function(String)? onTabClose;
|
||||||
|
final TarBarTheme theme;
|
||||||
|
final bool isMainWindow;
|
||||||
|
final bool showLogo;
|
||||||
|
final bool showTitle;
|
||||||
|
final bool showMinimize;
|
||||||
|
final bool showMaximize;
|
||||||
|
final bool showClose;
|
||||||
|
final Widget Function(Widget pageView)? pageViewBuilder;
|
||||||
|
final Widget? tail;
|
||||||
|
|
||||||
|
final DesktopTabBarController controller;
|
||||||
|
late final state = controller.state;
|
||||||
|
|
||||||
|
DesktopTab(
|
||||||
|
{required this.controller,
|
||||||
|
required this.isMainWindow,
|
||||||
|
this.theme = const TarBarTheme.light(),
|
||||||
this.onTabClose,
|
this.onTabClose,
|
||||||
required this.dark,
|
|
||||||
required this.mainTab,
|
|
||||||
this.onAddSetting,
|
|
||||||
this.onSelected,
|
|
||||||
this.showLogo = true,
|
this.showLogo = true,
|
||||||
this.showTitle = true,
|
this.showTitle = true,
|
||||||
this.showMinimize = true,
|
this.showMinimize = true,
|
||||||
this.showMaximize = true,
|
this.showMaximize = true,
|
||||||
this.showClose = true})
|
this.showClose = true,
|
||||||
: _theme = dark ? _Theme.dark() : _Theme.light(),
|
this.pageViewBuilder,
|
||||||
super(key: key) {
|
this.tail});
|
||||||
scrollController.itemCount = tabs.length;
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
scrollController.scrollToItem(selected.value,
|
|
||||||
center: true, animate: true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Column(children: [
|
||||||
height: _kTabBarHeight,
|
Container(
|
||||||
child: Column(
|
height: _kTabBarHeight,
|
||||||
children: [
|
child: Column(
|
||||||
Container(
|
children: [
|
||||||
height: _kTabBarHeight - 1,
|
Container(
|
||||||
child: Row(
|
height: _kTabBarHeight - 1,
|
||||||
children: [
|
child: _buildBar(),
|
||||||
Expanded(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Row(children: [
|
|
||||||
Offstage(
|
|
||||||
offstage: !showLogo,
|
|
||||||
child: Image.asset(
|
|
||||||
'assets/logo.ico',
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
)),
|
|
||||||
Offstage(
|
|
||||||
offstage: !showTitle,
|
|
||||||
child: Text(
|
|
||||||
"RustDesk",
|
|
||||||
style: TextStyle(fontSize: 13),
|
|
||||||
).marginOnly(left: 2))
|
|
||||||
]).marginOnly(
|
|
||||||
left: 5,
|
|
||||||
right: 10,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: GestureDetector(
|
|
||||||
onPanStart: (_) {
|
|
||||||
if (mainTab) {
|
|
||||||
windowManager.startDragging();
|
|
||||||
} else {
|
|
||||||
WindowController.fromWindowId(windowId!)
|
|
||||||
.startDragging();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: _ListView(
|
|
||||||
key: _tabBarListViewKey,
|
|
||||||
controller: controller,
|
|
||||||
scrollController: scrollController,
|
|
||||||
tabInfos: tabs,
|
|
||||||
selected: selected,
|
|
||||||
onTabClose: onTabClose,
|
|
||||||
theme: _theme,
|
|
||||||
onSelected: onSelected)),
|
|
||||||
),
|
|
||||||
Offstage(
|
|
||||||
offstage: mainTab,
|
|
||||||
child: _AddButton(
|
|
||||||
theme: _theme,
|
|
||||||
).paddingOnly(left: 10),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Offstage(
|
|
||||||
offstage: onAddSetting == null,
|
|
||||||
child: _ActionIcon(
|
|
||||||
message: 'Settings',
|
|
||||||
icon: IconFont.menu,
|
|
||||||
theme: _theme,
|
|
||||||
onTap: () => onAddSetting?.call(),
|
|
||||||
is_close: false,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
WindowActionPanel(
|
|
||||||
mainTab: mainTab,
|
|
||||||
theme: _theme,
|
|
||||||
showMinimize: showMinimize,
|
|
||||||
showMaximize: showMaximize,
|
|
||||||
showClose: showClose,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
Divider(
|
||||||
Divider(
|
height: 1,
|
||||||
height: 1,
|
thickness: 1,
|
||||||
thickness: 1,
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
|
Expanded(
|
||||||
|
child: pageViewBuilder != null
|
||||||
|
? pageViewBuilder!(_buildPageView())
|
||||||
|
: _buildPageView())
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildPageView() {
|
||||||
|
debugPrint("_buildPageView: ${state.value.tabs.length}");
|
||||||
|
return Obx(() => PageView(
|
||||||
|
controller: state.value.pageController,
|
||||||
|
children:
|
||||||
|
state.value.tabs.map((tab) => tab.page).toList(growable: false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildBar() {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Row(children: [
|
||||||
|
Offstage(
|
||||||
|
offstage: !showLogo,
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/logo.ico',
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
)),
|
||||||
|
Offstage(
|
||||||
|
offstage: !showTitle,
|
||||||
|
child: Text(
|
||||||
|
"RustDesk",
|
||||||
|
style: TextStyle(fontSize: 13),
|
||||||
|
).marginOnly(left: 2))
|
||||||
|
]).marginOnly(
|
||||||
|
left: 5,
|
||||||
|
right: 10,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: GestureDetector(
|
||||||
|
onPanStart: (_) {
|
||||||
|
if (isMainWindow) {
|
||||||
|
windowManager.startDragging();
|
||||||
|
} else {
|
||||||
|
WindowController.fromWindowId(windowId!)
|
||||||
|
.startDragging();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: _ListView(
|
||||||
|
controller: controller,
|
||||||
|
onTabClose: onTabClose,
|
||||||
|
theme: theme,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
Offstage(
|
||||||
|
offstage: isMainWindow,
|
||||||
|
child: _AddButton(
|
||||||
|
theme: theme,
|
||||||
|
).paddingOnly(left: 10),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Offstage(offstage: tail == null, child: tail),
|
||||||
|
WindowActionPanel(
|
||||||
|
mainTab: isMainWindow,
|
||||||
|
theme: theme,
|
||||||
|
showMinimize: showMinimize,
|
||||||
|
showMaximize: showMaximize,
|
||||||
|
showClose: showClose,
|
||||||
|
)
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static onAdd(RxList<TabInfo> tabs, TabInfo tab) {
|
|
||||||
if (!isDesktop) return;
|
|
||||||
int index = tabs.indexWhere((e) => e.key == tab.key);
|
|
||||||
if (index >= 0) {
|
|
||||||
selected.value = index;
|
|
||||||
} else {
|
|
||||||
tabs.add(tab);
|
|
||||||
selected.value = tabs.length - 1;
|
|
||||||
assert(selected.value >= 0);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
controller.value.jumpToPage(selected.value);
|
|
||||||
} catch (e) {
|
|
||||||
// call before binding controller will throw
|
|
||||||
debugPrint("Failed to jumpToPage: $e");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static remove(RxList<TabInfo> tabs, int index) {
|
|
||||||
if (!isDesktop) return;
|
|
||||||
if (index < 0) return;
|
|
||||||
if (index == tabs.length - 1) {
|
|
||||||
selected.value = max(0, selected.value - 1);
|
|
||||||
} else if (index < tabs.length - 1 && index < selected.value) {
|
|
||||||
selected.value = max(0, selected.value - 1);
|
|
||||||
}
|
|
||||||
tabs.removeAt(index);
|
|
||||||
controller.value.jumpToPage(selected.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void jumpTo(RxList<TabInfo> tabs, int index) {
|
|
||||||
if (!isDesktop) return;
|
|
||||||
if (index < 0 || index >= tabs.length) return;
|
|
||||||
selected.value = index;
|
|
||||||
controller.value.jumpToPage(selected.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void close(String? key) {
|
|
||||||
if (!isDesktop) return;
|
|
||||||
final tabBar = _tabBarListViewKey.currentWidget as _ListView?;
|
|
||||||
if (tabBar == null) return;
|
|
||||||
final tabs = tabBar.tabs;
|
|
||||||
if (key == null) {
|
|
||||||
if (tabBar.selected.value < tabs.length) {
|
|
||||||
tabs[tabBar.selected.value].onClose();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (final tab in tabs) {
|
|
||||||
if (tab.key == key) {
|
|
||||||
tab.onClose();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class WindowActionPanel extends StatelessWidget {
|
class WindowActionPanel extends StatelessWidget {
|
||||||
final bool mainTab;
|
final bool mainTab;
|
||||||
final _Theme theme;
|
final TarBarTheme theme;
|
||||||
|
|
||||||
final bool showMinimize;
|
final bool showMinimize;
|
||||||
final bool showMaximize;
|
final bool showMaximize;
|
||||||
@ -240,7 +246,7 @@ class WindowActionPanel extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Offstage(
|
Offstage(
|
||||||
offstage: !showMinimize,
|
offstage: !showMinimize,
|
||||||
child: _ActionIcon(
|
child: ActionIcon(
|
||||||
message: 'Minimize',
|
message: 'Minimize',
|
||||||
icon: IconFont.min,
|
icon: IconFont.min,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
@ -269,7 +275,7 @@ class WindowActionPanel extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
return Obx(
|
return Obx(
|
||||||
() => _ActionIcon(
|
() => ActionIcon(
|
||||||
message: is_maximized.value ? "Restore" : "Maximize",
|
message: is_maximized.value ? "Restore" : "Maximize",
|
||||||
icon: is_maximized.value ? IconFont.restore : IconFont.max,
|
icon: is_maximized.value ? IconFont.restore : IconFont.max,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
@ -297,7 +303,7 @@ class WindowActionPanel extends StatelessWidget {
|
|||||||
})),
|
})),
|
||||||
Offstage(
|
Offstage(
|
||||||
offstage: !showClose,
|
offstage: !showClose,
|
||||||
child: _ActionIcon(
|
child: ActionIcon(
|
||||||
message: 'Close',
|
message: 'Close',
|
||||||
icon: IconFont.close,
|
icon: IconFont.close,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
@ -317,69 +323,37 @@ class WindowActionPanel extends StatelessWidget {
|
|||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class _ListView extends StatelessWidget {
|
class _ListView extends StatelessWidget {
|
||||||
final Rx<PageController> controller;
|
final DesktopTabBarController controller;
|
||||||
final ScrollPosController scrollController;
|
late final Rx<DesktopTabBarState> state;
|
||||||
final RxList<TabInfo> tabInfos;
|
|
||||||
final Rx<int> selected;
|
|
||||||
final Function(String key)? onTabClose;
|
final Function(String key)? onTabClose;
|
||||||
final _Theme _theme;
|
final TarBarTheme theme;
|
||||||
late List<_Tab> tabs;
|
|
||||||
late final void Function(int)? onSelected;
|
|
||||||
|
|
||||||
_ListView(
|
_ListView(
|
||||||
{Key? key,
|
{required this.controller, required this.onTabClose, required this.theme})
|
||||||
required this.controller,
|
: this.state = controller.state;
|
||||||
required this.scrollController,
|
|
||||||
required this.tabInfos,
|
|
||||||
required this.selected,
|
|
||||||
required this.onTabClose,
|
|
||||||
required _Theme theme,
|
|
||||||
this.onSelected})
|
|
||||||
: _theme = theme,
|
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Obx(() {
|
return Obx(() => ListView(
|
||||||
tabs = tabInfos.asMap().entries.map((e) {
|
controller: state.value.scrollController,
|
||||||
int index = e.key;
|
scrollDirection: Axis.horizontal,
|
||||||
return _Tab(
|
shrinkWrap: true,
|
||||||
index: index,
|
physics: BouncingScrollPhysics(),
|
||||||
label: e.value.label,
|
children: state.value.tabs.asMap().entries.map((e) {
|
||||||
selectedIcon: e.value.selectedIcon,
|
final index = e.key;
|
||||||
unselectedIcon: e.value.unselectedIcon,
|
final tab = e.value;
|
||||||
closable: e.value.closable,
|
return _Tab(
|
||||||
selected: selected.value,
|
index: index,
|
||||||
onClose: () {
|
label: tab.label,
|
||||||
tabInfos.removeWhere((tab) => tab.key == e.value.key);
|
selectedIcon: tab.selectedIcon,
|
||||||
onTabClose?.call(e.value.key);
|
unselectedIcon: tab.unselectedIcon,
|
||||||
if (index <= selected.value) {
|
closable: tab.closable,
|
||||||
selected.value = max(0, selected.value - 1);
|
selected: state.value.selected,
|
||||||
}
|
onClose: () => controller.remove(index),
|
||||||
assert(tabInfos.length == 0 || selected.value < tabInfos.length);
|
onSelected: () => controller.jumpTo(index),
|
||||||
scrollController.itemCount = tabInfos.length;
|
theme: theme,
|
||||||
if (tabInfos.length > 0) {
|
);
|
||||||
scrollController.scrollToItem(selected.value,
|
}).toList()));
|
||||||
center: true, animate: true);
|
|
||||||
controller.value.jumpToPage(selected.value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onSelected: () {
|
|
||||||
selected.value = index;
|
|
||||||
scrollController.scrollToItem(index, center: true, animate: true);
|
|
||||||
controller.value.jumpToPage(index);
|
|
||||||
onSelected?.call(selected.value);
|
|
||||||
},
|
|
||||||
theme: _theme,
|
|
||||||
);
|
|
||||||
}).toList();
|
|
||||||
return ListView(
|
|
||||||
controller: scrollController,
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
shrinkWrap: true,
|
|
||||||
physics: BouncingScrollPhysics(),
|
|
||||||
children: tabs);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +367,7 @@ class _Tab extends StatelessWidget {
|
|||||||
late final Function() onClose;
|
late final Function() onClose;
|
||||||
late final Function() onSelected;
|
late final Function() onSelected;
|
||||||
final RxBool _hover = false.obs;
|
final RxBool _hover = false.obs;
|
||||||
late final _Theme theme;
|
late final TarBarTheme theme;
|
||||||
|
|
||||||
_Tab(
|
_Tab(
|
||||||
{Key? key,
|
{Key? key,
|
||||||
@ -474,7 +448,7 @@ class _Tab extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _AddButton extends StatelessWidget {
|
class _AddButton extends StatelessWidget {
|
||||||
late final _Theme theme;
|
late final TarBarTheme theme;
|
||||||
|
|
||||||
_AddButton({
|
_AddButton({
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -483,7 +457,7 @@ class _AddButton extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return _ActionIcon(
|
return ActionIcon(
|
||||||
message: 'New Connection',
|
message: 'New Connection',
|
||||||
icon: IconFont.add,
|
icon: IconFont.add,
|
||||||
theme: theme,
|
theme: theme,
|
||||||
@ -497,7 +471,7 @@ class _CloseButton extends StatelessWidget {
|
|||||||
final bool visiable;
|
final bool visiable;
|
||||||
final bool tabSelected;
|
final bool tabSelected;
|
||||||
final Function onClose;
|
final Function onClose;
|
||||||
late final _Theme theme;
|
late final TarBarTheme theme;
|
||||||
|
|
||||||
_CloseButton({
|
_CloseButton({
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -528,13 +502,13 @@ class _CloseButton extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ActionIcon extends StatelessWidget {
|
class ActionIcon extends StatelessWidget {
|
||||||
final String message;
|
final String message;
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
final _Theme theme;
|
final TarBarTheme theme;
|
||||||
final Function() onTap;
|
final Function() onTap;
|
||||||
final bool is_close;
|
final bool is_close;
|
||||||
const _ActionIcon({
|
const ActionIcon({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.message,
|
required this.message,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
@ -568,35 +542,34 @@ class _ActionIcon extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Theme {
|
class TarBarTheme {
|
||||||
late Color unSelectedtabIconColor;
|
final Color unSelectedtabIconColor;
|
||||||
late Color selectedtabIconColor;
|
final Color selectedtabIconColor;
|
||||||
late Color selectedTextColor;
|
final Color selectedTextColor;
|
||||||
late Color unSelectedTextColor;
|
final Color unSelectedTextColor;
|
||||||
late Color selectedIconColor;
|
final Color selectedIconColor;
|
||||||
late Color unSelectedIconColor;
|
final Color unSelectedIconColor;
|
||||||
late Color dividerColor;
|
final Color dividerColor;
|
||||||
late Color hoverColor;
|
final Color hoverColor;
|
||||||
|
|
||||||
_Theme.light() {
|
const TarBarTheme.light()
|
||||||
unSelectedtabIconColor = Color.fromARGB(255, 162, 203, 241);
|
: unSelectedtabIconColor = const Color.fromARGB(255, 162, 203, 241),
|
||||||
selectedtabIconColor = MyTheme.accent;
|
selectedtabIconColor = MyTheme.accent,
|
||||||
selectedTextColor = Color.fromARGB(255, 26, 26, 26);
|
selectedTextColor = const Color.fromARGB(255, 26, 26, 26),
|
||||||
unSelectedTextColor = Color.fromARGB(255, 96, 96, 96);
|
unSelectedTextColor = const Color.fromARGB(255, 96, 96, 96),
|
||||||
selectedIconColor = Color.fromARGB(255, 26, 26, 26);
|
selectedIconColor = const Color.fromARGB(255, 26, 26, 26),
|
||||||
unSelectedIconColor = Color.fromARGB(255, 96, 96, 96);
|
unSelectedIconColor = const Color.fromARGB(255, 96, 96, 96),
|
||||||
dividerColor = Color.fromARGB(255, 238, 238, 238);
|
dividerColor = const Color.fromARGB(255, 238, 238, 238),
|
||||||
hoverColor = Colors.grey.withOpacity(0.2);
|
hoverColor = const Color.fromARGB(
|
||||||
}
|
51, 158, 158, 158); // Colors.grey; //0xFF9E9E9E
|
||||||
|
|
||||||
_Theme.dark() {
|
const TarBarTheme.dark()
|
||||||
unSelectedtabIconColor = Color.fromARGB(255, 30, 65, 98);
|
: unSelectedtabIconColor = const Color.fromARGB(255, 30, 65, 98),
|
||||||
selectedtabIconColor = MyTheme.accent;
|
selectedtabIconColor = MyTheme.accent,
|
||||||
selectedTextColor = Color.fromARGB(255, 255, 255, 255);
|
selectedTextColor = const Color.fromARGB(255, 255, 255, 255),
|
||||||
unSelectedTextColor = Color.fromARGB(255, 207, 207, 207);
|
unSelectedTextColor = const Color.fromARGB(255, 207, 207, 207),
|
||||||
selectedIconColor = Color.fromARGB(255, 215, 215, 215);
|
selectedIconColor = const Color.fromARGB(255, 215, 215, 215),
|
||||||
unSelectedIconColor = Color.fromARGB(255, 255, 255, 255);
|
unSelectedIconColor = const Color.fromARGB(255, 255, 255, 255),
|
||||||
dividerColor = Color.fromARGB(255, 64, 64, 64);
|
dividerColor = const Color.fromARGB(255, 64, 64, 64),
|
||||||
hoverColor = Colors.black26;
|
hoverColor = Colors.black26;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user