This commit is contained in:
toly
2023-12-16 12:40:32 +08:00
parent ab2778a22b
commit 01fdf966c5
593 changed files with 8995 additions and 27753 deletions

View File

@@ -0,0 +1,53 @@
import 'package:components/components.dart';
import 'package:flutter/material.dart';
import 'package:toly_menu/src/menu.dart';
import 'package:toly_menu/toly_menu.dart';
import '../router/menus/menu_scope/menu_scope.dart';
import 'menu_record.dart';
import 'top_logo.dart';
import 'top_bar.dart';
class TolyBookNavigation extends StatelessWidget {
final Widget content;
const TolyBookNavigation({super.key, required this.content});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
DragToMoveWrap(
child: Container(
color: const Color(0xff001529),
width: 210,
child: Column(
children: [
TopLogo(),
Expanded(child: MenuTreeView()),
],
),
),
),
Expanded(
child: Column(
children: [
ColoredBox(
color: const Color(0xffF2F2F2),
child: AppTopBar()),
MenuRecord() ,
Expanded(child: content)],
),
)
],
),
);
}
}
class MenuTreeView extends StatelessWidget {
@override
Widget build(BuildContext context) {
MenuStore store = MenuScope.of(context);
return TolyMenu(state: store.state, onSelect: store.select);
}
}

View File

@@ -0,0 +1,131 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/gestures/events.dart';
import 'package:iroute/navigation/router/menus/menu_scope/menu_history.dart';
import 'package:iroute/navigation/router/menus/menu_scope/menu_scope.dart';
class MenuRecord extends StatelessWidget {
const MenuRecord({super.key});
@override
Widget build(BuildContext context) {
MenuStore store = MenuScope.of(context);
List<MenuHistory> history = MenuScope.of(context).history;
const BorderSide side = BorderSide(color: Color(0xffE8E8E8), width: 1);
Color themeColor = Theme.of(context).primaryColor;
return Container(
alignment: Alignment.centerLeft,
decoration: BoxDecoration(
color: const Color(0xffF2F2F2),
border: Border(top: side, bottom: side)),
height: 28,
child: ListView(
scrollDirection: Axis.horizontal,
children: history
.map((e) => RecordTab(
canClose: history.length > 1,
onCloseHistory: store.closeHistory,
onTapHistory: store.selectHistory,
active: store.state.activeMenu == e.menuPath,
history: e,
))
.toList()),
);
}
}
class RecordTab extends StatelessWidget {
final bool active;
final bool canClose;
final MenuHistory history;
final ValueChanged<MenuHistory> onCloseHistory;
final ValueChanged<String> onTapHistory;
const RecordTab({
super.key,
this.active = false,
required this.canClose,
required this.history,
required this.onCloseHistory,
required this.onTapHistory,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: ()=>onTapHistory(history.menuPath),
child: ColoredBox(
color: active ? Colors.white : Colors.transparent,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Text(
history.menuLabel,
style: TextStyle(
fontSize: 12,
),
),
const SizedBox(
width: 2,
),
if(canClose)
CloseHoverButton(
onPressed: ()=>onCloseHistory(history)
)
],
),
),
),
),
);
}
}
class CloseHoverButton extends StatefulWidget {
final VoidCallback onPressed;
const CloseHoverButton({super.key, required this.onPressed});
@override
State<CloseHoverButton> createState() => _CloseHoverButtonState();
}
class _CloseHoverButtonState extends State<CloseHoverButton> {
bool _isHover = false;
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: widget.onPressed,
child: MouseRegion(
cursor: SystemMouseCursors.click,
onExit: _onExit,
onEnter: _onEnter,
child: Container(
padding: EdgeInsets.all(3),
decoration: BoxDecoration(
color: _isHover ? Color(0xffBFC5C8) : Colors.transparent,
borderRadius: BorderRadius.circular(10)),
child: Icon(
CupertinoIcons.clear_thick,
size: 10,
color: _isHover ? Colors.white : Colors.grey,
)),
),
);
}
void _onExit(PointerExitEvent event) {
setState(() {
_isHover = false;
});
}
void _onEnter(PointerEnterEvent event) {
setState(() {
_isHover = true;
});
}
}

