This commit is contained in:
toly
2023-10-21 10:10:48 +08:00
parent 689e8d9fdb
commit bcba7ebae2
268 changed files with 83 additions and 13102 deletions

View File

@@ -0,0 +1,2 @@
export 'toly_ui/toly_ui.dart';
export 'windows/window_buttons.dart';

View File

@@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
class ColorsPanel extends StatelessWidget {
final List<Color> colors;
final ValueChanged<Color> onSelect;
const ColorsPanel({super.key, required this.colors, required this.onSelect});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Wrap(
spacing: 8,
runSpacing: 8,
children: colors
.asMap()
.keys
.map((int index) => GestureDetector(
onTap: () => onSelect(colors[index]),
child: Container(
alignment: Alignment.center,
width: 60,
height: 60,
decoration: BoxDecoration(
color: colors[index],
borderRadius: BorderRadius.circular(8)),
child: Text(
'$index',
style: TextStyle(color: Colors.white),
),
),
))
.toList(),
),
);
}
}

View File

@@ -0,0 +1,18 @@
import 'package:flutter/cupertino.dart';
class MenuMeta {
// 标签
final String label;
// 图标数据
final IconData icon;
// 图标颜色
final Color? color;
const MenuMeta({
required this.label,
required this.icon,
this.color,
});
}

View File

@@ -0,0 +1,104 @@
import 'package:flutter/material.dart';
import 'package:flutter/src/gestures/events.dart';
class TolyBreadcrumb extends StatelessWidget {
final List<BreadcrumbItem> items;
final ValueChanged<BreadcrumbItem>? onTapItem;
const TolyBreadcrumb({super.key, required this.items, this.onTapItem});
@override
Widget build(BuildContext context) {
List<Widget> children = [];
for (int i = 0; i < items.length; i++) {
children.add(TolyBreadcrumbItem(
item: items[i], onTapItem: onTapItem,
));
if (i != items.length - 1) {
children.add(Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: Text(
'/',
style: TextStyle(color: Colors.grey),
),
));
}
}
return Wrap(
children: children,
);
}
}
class TolyBreadcrumbItem extends StatefulWidget {
final BreadcrumbItem item;
final ValueChanged<BreadcrumbItem>? onTapItem;
const TolyBreadcrumbItem({super.key, required this.item, required this.onTapItem});
@override
State<TolyBreadcrumbItem> createState() => _TolyBreadcrumbItemState();
}
class _TolyBreadcrumbItemState extends State<TolyBreadcrumbItem> {
bool _hover = false;
@override
Widget build(BuildContext context) {
bool hasTarget = (widget.item.to != null);
Color? color = (_hover&&hasTarget)?Colors.blue:null;
MouseCursor cursor = hasTarget?SystemMouseCursors.click:SystemMouseCursors.basic;
if(widget.item.active) {
color = null;
cursor = SystemMouseCursors.basic;
}
TextStyle style = TextStyle(
fontWeight: hasTarget ? FontWeight.bold : null,
color: color
);
return MouseRegion(
cursor: cursor,
onEnter: _onEnter,
onExit: _onExit,
child: GestureDetector(
onTap: () {
if(!widget.item.active){
widget.onTapItem?.call(widget.item);
}
},
child: Text(widget.item.label, style: style)),
);
}
void _onEnter(PointerEnterEvent event) {
setState(() {
_hover = true;
});
}
void _onExit(PointerExitEvent event) {
setState(() {
_hover = false;
});
}
}
class BreadcrumbItem {
final String? to;
final String label;
final bool active;
BreadcrumbItem( {this.to, required this.label,this.active=false,});
}
//<el-breadcrumb separator="/">
// <el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
// <el-breadcrumb-item><a href="/">活动管理</a></el-breadcrumb-item>
// <el-breadcrumb-item>活动列表</el-breadcrumb-item>
// <el-breadcrumb-item>活动详情</el-breadcrumb-item>
// </el-breadcrumb>

View File