View File

@@ -1,25 +1,162 @@
import 'package:components/components.dart';
import 'package:flutter/material.dart';
import '../../components/components.dart';
import 'package:go_router/go_router.dart';
import 'package:iroute/navigation/router/menus/menu_scope/menu_scope.dart';
class AppTopBar extends StatelessWidget {
const AppTopBar({super.key});
@override
Widget build(BuildContext context) {
// String? lable = MenuScope.of(context).currentNode?.label;
return DragToMoveWrap(
child: const Row(
children: [
SizedBox(width: 20,),
// Text(
// '404 界面丢失',
// style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
// ),
Spacer(),
WindowButtons()
],
child: Stack(
alignment: Alignment.centerRight,
children: [Row(
children: [
SizedBox(width: 20,),
RouteBackIndicator(),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: RouterIndicator(),
),
// Text(
// '$lable',
// style: TextStyle(fontSize: 14),
// ),
Spacer(),
],
),WindowButtons()]
),
);
}
}
class RouteBackIndicator extends StatefulWidget {
const RouteBackIndicator({super.key});
@override
State<RouteBackIndicator> createState() => _RouteBackIndicatorState();
}
class _RouteBackIndicatorState extends State<RouteBackIndicator> {
late GoRouterDelegate _delegate ;
@override
void initState() {
super.initState();
_delegate = GoRouter.of(context).routerDelegate;
_delegate.addListener(_onChange);
}
@override
void dispose() {
_delegate.removeListener(_onChange);
super.dispose();
}
@override
Widget build(BuildContext context) {
bool hasPush = _delegate.currentConfiguration.matches
.whereType<ImperativeRouteMatch>().isNotEmpty;
if(hasPush){
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: context.pop,
child: Container(
width: 20,
height: 20,
margin: EdgeInsets.only(right: 8),
alignment: Alignment.center,
decoration: BoxDecoration(
color: Color(0xffE3E5E7),
borderRadius: BorderRadius.circular(6)
),
child: Icon(Icons.arrow_back_ios_new,size: 14,)),
),
);
}
return SizedBox();
}
void _onChange() {
setState(() {
});
}
}
class RouterIndicator extends StatefulWidget {
const RouterIndicator({super.key});
@override
State<RouterIndicator> createState() => _RouterIndicatorState();
}
class _RouterIndicatorState extends State<RouterIndicator> {
late GoRouterDelegate _delegate;
@override
void initState() {
super.initState();
_delegate = GoRouter.of(context).routerDelegate;
_delegate.addListener(_onRouterChange);
}
@override
void dispose() {
_delegate.removeListener(_onRouterChange);
super.dispose();
}
@override
Widget build(BuildContext context) {
List<RouteMatch> matches = _delegate.currentConfiguration.matches;
if(matches.isEmpty) return const SizedBox();
RouteMatch match = _delegate.currentConfiguration.matches.last;
print(
"=========_RouterIndicatorState:build==${match.matchedLocation}========");
return TolyBreadcrumb(
fontSize: 12,
items: pathToBreadcrumbItems(context, match.matchedLocation),
onTapItem: (item) {
if (item.to != null) {
GoRouter.of(context).go(item.to!);
}
},
);
}
void _onRouterChange() {
setState(() {});
}
List<BreadcrumbItem> pathToBreadcrumbItems(
BuildContext context, String path) {
Uri uri = Uri.parse(path);
List<BreadcrumbItem> result = [];
String to = '';
String distPath = '';
for (String segment in uri.pathSegments) {
distPath += '/$segment';
}
for (String segment in uri.pathSegments) {
to += '/$segment';
String? label;
if(to=='/code'){
label = '代码详情';
}else{
label = MenuScope.read(context).pathName(to);
}
if (label!=null&&label.isNotEmpty) {
result
.add(BreadcrumbItem(to: to, label: label, active: to == distPath));
}
}
return result;
}
}