@@ -0,0 +1,163 @@
import 'package:flutter/material.dart';
import 'menu_meta.dart';
// final List<NavigationRailDestination> destinations = const [
// NavigationRailDestination(icon: Icon(Icons.color_lens_outlined), label: Text("颜色板")),
// NavigationRailDestination(icon: Icon(Icons.add_chart), label: Text("计数器")),
// NavigationRailDestination(icon: Icon(Icons.person), label: Text("我的")),
// NavigationRailDestination(icon: Icon(Icons.settings), label: Text("设置")),
// ];
const List<MenuMeta> kDeskNavBarMenus = [
MenuMeta(label: '颜色板', icon: Icons.color_lens_outlined),
MenuMeta(
label: '计数器',
icon: Icons.add_chart,
),
MenuMeta(
label: '我的',
icon: Icons.person,
),
MenuMeta(label: '设置', icon: Icons.settings),
];
class TolyNavigationRail extends StatelessWidget {
final ValueChanged<int> onDestinationSelected;
final Color backgroundColor;
final int? selectedIndex;
final Widget? leading;
const TolyNavigationRail({
Key? key,
required this.onDestinationSelected,
required this.selectedIndex,
this.leading,
required this.backgroundColor,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
width: 64,
color: backgroundColor,
child: Column(
children: [
if(leading!=null) leading!,
Expanded(
child: LeftNavigationMenu(
items: kDeskNavBarMenus,
selectedIndex: selectedIndex,
onTapItem: onDestinationSelected,
)),
// if (selectedIndex == 0) HelpButton()
],
),
);
}
}
class LeftNavigationMenu extends StatelessWidget {
final List<MenuMeta> items;
final ValueChanged<int> onTapItem;
final int? selectedIndex;
const LeftNavigationMenu(
{Key? key,
required this.items,
required this.selectedIndex,
required this.onTapItem})
: super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: items.asMap().keys.map((int index) {
return LeftNavigationBarItemWidget(
item: items[index],
selected: index == selectedIndex,
onTap: () {
onTapItem.call(index);
},
);
}).toList(),
);
}
}
class LeftNavigationBarItemWidget extends StatefulWidget {
final MenuMeta item;
final bool selected;
final VoidCallback onTap;
const LeftNavigationBarItemWidget(
{Key? key,
required this.item,
required this.selected,
required this.onTap})
: super(key: key);
@override
State<LeftNavigationBarItemWidget> createState() =>
_LeftNavigationBarItemWidgetState();
}
class _LeftNavigationBarItemWidgetState
extends State<LeftNavigationBarItemWidget> {
bool _hover = false;
@override
Widget build(BuildContext context) {
Color? bgColor;
Color iconColor;
if (widget.selected) {
bgColor = Colors.white.withOpacity(0.2);
iconColor = Colors.white;
} else {
bgColor = _hover ? Colors.white.withOpacity(0.1) : null;
iconColor = Colors.white.withOpacity(0.8);
}
return InkWell(
onTap: widget.selected
? null
: () {
widget.onTap();
setState(() {
_hover = false;
});
},
onHover: widget.selected
? null
: (v) {
setState(() {
_hover = v;
});
},
child: Container(
alignment: Alignment.center,
margin: EdgeInsets.only(bottom: 10),
width: 50,
height: 50,
decoration: BoxDecoration(
color: bgColor, borderRadius: BorderRadius.circular(8)),
child: Wrap(
direction: Axis.vertical,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 2,
children: [
Icon(
widget.item.icon,
color: iconColor,
),
Text(
widget.item.label,
style: TextStyle(color: iconColor, fontSize: 12),
)
],
),
),
);
}
}

View File

@@ -0,0 +1,4 @@
export 'navigation/menu_meta.dart';
export 'navigation/toly_breadcrumb.dart';
export 'navigation/toly_navigation_rail.dart';

View File

@@ -0,0 +1,80 @@
import 'package:flutter/material.dart';
import 'package:window_manager/window_manager.dart';
class WindowButtons extends StatefulWidget {
final List<Widget>? actions;
const WindowButtons({Key? key, this.actions}) : super(key: key);
@override
State<WindowButtons> createState() => _WindowButtonsState();
}
class _WindowButtonsState extends State<WindowButtons> {
@override
Widget build(BuildContext context) {
Brightness brightness = Theme.of(context).brightness;
return Align(
alignment:Alignment.topRight,child: Wrap(
spacing: 5,
children: [
if(widget.actions!=null)
...widget.actions!,
SizedBox(
width: 30,
height: 30,
child: WindowCaptionButton.minimize(
brightness:brightness,
onPressed: () async {
bool isMinimized = await windowManager.isMinimized();
if (isMinimized) {
windowManager.restore();
} else {
windowManager.minimize();
}
},
),
),
SizedBox(
width: 30,
height: 30,
child: FutureBuilder<bool>(
future: windowManager.isMaximized(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (snapshot.data == true) {
return WindowCaptionButton.unmaximize(
brightness: brightness,
onPressed: () async{
await windowManager.unmaximize();
setState(() {
});
},
);
}
return WindowCaptionButton.maximize(
brightness: brightness,
onPressed: () async{
await windowManager.maximize();
setState(() {
});
},
);
},
),
),
SizedBox(
height: 30,
width: 30,
child: WindowCaptionButton.close(
brightness: brightness,
onPressed: () {
windowManager.close();
},
),
),
],
),
);
}
}