v7
This commit is contained in:
@@ -16,7 +16,7 @@ class HoverIconButton extends StatefulWidget {
|
|||||||
this.hoverColor,
|
this.hoverColor,
|
||||||
this.size = 24,
|
this.size = 24,
|
||||||
this.defaultColor,
|
this.defaultColor,
|
||||||
this.cursor = SystemMouseCursors.cell,
|
this.cursor = SystemMouseCursors.click,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ class MenuMeta {
|
|||||||
// 标签
|
// 标签
|
||||||
final String label;
|
final String label;
|
||||||
|
|
||||||
|
final String? path;
|
||||||
|
|
||||||
// 图标数据
|
// 图标数据
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
|
|
||||||
@@ -12,6 +14,7 @@ class MenuMeta {
|
|||||||
|
|
||||||
const MenuMeta({
|
const MenuMeta({
|
||||||
required this.label,
|
required this.label,
|
||||||
|
this.path,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
this.color,
|
this.color,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:window_manager/window_manager.dart';
|
import 'package:window_manager/window_manager.dart';
|
||||||
|
|
||||||
import 'v7/app.dart';
|
import 'v8/app.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|||||||
@@ -1,237 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import '../../../pages/color/color_detail_page.dart';
|
|
||||||
import '../../../pages/color/color_page.dart';
|
|
||||||
import '../../../pages/empty/empty_page.dart';
|
|
||||||
import '../../../pages/settings/settings_page.dart';
|
|
||||||
import '../../../pages/user/user_page.dart';
|
|
||||||
import '../../../pages/counter/counter_page.dart';
|
|
||||||
import '../transition/fade_transition_page.dart';
|
|
||||||
import '../../../pages/color/color_add_page.dart';
|
|
||||||
|
|
||||||
const List<String> kDestinationsPaths = [
|
|
||||||
'/color',
|
|
||||||
'/counter',
|
|
||||||
'/user',
|
|
||||||
'/settings',
|
|
||||||
];
|
|
||||||
|
|
||||||
AppRouterDelegate router = AppRouterDelegate();
|
|
||||||
|
|
||||||
class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
|
||||||
|
|
||||||
AppRouterDelegate({String initial = '/'}){
|
|
||||||
// changePath('/color',keepAlive: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
String _path = '/color';
|
|
||||||
|
|
||||||
String get path => _path;
|
|
||||||
|
|
||||||
int? get activeIndex {
|
|
||||||
if(path.startsWith('/color')) return 0;
|
|
||||||
if(path.startsWith('/counter')) return 1;
|
|
||||||
if(path.startsWith('/user')) return 2;
|
|
||||||
if(path.startsWith('/settings')) return 3;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String,Completer<dynamic>> _completerMap = {};
|
|
||||||
|
|
||||||
Completer<dynamic>? completer;
|
|
||||||
|
|
||||||
final Map<String,List<Page>> _alivePageMap = {};
|
|
||||||
|
|
||||||
void setPathKeepLive(String value){
|
|
||||||
_alivePageMap[value] = _buildPageByPath(value);
|
|
||||||
path = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String,dynamic> _pathExtraMap = {};
|
|
||||||
|
|
||||||
FutureOr<dynamic> changePath(String value,{bool forResult=false,Object? extra,bool keepAlive = false}){
|
|
||||||
if(forResult){
|
|
||||||
_completerMap[value] = Completer();
|
|
||||||
}
|
|
||||||
if(keepAlive){
|
|
||||||
_alivePageMap[value] = _buildPageByPath(value);
|
|
||||||
}
|
|
||||||
if(extra!=null){
|
|
||||||
_pathExtraMap[value] = extra;
|
|
||||||
}
|
|
||||||
path = value;
|
|
||||||
if(forResult){
|
|
||||||
return _completerMap[value]!.future;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
set path(String value) {
|
|
||||||
if (_path == value) return;
|
|
||||||
_path = value;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
List<Page> pages = [];
|
|
||||||
if(_alivePageMap.containsKey(path)){
|
|
||||||
for (String key in _alivePageMap.keys) {
|
|
||||||
if(path!=key){
|
|
||||||
pages.addAll(_alivePageMap[key]!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pages.addAll(_alivePageMap[path]!) ;
|
|
||||||
}else{
|
|
||||||
for (var element in _alivePageMap.values) {
|
|
||||||
pages.addAll(element);
|
|
||||||
}
|
|
||||||
List<Page> currentPages = _buildPageByPath(path);
|
|
||||||
pages.removeWhere((element) {
|
|
||||||
return currentPages.map((e) => e.key).contains(element.key);
|
|
||||||
});
|
|
||||||
// 移除 pages 中和 currentPages 具有相同key 的元素
|
|
||||||
pages.addAll(_buildPageByPath(path));
|
|
||||||
}
|
|
||||||
return Navigator(
|
|
||||||
onPopPage: _onPopPage,
|
|
||||||
pages: pages,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Page> _buildPageByPath(String path) {
|
|
||||||
Widget? child;
|
|
||||||
if(path.startsWith('/color')){
|
|
||||||
return buildColorPages(path);
|
|
||||||
}
|
|
||||||
if (path == kDestinationsPaths[1]) {
|
|
||||||
child = const CounterPage();
|
|
||||||
}
|
|
||||||
if (path == kDestinationsPaths[2]) {
|
|
||||||
child = const UserPage();
|
|
||||||
}
|
|
||||||
if (path == kDestinationsPaths[3]) {
|
|
||||||
child = const SettingPage();
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
FadeTransitionPage(
|
|
||||||
key: ValueKey(path),
|
|
||||||
child: child ?? const EmptyPage(),
|
|
||||||
)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Page> buildColorPages(String path){
|
|
||||||
List<Page> result = [];
|
|
||||||
Uri uri = Uri.parse(path);
|
|
||||||
for (String segment in uri.pathSegments) {
|
|
||||||
if(segment == 'color'){
|
|
||||||
result.add( const FadeTransitionPage(
|
|
||||||
key: ValueKey('/color'),
|
|
||||||
child:ColorPage(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if(segment =='detail'){
|
|
||||||
final Map<String, String> queryParams = uri.queryParameters;
|
|
||||||
String? selectedColor = queryParams['color'];
|
|
||||||
|
|
||||||
if (selectedColor != null) {
|
|
||||||
Color color = Color(int.parse(selectedColor, radix: 16));
|
|
||||||
result.add( FadeTransitionPage(
|
|
||||||
key: const ValueKey('/color/detail'),
|
|
||||||
child:ColorDetailPage(color: color),
|
|
||||||
));
|
|
||||||
}else{
|
|
||||||
Color? selectedColor = _pathExtraMap[path];
|
|
||||||
if (selectedColor != null) {
|
|
||||||
result.add( FadeTransitionPage(
|
|
||||||
key: const ValueKey('/color/detail'),
|
|
||||||
child:ColorDetailPage(color: selectedColor),
|
|
||||||
));
|
|
||||||
_pathExtraMap.remove(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(segment == 'add'){
|
|
||||||
result.add( const FadeTransitionPage(
|
|
||||||
key: ValueKey('/color/add'),
|
|
||||||
child:ColorAddPage(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<bool> popRoute() async {
|
|
||||||
print('=======popRoute=========');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _onPopPage(Route route, result) {
|
|
||||||
if(_completerMap.containsKey(path)){
|
|
||||||
_completerMap[path]?.complete(result);
|
|
||||||
_completerMap.remove(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
path = backPath(path);
|
|
||||||
return route.didPop(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
String backPath(String path){
|
|
||||||
Uri uri = Uri.parse(path);
|
|
||||||
if(uri.pathSegments.length==1) return path;
|
|
||||||
List<String> parts = List.of(uri.pathSegments)..removeLast();
|
|
||||||
return '/${parts.join('/')}';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> setNewRoutePath(configuration) async {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// class AppRouterDelegate extends RouterDelegate<String> with ChangeNotifier, PopNavigatorRouterDelegateMixin {
|
|
||||||
//
|
|
||||||
// List<String> _value = ['/'];
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// List<String> get value => _value;
|
|
||||||
//
|
|
||||||
// set value(List<String> value){
|
|
||||||
// _value = value;
|
|
||||||
// notifyListeners();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// Widget build(BuildContext context) {
|
|
||||||
// return Navigator(
|
|
||||||
// onPopPage: _onPopPage,
|
|
||||||
// pages: _value.map((e) => _pageMap[e]!).toList(),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final Map<String, Page> _pageMap = const {
|
|
||||||
// '/': MaterialPage(child: HomePage()),
|
|
||||||
// 'a': MaterialPage(child: PageA()),
|
|
||||||
// 'b': MaterialPage(child: PageB()),
|
|
||||||
// 'c': MaterialPage(child: PageC()),
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// bool _onPopPage(Route route, result) {
|
|
||||||
// _value = List.of(_value)..removeLast();
|
|
||||||
// notifyListeners();
|
|
||||||
// return route.didPop(result);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// GlobalKey<NavigatorState>? navigatorKey = GlobalKey<NavigatorState>();
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// Future<void> setNewRoutePath(String configuration) async{
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
|
|
||||||
import '../../../pages/color/color_add_page.dart';
|
|
||||||
import '../../../pages/color/color_detail_page.dart';
|
|
||||||
import '../../../pages/color/color_page.dart';
|
|
||||||
import '../transition/fade_transition_page.dart';
|
|
||||||
|
|
||||||
class IRoute {
|
|
||||||
final String path;
|
|
||||||
final IRoutePageBuilder builder;
|
|
||||||
final List<IRoute> children;
|
|
||||||
|
|
||||||
const IRoute({
|
|
||||||
required this.path,
|
|
||||||
this.children = const [],
|
|
||||||
required this.builder,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'IRoute{path: $path, children: $children}';
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> list() {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef IRoutePageBuilder = Page? Function(
|
|
||||||
BuildContext context, IRouteData data);
|
|
||||||
|
|
||||||
class IRouteData {
|
|
||||||
final Object? extra;
|
|
||||||
final bool forResult;
|
|
||||||
final Uri uri;
|
|
||||||
final bool keepAlive;
|
|
||||||
|
|
||||||
IRouteData({
|
|
||||||
required this.extra,
|
|
||||||
required this.uri,
|
|
||||||
required this.forResult,
|
|
||||||
required this.keepAlive,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IRoute> kDestinationsIRoutes = [
|
|
||||||
IRoute(
|
|
||||||
path: '/color',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/color'),
|
|
||||||
child: ColorPage(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
IRoute(
|
|
||||||
path: '/color/detail',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
final Map<String, String> queryParams = data.uri.queryParameters;
|
|
||||||
String? selectedColor = queryParams['color'];
|
|
||||||
if (selectedColor != null) {
|
|
||||||
Color color = Color(int.parse(selectedColor, radix: 16));
|
|
||||||
return FadeTransitionPage(
|
|
||||||
key: const ValueKey('/color/detail'),
|
|
||||||
child: ColorDetailPage(color: color),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
IRoute(
|
|
||||||
path: '/color/add',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/color/add'),
|
|
||||||
child: ColorAddPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
IRoute(
|
|
||||||
path: '/counter',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/counter'),
|
|
||||||
child: ColorAddPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
IRoute(
|
|
||||||
path: '/user',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/user'),
|
|
||||||
child: ColorAddPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
IRoute(
|
|
||||||
path: '/settings',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/settings'),
|
|
||||||
child: ColorAddPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
// Copyright 2021, the Flutter project authors. Please see the AUTHORS file
|
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
|
||||||
// BSD-style license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class FadeTransitionPage<T> extends Page<T> {
|
|
||||||
final Widget child;
|
|
||||||
final Duration duration;
|
|
||||||
|
|
||||||
const FadeTransitionPage({
|
|
||||||
super.key,
|
|
||||||
required this.child,
|
|
||||||
this.duration = const Duration(milliseconds: 300),
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Route<T> createRoute(BuildContext context) =>
|
|
||||||
PageBasedFadeTransitionRoute<T>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
class PageBasedFadeTransitionRoute<T> extends PageRoute<T> {
|
|
||||||
final FadeTransitionPage<T> _page;
|
|
||||||
|
|
||||||
PageBasedFadeTransitionRoute(this._page) : super(settings: _page);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Color? get barrierColor => null;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? get barrierLabel => null;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Duration get transitionDuration => _page.duration;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool get maintainState => true;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget buildPage(BuildContext context, Animation<double> animation,
|
|
||||||
Animation<double> secondaryAnimation) {
|
|
||||||
var curveTween = CurveTween(curve: Curves.easeIn);
|
|
||||||
return FadeTransition(
|
|
||||||
opacity: animation.drive(curveTween),
|
|
||||||
child: (settings as FadeTransitionPage).child,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget buildTransitions(BuildContext context, Animation<double> animation,
|
|
||||||
Animation<double> secondaryAnimation, Widget child) =>
|
|
||||||
child;
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import '../router/app_router_delegate.dart';
|
|
||||||
import 'app_navigation_rail.dart';
|
|
||||||
import 'app_top_bar.dart';
|
|
||||||
|
|
||||||
class AppNavigation extends StatelessWidget {
|
|
||||||
const AppNavigation({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
double px1 = 1/View.of(context).devicePixelRatio;
|
|
||||||
return Scaffold(
|
|
||||||
body: Row(
|
|
||||||
children: [
|
|
||||||
const AppNavigationRail(),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
const AppTopBar(),
|
|
||||||
Divider(height: px1,),
|
|
||||||
Expanded(
|
|
||||||
child: Router(
|
|
||||||
routerDelegate: router,
|
|
||||||
backButtonDispatcher: RootBackButtonDispatcher(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:iroute/components/toly_ui/button/hover_icon_button.dart';
|
|
||||||
import '../router/app_router_delegate.dart';
|
|
||||||
|
|
||||||
class AppRouterEditor extends StatefulWidget {
|
|
||||||
final ValueChanged<String>? onSubmit;
|
|
||||||
const AppRouterEditor({super.key, this.onSubmit});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<AppRouterEditor> createState() => _AppRouterEditorState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AppRouterEditorState extends State<AppRouterEditor> {
|
|
||||||
|
|
||||||
final TextEditingController _controller = TextEditingController();
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_onRouteChange();
|
|
||||||
router.addListener(_onRouteChange);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onRouteChange() {
|
|
||||||
_controller.text=router.path;
|
|
||||||
setState(() {
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
router.removeListener(_onRouteChange);
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SizedBox(
|
|
||||||
width: 250,
|
|
||||||
child: Stack(
|
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
child: CupertinoTextField(
|
|
||||||
controller: _controller,
|
|
||||||
style: TextStyle(fontSize: 14),
|
|
||||||
padding: EdgeInsets.only(left:12,top: 6,bottom: 6,right: 32),
|
|
||||||
placeholder: '输入路由地址导航',
|
|
||||||
onSubmitted: widget.onSubmit,
|
|
||||||
decoration: BoxDecoration(color: Color(0xffF1F2F3),borderRadius: BorderRadius.circular(6)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 8.0),
|
|
||||||
child: HoverIconButton(
|
|
||||||
icon: Icons.directions_outlined,
|
|
||||||
defaultColor: Color(0xff68696B),
|
|
||||||
onPressed:()=>widget.onSubmit?.call(_controller.text),
|
|
||||||
size: 20
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:iroute/components/components.dart';
|
|
||||||
import '../router/app_router_delegate.dart';
|
|
||||||
import 'app_router_editor.dart';
|
|
||||||
|
|
||||||
class AppTopBar extends StatelessWidget {
|
|
||||||
const AppTopBar({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return DragToMoveWrap(
|
|
||||||
child: Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
height: 46,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
const RouterIndicator(),
|
|
||||||
Expanded(
|
|
||||||
child: Row(children: [
|
|
||||||
const Spacer(),
|
|
||||||
SizedBox(
|
|
||||||
// width: 200,
|
|
||||||
child: AppRouterEditor(
|
|
||||||
onSubmit: (path) => router.path = path,
|
|
||||||
)),
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 12.0),
|
|
||||||
child: VerticalDivider(
|
|
||||||
width: 32,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
])),
|
|
||||||
const WindowButtons()
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RouterIndicator extends StatefulWidget {
|
|
||||||
const RouterIndicator({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<RouterIndicator> createState() => _RouterIndicatorState();
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> kRouteLabelMap = {
|
|
||||||
'/color': '颜色板',
|
|
||||||
'/color/add': '添加颜色',
|
|
||||||
'/color/detail': '颜色详情',
|
|
||||||
'/counter': '计数器',
|
|
||||||
'/user': '我的',
|
|
||||||
'/settings': '系统设置',
|
|
||||||
};
|
|
||||||
|
|
||||||
class _RouterIndicatorState extends State<RouterIndicator> {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
router.addListener(_onRouterChange);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
router.removeListener(_onRouterChange);
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return TolyBreadcrumb(
|
|
||||||
items: pathToBreadcrumbItems(router.path),
|
|
||||||
onTapItem: (item) {
|
|
||||||
if (item.to != null) {
|
|
||||||
router.path = item.to!;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onRouterChange() {
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
|
|
||||||
List<BreadcrumbItem> pathToBreadcrumbItems(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 = kRouteLabelMap[to] ?? '未知路由';
|
|
||||||
result.add(BreadcrumbItem(to: to, label: label, active: to == distPath));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'navigation/views/app_navigation.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class UnitApp extends StatelessWidget {
|
|
||||||
const UnitApp({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return MaterialApp(
|
|
||||||
theme: ThemeData(
|
|
||||||
fontFamily: "宋体",
|
|
||||||
scaffoldBackgroundColor: Colors.white,
|
|
||||||
appBarTheme: const AppBarTheme(
|
|
||||||
elevation: 0,
|
|
||||||
iconTheme: IconThemeData(color: Colors.black),
|
|
||||||
titleTextStyle: TextStyle(
|
|
||||||
color: Colors.black,
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
))),
|
|
||||||
debugShowCheckedModeBanner: false,
|
|
||||||
home: AppNavigation()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
|
|
||||||
|
|
||||||
class ColorAddPage extends StatefulWidget {
|
|
||||||
const ColorAddPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ColorAddPage> createState() => _ColorAddPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ColorAddPageState extends State<ColorAddPage> {
|
|
||||||
late Color _color;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_color = randomColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
String text = '# ${_color.value.toRadixString(16)}';
|
|
||||||
return Scaffold(
|
|
||||||
bottomNavigationBar: Container(
|
|
||||||
margin: EdgeInsets.only(right:20,bottom: 20),
|
|
||||||
// color: Colors.redAccent,
|
|
||||||
child: Row(
|
|
||||||
textDirection:TextDirection.rtl,
|
|
||||||
children: [
|
|
||||||
ElevatedButton(onPressed: (){
|
|
||||||
Navigator.of(context).pop(_color);
|
|
||||||
|
|
||||||
}, child: Text('添加')),
|
|
||||||
SizedBox(width: 12,),
|
|
||||||
OutlinedButton(onPressed: (){
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
}, child: Text('取消')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: Column(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0,vertical: 16),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Expanded(child: Text(text,style: TextStyle(color: _color,fontSize: 24,letterSpacing: 4),)),
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.only(left: 10),
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
child: Icon(
|
|
||||||
Icons.sell_outlined,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: _color,
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ColorPicker(
|
|
||||||
colorPickerWidth:200,
|
|
||||||
// enableAlpha: false,
|
|
||||||
displayThumbColor:true,
|
|
||||||
pickerColor: _color,
|
|
||||||
paletteType: PaletteType.hueWheel,
|
|
||||||
onColorChanged: changeColor,
|
|
||||||
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Random _random = Random();
|
|
||||||
|
|
||||||
Color get randomColor {
|
|
||||||
return Color.fromARGB(
|
|
||||||
255,
|
|
||||||
_random.nextInt(256),
|
|
||||||
_random.nextInt(256),
|
|
||||||
_random.nextInt(256),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _selectColor() {
|
|
||||||
Navigator.of(context).pop(_color);
|
|
||||||
}
|
|
||||||
|
|
||||||
void changeColor(Color value) {
|
|
||||||
_color = value;
|
|
||||||
setState(() {
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
class ColorDetailPage extends StatelessWidget {
|
|
||||||
final Color color;
|
|
||||||
const ColorDetailPage({super.key, required this.color});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
|
|
||||||
const TextStyle style = TextStyle(
|
|
||||||
fontSize: 32,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.white
|
|
||||||
);
|
|
||||||
String text = '# ${color.value.toRadixString(16)}';
|
|
||||||
return Scaffold(
|
|
||||||
// appBar: AppBar(
|
|
||||||
// systemOverlayStyle: SystemUiOverlayStyle(
|
|
||||||
// statusBarColor: Colors.transparent,
|
|
||||||
// statusBarIconBrightness: Brightness.light
|
|
||||||
// ),
|
|
||||||
// iconTheme: IconThemeData(color: Colors.white),
|
|
||||||
// titleTextStyle:TextStyle(color: Colors.white,fontSize: 18) ,
|
|
||||||
// backgroundColor: color,
|
|
||||||
// title: Text('颜色界面',),),
|
|
||||||
body: Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
color: color,
|
|
||||||
child: Text(text ,style: style,),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:iroute/components/project/colors_panel.dart';
|
|
||||||
import '../../app/navigation/router/app_router_delegate.dart';
|
|
||||||
|
|
||||||
class ColorPage extends StatefulWidget {
|
|
||||||
const ColorPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ColorPage> createState() => _ColorPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ColorPageState extends State<ColorPage> {
|
|
||||||
final List<Color> _colors = [
|
|
||||||
Colors.red, Colors.black, Colors.blue, Colors.green, Colors.orange,
|
|
||||||
Colors.pink, Colors.purple, Colors.indigo, Colors.amber, Colors.cyan,
|
|
||||||
Colors.redAccent, Colors.grey, Colors.blueAccent, Colors.greenAccent, Colors.orangeAccent,
|
|
||||||
Colors.pinkAccent, Colors.purpleAccent, Colors.indigoAccent, Colors.amberAccent, Colors.cyanAccent,
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
// appBar: AppBar(title:const Text('颜色主页')),
|
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
onPressed: _toAddPage,
|
|
||||||
child: const Icon(Icons.add),
|
|
||||||
),
|
|
||||||
body: Align(
|
|
||||||
alignment: Alignment.topCenter,
|
|
||||||
child: ColorsPanel(
|
|
||||||
colors: _colors,
|
|
||||||
onSelect: _selectColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _selectColor(Color color){
|
|
||||||
String value = color.value.toRadixString(16);
|
|
||||||
router.path = '/color/detail?color=$value';
|
|
||||||
// router.setPathForData('/color/detail',color);
|
|
||||||
// router.setPathKeepLive('/color/detail?color=$value');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void _toAddPage() async {
|
|
||||||
Color? color = await router.changePath('/color/add',forResult: true);
|
|
||||||
if (color != null) {
|
|
||||||
setState(() {
|
|
||||||
_colors.add(color);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export 'app/unit_app.dart';
|
|
||||||
@@ -1,245 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import '../../../pages/color/color_detail_page.dart';
|
|
||||||
import '../../../pages/color/color_page.dart';
|
|
||||||
import '../../../pages/empty/empty_page.dart';
|
|
||||||
import '../../../pages/settings/settings_page.dart';
|
|
||||||
import '../../../pages/user/user_page.dart';
|
|
||||||
import '../../../pages/counter/counter_page.dart';
|
|
||||||
import '../../../pages/sort/views/sort_page.dart';
|
|
||||||
import '../transition/fade_transition_page.dart';
|
|
||||||
import '../../../pages/color/color_add_page.dart';
|
|
||||||
|
|
||||||
const List<String> kDestinationsPaths = [
|
|
||||||
'/color',
|
|
||||||
'/counter',
|
|
||||||
'/sort',
|
|
||||||
'/user',
|
|
||||||
'/settings',
|
|
||||||
];
|
|
||||||
|
|
||||||
AppRouterDelegate router = AppRouterDelegate();
|
|
||||||
|
|
||||||
class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
|
||||||
|
|
||||||
AppRouterDelegate({String initial = '/'}){
|
|
||||||
changePath('/color',keepAlive: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
String _path = '/color';
|
|
||||||
|
|
||||||
String get path => _path;
|
|
||||||
|
|
||||||
int? get activeIndex {
|
|
||||||
if(path.startsWith('/color')) return 0;
|
|
||||||
if(path.startsWith('/counter')) return 1;
|
|
||||||
if(path.startsWith('/sort')) return 2;
|
|
||||||
if(path.startsWith('/user')) return 3;
|
|
||||||
if(path.startsWith('/settings')) return 4;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String,Completer<dynamic>> _completerMap = {};
|
|
||||||
|
|
||||||
Completer<dynamic>? completer;
|
|
||||||
|
|
||||||
final Map<String,List<Page>> _alivePageMap = {};
|
|
||||||
|
|
||||||
void setPathKeepLive(String value){
|
|
||||||
_alivePageMap[value] = _buildPageByPath(value);
|
|
||||||
path = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String,dynamic> _pathExtraMap = {};
|
|
||||||
|
|
||||||
FutureOr<dynamic> changePath(String value,{bool forResult=false,Object? extra,bool keepAlive = false}){
|
|
||||||
if(forResult){
|
|
||||||
_completerMap[value] = Completer();
|
|
||||||
}
|
|
||||||
if(keepAlive){
|
|
||||||
_alivePageMap[value] = _buildPageByPath(value);
|
|
||||||
}
|
|
||||||
if(extra!=null){
|
|
||||||
_pathExtraMap[value] = extra;
|
|
||||||
}
|
|
||||||
path = value;
|
|
||||||
if(forResult){
|
|
||||||
return _completerMap[value]!.future;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
set path(String value) {
|
|
||||||
if (_path == value) return;
|
|
||||||
_path = value;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
List<Page> pages = [];
|
|
||||||
if(_alivePageMap.containsKey(path)){
|
|
||||||
for (String key in _alivePageMap.keys) {
|
|
||||||
if(path!=key){
|
|
||||||
pages.addAll(_alivePageMap[key]!);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pages.addAll(_alivePageMap[path]!) ;
|
|
||||||
}else{
|
|
||||||
for (var element in _alivePageMap.values) {
|
|
||||||
pages.addAll(element);
|
|
||||||
}
|
|
||||||
List<Page> currentPages = _buildPageByPath(path);
|
|
||||||
pages.removeWhere((element) {
|
|
||||||
return currentPages.map((e) => e.key).contains(element.key);
|
|
||||||
});
|
|
||||||
// 移除 pages 中和 currentPages 具有相同key 的元素
|
|
||||||
pages.addAll(_buildPageByPath(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Navigator(
|
|
||||||
onPopPage: _onPopPage,
|
|
||||||
pages: pages.toSet().toList(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Page> _buildPageByPath(String path) {
|
|
||||||
Widget? child;
|
|
||||||
if(path.startsWith('/color')){
|
|
||||||
return buildColorPages(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path == kDestinationsPaths[1]) {
|
|
||||||
child = const CounterPage();
|
|
||||||
}
|
|
||||||
if (path == kDestinationsPaths[2]) {
|
|
||||||
child = SortPage();
|
|
||||||
}
|
|
||||||
if (path == kDestinationsPaths[3]) {
|
|
||||||
child = const UserPage();
|
|
||||||
}
|
|
||||||
if (path == kDestinationsPaths[4]) {
|
|
||||||
child = const SettingPage();
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
FadeTransitionPage(
|
|
||||||
key: ValueKey(path),
|
|
||||||
child: child ?? const EmptyPage(),
|
|
||||||
)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Page> buildColorPages(String path){
|
|
||||||
List<Page> result = [];
|
|
||||||
Uri uri = Uri.parse(path);
|
|
||||||
for (String segment in uri.pathSegments) {
|
|
||||||
if(segment == 'color'){
|
|
||||||
result.add( const FadeTransitionPage(
|
|
||||||
key: ValueKey('/color'),
|
|
||||||
child:ColorPage(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
if(segment =='detail'){
|
|
||||||
final Map<String, String> queryParams = uri.queryParameters;
|
|
||||||
String? selectedColor = queryParams['color'];
|
|
||||||
|
|
||||||
if (selectedColor != null) {
|
|
||||||
Color color = Color(int.parse(selectedColor, radix: 16));
|
|
||||||
result.add( FadeTransitionPage(
|
|
||||||
key: const ValueKey('/color/detail'),
|
|
||||||
child:ColorDetailPage(color: color),
|
|
||||||
));
|
|
||||||
}else{
|
|
||||||
Color? selectedColor = _pathExtraMap[path];
|
|
||||||
if (selectedColor != null) {
|
|
||||||
result.add( FadeTransitionPage(
|
|
||||||
key: const ValueKey('/color/detail'),
|
|
||||||
child:ColorDetailPage(color: selectedColor),
|
|
||||||
));
|
|
||||||
_pathExtraMap.remove(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(segment == 'add'){
|
|
||||||
result.add( const FadeTransitionPage(
|
|
||||||
key: ValueKey('/color/add'),
|
|
||||||
child:ColorAddPage(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<bool> popRoute() async {
|
|
||||||
print('=======popRoute=========');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _onPopPage(Route route, result) {
|
|
||||||
if(_completerMap.containsKey(path)){
|
|
||||||
_completerMap[path]?.complete(result);
|
|
||||||
_completerMap.remove(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
path = backPath(path);
|
|
||||||
return route.didPop(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
String backPath(String path){
|
|
||||||
Uri uri = Uri.parse(path);
|
|
||||||
if(uri.pathSegments.length==1) return path;
|
|
||||||
List<String> parts = List.of(uri.pathSegments)..removeLast();
|
|
||||||
return '/${parts.join('/')}';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> setNewRoutePath(configuration) async {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// class AppRouterDelegate extends RouterDelegate<String> with ChangeNotifier, PopNavigatorRouterDelegateMixin {
|
|
||||||
//
|
|
||||||
// List<String> _value = ['/'];
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// List<String> get value => _value;
|
|
||||||
//
|
|
||||||
// set value(List<String> value){
|
|
||||||
// _value = value;
|
|
||||||
// notifyListeners();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// Widget build(BuildContext context) {
|
|
||||||
// return Navigator(
|
|
||||||
// onPopPage: _onPopPage,
|
|
||||||
// pages: _value.map((e) => _pageMap[e]!).toList(),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final Map<String, Page> _pageMap = const {
|
|
||||||
// '/': MaterialPage(child: HomePage()),
|
|
||||||
// 'a': MaterialPage(child: PageA()),
|
|
||||||
// 'b': MaterialPage(child: PageB()),
|
|
||||||
// 'c': MaterialPage(child: PageC()),
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// bool _onPopPage(Route route, result) {
|
|
||||||
// _value = List.of(_value)..removeLast();
|
|
||||||
// notifyListeners();
|
|
||||||
// return route.didPop(result);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// GlobalKey<NavigatorState>? navigatorKey = GlobalKey<NavigatorState>();
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// Future<void> setNewRoutePath(String configuration) async{
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
|
|
||||||
import '../../../pages/color/color_add_page.dart';
|
|
||||||
import '../../../pages/color/color_detail_page.dart';
|
|
||||||
import '../../../pages/color/color_page.dart';
|
|
||||||
import '../transition/fade_transition_page.dart';
|
|
||||||
|
|
||||||
class IRoute {
|
|
||||||
final String path;
|
|
||||||
final IRoutePageBuilder builder;
|
|
||||||
final List<IRoute> children;
|
|
||||||
|
|
||||||
const IRoute({
|
|
||||||
required this.path,
|
|
||||||
this.children = const [],
|
|
||||||
required this.builder,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'IRoute{path: $path, children: $children}';
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> list() {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef IRoutePageBuilder = Page? Function(
|
|
||||||
BuildContext context, IRouteData data);
|
|
||||||
|
|
||||||
class IRouteData {
|
|
||||||
final Object? extra;
|
|
||||||
final bool forResult;
|
|
||||||
final Uri uri;
|
|
||||||
final bool keepAlive;
|
|
||||||
|
|
||||||
IRouteData({
|
|
||||||
required this.extra,
|
|
||||||
required this.uri,
|
|
||||||
required this.forResult,
|
|
||||||
required this.keepAlive,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IRoute> kDestinationsIRoutes = [
|
|
||||||
IRoute(
|
|
||||||
path: '/color',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/color'),
|
|
||||||
child: ColorPage(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
IRoute(
|
|
||||||
path: '/color/detail',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
final Map<String, String> queryParams = data.uri.queryParameters;
|
|
||||||
String? selectedColor = queryParams['color'];
|
|
||||||
if (selectedColor != null) {
|
|
||||||
Color color = Color(int.parse(selectedColor, radix: 16));
|
|
||||||
return FadeTransitionPage(
|
|
||||||
key: const ValueKey('/color/detail'),
|
|
||||||
child: ColorDetailPage(color: color),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
IRoute(
|
|
||||||
path: '/color/add',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/color/add'),
|
|
||||||
child: ColorAddPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
IRoute(
|
|
||||||
path: '/counter',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/counter'),
|
|
||||||
child: ColorAddPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
IRoute(
|
|
||||||
path: '/user',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/user'),
|
|
||||||
child: ColorAddPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
IRoute(
|
|
||||||
path: '/settings',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/settings'),
|
|
||||||
child: ColorAddPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
// Copyright 2021, the Flutter project authors. Please see the AUTHORS file
|
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
|
||||||
// BSD-style license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class FadeTransitionPage<T> extends Page<T> {
|
|
||||||
final Widget child;
|
|
||||||
final Duration duration;
|
|
||||||
|
|
||||||
const FadeTransitionPage({
|
|
||||||
super.key,
|
|
||||||
required this.child,
|
|
||||||
this.duration = const Duration(milliseconds: 300),
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Route<T> createRoute(BuildContext context) =>
|
|
||||||
PageBasedFadeTransitionRoute<T>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
class PageBasedFadeTransitionRoute<T> extends PageRoute<T> {
|
|
||||||
final FadeTransitionPage<T> _page;
|
|
||||||
|
|
||||||
PageBasedFadeTransitionRoute(this._page) : super(settings: _page);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Color? get barrierColor => null;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? get barrierLabel => null;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Duration get transitionDuration => _page.duration;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool get maintainState => true;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget buildPage(BuildContext context, Animation<double> animation,
|
|
||||||
Animation<double> secondaryAnimation) {
|
|
||||||
var curveTween = CurveTween(curve: Curves.easeIn);
|
|
||||||
return FadeTransition(
|
|
||||||
opacity: animation.drive(curveTween),
|
|
||||||
child: (settings as FadeTransitionPage).child,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget buildTransitions(BuildContext context, Animation<double> animation,
|
|
||||||
Animation<double> secondaryAnimation, Widget child) =>
|
|
||||||
child;
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
// Copyright 2021, the Flutter project authors. Please see the AUTHORS file
|
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
|
||||||
// BSD-style license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class NoTransitionPage<T> extends Page<T> {
|
|
||||||
final Widget child;
|
|
||||||
|
|
||||||
const NoTransitionPage({
|
|
||||||
super.key,
|
|
||||||
required this.child,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Route<T> createRoute(BuildContext context) => NoTransitionRoute<T>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
class NoTransitionRoute<T> extends PageRoute<T> {
|
|
||||||
|
|
||||||
final NoTransitionPage<T> _page;
|
|
||||||
|
|
||||||
NoTransitionRoute(this._page) : super(settings: _page);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Color? get barrierColor => null;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? get barrierLabel => null;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Duration get transitionDuration => const Duration(milliseconds: 0);
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool get maintainState => true;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget buildPage(BuildContext context, Animation<double> animation,
|
|
||||||
Animation<double> secondaryAnimation) {
|
|
||||||
return (settings as NoTransitionPage).child;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget buildTransitions(BuildContext context, Animation<double> animation,
|
|
||||||
Animation<double> secondaryAnimation, Widget child) =>
|
|
||||||
child;
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import '../../../pages/sort/sort_setting.dart';
|
|
||||||
import '../router/app_router_delegate.dart';
|
|
||||||
import 'app_navigation_rail.dart';
|
|
||||||
import 'app_top_bar.dart';
|
|
||||||
|
|
||||||
class AppNavigation extends StatelessWidget {
|
|
||||||
const AppNavigation({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
double px1 = 1/View.of(context).devicePixelRatio;
|
|
||||||
return Scaffold(
|
|
||||||
endDrawer: Drawer(
|
|
||||||
child: SortSettings(),
|
|
||||||
),
|
|
||||||
body: Row(
|
|
||||||
children: [
|
|
||||||
const AppNavigationRail(),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
const AppTopBar(),
|
|
||||||
Divider(height: px1,),
|
|
||||||
Expanded(
|
|
||||||
child: Router(
|
|
||||||
routerDelegate: router,
|
|
||||||
backButtonDispatcher: RootBackButtonDispatcher(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:iroute/components/components.dart';
|
|
||||||
import '../router/app_router_delegate.dart';
|
|
||||||
|
|
||||||
class AppNavigationRail extends StatefulWidget {
|
|
||||||
const AppNavigationRail({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<AppNavigationRail> createState() => _AppNavigationRailState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AppNavigationRailState extends State<AppNavigationRail> {
|
|
||||||
|
|
||||||
final List<MenuMeta> deskNavBarMenus = const [
|
|
||||||
MenuMeta(label: '颜色板', icon: Icons.color_lens_outlined),
|
|
||||||
MenuMeta(label: '计数器', icon: Icons.add_chart),
|
|
||||||
MenuMeta(label: '排序', icon: Icons.sort),
|
|
||||||
MenuMeta(label: '我的', icon: Icons.person),
|
|
||||||
MenuMeta(label: '设置', icon: Icons.settings),
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
router.addListener(_onRouterChange);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
router.removeListener(_onRouterChange);
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return DragToMoveWrap(
|
|
||||||
child: TolyNavigationRail(
|
|
||||||
items: deskNavBarMenus,
|
|
||||||
leading: const Padding(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 18.0),
|
|
||||||
child: FlutterLogo(),
|
|
||||||
),
|
|
||||||
tail: Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 6.0),
|
|
||||||
child: Text('V0.0.4',style: TextStyle(color: Colors.white,fontSize: 12),),
|
|
||||||
),
|
|
||||||
backgroundColor: const Color(0xff3975c6),
|
|
||||||
onDestinationSelected: _onDestinationSelected,
|
|
||||||
selectedIndex: router.activeIndex,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onDestinationSelected(int index) {
|
|
||||||
if(index==1){
|
|
||||||
router.changePath(kDestinationsPaths[index],keepAlive: true);
|
|
||||||
}else{
|
|
||||||
router.path = kDestinationsPaths[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onRouterChange() {
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:iroute/components/toly_ui/button/hover_icon_button.dart';
|
|
||||||
import 'package:iroute/components/toly_ui/popable/drop_selectable_widget.dart';
|
|
||||||
import '../../../pages/sort/functions.dart';
|
|
||||||
import '../../../pages/sort/views/sort_bar.dart';
|
|
||||||
import '../../../pages/sort/views/sort_button.dart';
|
|
||||||
import '../router/app_router_delegate.dart';
|
|
||||||
|
|
||||||
class AppRouterEditor extends StatefulWidget {
|
|
||||||
final ValueChanged<String>? onSubmit;
|
|
||||||
const AppRouterEditor({super.key, this.onSubmit});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<AppRouterEditor> createState() => _AppRouterEditorState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AppRouterEditorState extends State<AppRouterEditor> {
|
|
||||||
|
|
||||||
final TextEditingController _controller = TextEditingController();
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_onRouteChange();
|
|
||||||
router.addListener(_onRouteChange);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onRouteChange() {
|
|
||||||
_controller.text=router.path;
|
|
||||||
setState(() {
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
router.removeListener(_onRouteChange);
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
print(router.path);
|
|
||||||
if(router.path=='/sort'){
|
|
||||||
return SortBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
return SizedBox(
|
|
||||||
width: 250,
|
|
||||||
child: Stack(
|
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
child: CupertinoTextField(
|
|
||||||
controller: _controller,
|
|
||||||
style: TextStyle(fontSize: 14),
|
|
||||||
padding: EdgeInsets.only(left:12,top: 6,bottom: 6,right: 32),
|
|
||||||
placeholder: '输入路由地址导航',
|
|
||||||
onSubmitted: widget.onSubmit,
|
|
||||||
decoration: BoxDecoration(color: Color(0xffF1F2F3),borderRadius: BorderRadius.circular(6)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 8.0),
|
|
||||||
child: HoverIconButton(
|
|
||||||
icon: Icons.directions_outlined,
|
|
||||||
defaultColor: Color(0xff68696B),
|
|
||||||
onPressed:()=>widget.onSubmit?.call(_controller.text),
|
|
||||||
size: 20
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:iroute/components/components.dart';
|
|
||||||
import '../../../pages/sort/functions.dart';
|
|
||||||
import '../router/app_router_delegate.dart';
|
|
||||||
import 'app_router_editor.dart';
|
|
||||||
|
|
||||||
class AppTopBar extends StatelessWidget {
|
|
||||||
const AppTopBar({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return DragToMoveWrap(
|
|
||||||
child: Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
height: 46,
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
const RouterIndicator(),
|
|
||||||
Expanded(
|
|
||||||
child: Row(children: [
|
|
||||||
const Spacer(),
|
|
||||||
SizedBox(
|
|
||||||
// width: 200,
|
|
||||||
child: AppRouterEditor(
|
|
||||||
onSubmit: (path) => router.path = path,
|
|
||||||
)),
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 12.0),
|
|
||||||
child: VerticalDivider(
|
|
||||||
width: 32,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
])),
|
|
||||||
const WindowButtons()
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RouterIndicator extends StatefulWidget {
|
|
||||||
const RouterIndicator({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<RouterIndicator> createState() => _RouterIndicatorState();
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, String> kRouteLabelMap = {
|
|
||||||
'/color': '颜色板',
|
|
||||||
'/color/add': '添加颜色',
|
|
||||||
'/color/detail': '颜色详情',
|
|
||||||
'/counter': '计数器',
|
|
||||||
'/user': '我的',
|
|
||||||
'/sort': '可视化排序',
|
|
||||||
'/settings': '系统设置',
|
|
||||||
};
|
|
||||||
|
|
||||||
class _RouterIndicatorState extends State<RouterIndicator> {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
router.addListener(_onRouterChange);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
router.removeListener(_onRouterChange);
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return TolyBreadcrumb(
|
|
||||||
items: pathToBreadcrumbItems(router.path),
|
|
||||||
onTapItem: (item) {
|
|
||||||
if (item.to != null) {
|
|
||||||
router.path = item.to!;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onRouterChange() {
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
|
|
||||||
List<BreadcrumbItem> pathToBreadcrumbItems(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 = kRouteLabelMap[to] ?? '未知路由';
|
|
||||||
result.add(BreadcrumbItem(to: to, label: label, active: to == distPath));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
|
|
||||||
|
|
||||||
class ColorAddPage extends StatefulWidget {
|
|
||||||
const ColorAddPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ColorAddPage> createState() => _ColorAddPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ColorAddPageState extends State<ColorAddPage> {
|
|
||||||
late Color _color;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_color = randomColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
String text = '# ${_color.value.toRadixString(16)}';
|
|
||||||
return Scaffold(
|
|
||||||
bottomNavigationBar: Container(
|
|
||||||
margin: EdgeInsets.only(right:20,bottom: 20),
|
|
||||||
// color: Colors.redAccent,
|
|
||||||
child: Row(
|
|
||||||
textDirection:TextDirection.rtl,
|
|
||||||
children: [
|
|
||||||
ElevatedButton(onPressed: (){
|
|
||||||
Navigator.of(context).pop(_color);
|
|
||||||
|
|
||||||
}, child: Text('添加')),
|
|
||||||
SizedBox(width: 12,),
|
|
||||||
OutlinedButton(onPressed: (){
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
}, child: Text('取消')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: Column(
|
|
||||||
// mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16.0,vertical: 16),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Expanded(child: Text(text,style: TextStyle(color: _color,fontSize: 24,letterSpacing: 4),)),
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.only(left: 10),
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
child: Icon(
|
|
||||||
Icons.sell_outlined,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: _color,
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ColorPicker(
|
|
||||||
colorPickerWidth:200,
|
|
||||||
// enableAlpha: false,
|
|
||||||
displayThumbColor:true,
|
|
||||||
pickerColor: _color,
|
|
||||||
paletteType: PaletteType.hueWheel,
|
|
||||||
onColorChanged: changeColor,
|
|
||||||
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Random _random = Random();
|
|
||||||
|
|
||||||
Color get randomColor {
|
|
||||||
return Color.fromARGB(
|
|
||||||
255,
|
|
||||||
_random.nextInt(256),
|
|
||||||
_random.nextInt(256),
|
|
||||||
_random.nextInt(256),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _selectColor() {
|
|
||||||
Navigator.of(context).pop(_color);
|
|
||||||
}
|
|
||||||
|
|
||||||
void changeColor(Color value) {
|
|
||||||
_color = value;
|
|
||||||
setState(() {
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
class ColorDetailPage extends StatelessWidget {
|
|
||||||
final Color color;
|
|
||||||
const ColorDetailPage({super.key, required this.color});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
|
|
||||||
const TextStyle style = TextStyle(
|
|
||||||
fontSize: 32,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.white
|
|
||||||
);
|
|
||||||
String text = '# ${color.value.toRadixString(16)}';
|
|
||||||
return Scaffold(
|
|
||||||
// appBar: AppBar(
|
|
||||||
// systemOverlayStyle: SystemUiOverlayStyle(
|
|
||||||
// statusBarColor: Colors.transparent,
|
|
||||||
// statusBarIconBrightness: Brightness.light
|
|
||||||
// ),
|
|
||||||
// iconTheme: IconThemeData(color: Colors.white),
|
|
||||||
// titleTextStyle:TextStyle(color: Colors.white,fontSize: 18) ,
|
|
||||||
// backgroundColor: color,
|
|
||||||
// title: Text('颜色界面',),),
|
|
||||||
body: Container(
|
|
||||||
alignment: Alignment.center,
|
|
||||||
color: color,
|
|
||||||
child: Text(text ,style: style,),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:iroute/components/project/colors_panel.dart';
|
|
||||||
import '../../app/navigation/router/app_router_delegate.dart';
|
|
||||||
|
|
||||||
class ColorPage extends StatefulWidget {
|
|
||||||
const ColorPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ColorPage> createState() => _ColorPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ColorPageState extends State<ColorPage> {
|
|
||||||
final List<Color> _colors = [
|
|
||||||
Colors.red, Colors.black, Colors.blue, Colors.green, Colors.orange,
|
|
||||||
Colors.pink, Colors.purple, Colors.indigo, Colors.amber, Colors.cyan,
|
|
||||||
Colors.redAccent, Colors.grey, Colors.blueAccent, Colors.greenAccent, Colors.orangeAccent,
|
|
||||||
Colors.pinkAccent, Colors.purpleAccent, Colors.indigoAccent, Colors.amberAccent, Colors.cyanAccent,
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
// appBar: AppBar(title:const Text('颜色主页')),
|
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
onPressed: _toAddPage,
|
|
||||||
child: const Icon(Icons.add),
|
|
||||||
),
|
|
||||||
body: Align(
|
|
||||||
alignment: Alignment.topCenter,
|
|
||||||
child: ColorsPanel(
|
|
||||||
colors: _colors,
|
|
||||||
onSelect: _selectColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _selectColor(Color color){
|
|
||||||
String value = color.value.toRadixString(16);
|
|
||||||
router.path = '/color/detail?color=$value';
|
|
||||||
// router.setPathForData('/color/detail',color);
|
|
||||||
// router.setPathKeepLive('/color/detail?color=$value');
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void _toAddPage() async {
|
|
||||||
Color? color = await router.changePath('/color/add',forResult: true);
|
|
||||||
if (color != null) {
|
|
||||||
setState(() {
|
|
||||||
_colors.add(color);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class CounterPage extends StatefulWidget {
|
|
||||||
const CounterPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<CounterPage> createState() => _CounterPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CounterPageState extends State<CounterPage> {
|
|
||||||
int _counter = 0;
|
|
||||||
|
|
||||||
void _incrementCounter() {
|
|
||||||
setState(() {
|
|
||||||
_counter++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
const Text(
|
|
||||||
'You have pushed the button this many times:',
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'$_counter',
|
|
||||||
style: Theme.of(context).textTheme.headlineMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
onPressed: _incrementCounter,
|
|
||||||
tooltip: 'Increment',
|
|
||||||
child: const Icon(Icons.add),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class EmptyPage extends StatelessWidget {
|
|
||||||
const EmptyPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
// appBar: AppBar(
|
|
||||||
// title: Text('界面走丢了'),
|
|
||||||
// ),
|
|
||||||
body: Scaffold(
|
|
||||||
body: Center(
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 16,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
direction: Axis.vertical,
|
|
||||||
children: [
|
|
||||||
Icon(Icons.nearby_error,size: 64, color: Colors.grey),
|
|
||||||
Text(
|
|
||||||
'404 界面丢失',
|
|
||||||
style: TextStyle(fontSize: 24, color: Colors.grey),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class SettingPage extends StatelessWidget {
|
|
||||||
const SettingPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body:Center(child: Text('SettingPage')));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,22 +0,0 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import '../provider/state.dart';
|
|
||||||
import 'data_painter.dart';
|
|
||||||
|
|
||||||
class SortPage extends StatelessWidget{
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
SortState state = SortStateScope.of(context);
|
|
||||||
List<int> numbers = state.data;
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
body: CustomPaint(
|
|
||||||
painter: DataPainter(data: numbers),
|
|
||||||
child: ConstrainedBox(constraints: BoxConstraints.expand()),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class UserPage extends StatelessWidget {
|
|
||||||
const UserPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body:Center(child: Text('UserPage')));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export 'app/unit_app.dart';
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import '../../../pages/color/color_add_page.dart';
|
|
||||||
import '../../../pages/color/color_detail_page.dart';
|
|
||||||
import '../../../pages/color/color_page.dart';
|
|
||||||
import '../../../pages/counter/counter_page.dart';
|
|
||||||
import '../../../pages/user/user_page.dart';
|
|
||||||
import '../../../pages/settings/settings_page.dart';
|
|
||||||
import '../transition/fade_transition_page.dart';
|
|
||||||
|
|
||||||
class IRoute {
|
|
||||||
final String path;
|
|
||||||
final IRoutePageBuilder? builder;
|
|
||||||
final List<IRoute> children;
|
|
||||||
|
|
||||||
const IRoute({
|
|
||||||
required this.path,
|
|
||||||
this.children = const [],
|
|
||||||
this.builder,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'IRoute{path: $path, children: $children}';
|
|
||||||
}
|
|
||||||
|
|
||||||
IRoute? match(String path) {
|
|
||||||
return matchRoute(this, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IRoute> find(String input){
|
|
||||||
String fixInput = input.substring(1);
|
|
||||||
List<IRoute> nodes = findNodes(this,fixInput,0,'/',[]);
|
|
||||||
if(nodes.isNotEmpty&&nodes.last.path!=input){
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
return nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IRoute> findNodes(IRoute node,String input,int deep,String prefix,List<IRoute> result){
|
|
||||||
String separator = '/';
|
|
||||||
|
|
||||||
List<String> parts = input.split(separator);
|
|
||||||
if(deep>parts.length-1){
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
String target = parts[deep];
|
|
||||||
if(node.children.isNotEmpty){
|
|
||||||
List<IRoute> nodes = node.children.where((e) => e.path==prefix+target).toList();
|
|
||||||
bool match = nodes.isNotEmpty;
|
|
||||||
if(match){
|
|
||||||
IRoute matched = nodes.first;
|
|
||||||
result.add(matched);
|
|
||||||
String nextPrefix = '${matched.path}$separator';
|
|
||||||
findNodes(matched, input, ++deep,nextPrefix,result);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// List<IRoute> findNodes(IRoute node,String input,int deep,String prefix,List<IRoute> result){
|
|
||||||
// String separator = '/';
|
|
||||||
// List<String> parts = input.split(separator);
|
|
||||||
// if(deep>parts.length-1){
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
// String target = parts[deep];
|
|
||||||
// if(node.children.isNotEmpty){
|
|
||||||
// List<IRoute> nodes = node.children.where((e) => e.path==prefix+target).toList();
|
|
||||||
// bool match = nodes.isNotEmpty;
|
|
||||||
// if(match){
|
|
||||||
// IRoute matched = nodes.first;
|
|
||||||
// result.add(matched);
|
|
||||||
// String nextPrefix = '${matched.path}$separator';
|
|
||||||
// findNodes(matched, input, ++deep,nextPrefix,result);
|
|
||||||
// }
|
|
||||||
// }else{
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
|
|
||||||
IRoute? matchRoute(IRoute route, String path) {
|
|
||||||
if (route.path == path) {
|
|
||||||
return route;
|
|
||||||
} else {
|
|
||||||
if (route.children.isNotEmpty) {
|
|
||||||
for (int i = 0; i < route.children.length; i++) {
|
|
||||||
IRoute current = route.children[i];
|
|
||||||
IRoute? target = matchRoute(current, path);
|
|
||||||
if (target != null) {
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef IRoutePageBuilder = Page? Function(
|
|
||||||
BuildContext context, IRouteData data);
|
|
||||||
|
|
||||||
class IRouteData {
|
|
||||||
final Object? extra;
|
|
||||||
final bool forResult;
|
|
||||||
final Uri uri;
|
|
||||||
final bool keepAlive;
|
|
||||||
|
|
||||||
IRouteData({
|
|
||||||
this.extra,
|
|
||||||
required this.uri,
|
|
||||||
this.forResult = false,
|
|
||||||
this.keepAlive = false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
IRoute root = IRoute(path: 'root', children: kDestinationsIRoutes);
|
|
||||||
|
|
||||||
List<IRoute> kDestinationsIRoutes = [
|
|
||||||
IRoute(
|
|
||||||
path: '/color',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/color'),
|
|
||||||
child: ColorPage(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
IRoute(
|
|
||||||
path: '/color/detail',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
final Map<String, String> queryParams = data.uri.queryParameters;
|
|
||||||
String? selectedColor = queryParams['color'];
|
|
||||||
Color color = Colors.black;
|
|
||||||
if (selectedColor != null) {
|
|
||||||
color = Color(int.parse(selectedColor, radix: 16));
|
|
||||||
} else if (data.extra is Color) {
|
|
||||||
color = data.extra as Color;
|
|
||||||
}
|
|
||||||
return FadeTransitionPage(
|
|
||||||
key: const ValueKey('/color/detail'),
|
|
||||||
child: ColorDetailPage(color: color),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
IRoute(
|
|
||||||
path: '/color/add',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/color/add'),
|
|
||||||
child: ColorAddPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
IRoute(
|
|
||||||
path: '/counter',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/counter'),
|
|
||||||
child: CounterPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
IRoute(
|
|
||||||
path: '/user',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/user'),
|
|
||||||
child: UserPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
IRoute(
|
|
||||||
path: '/settings',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/settings'),
|
|
||||||
child: SettingPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
class RouteHistory{
|
|
||||||
final String path;
|
|
||||||
final Object? extra;
|
|
||||||
|
|
||||||
RouteHistory(this.path, { this.extra});
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
// Copyright 2021, the Flutter project authors. Please see the AUTHORS file
|
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
|
||||||
// BSD-style license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class NoTransitionPage<T> extends Page<T> {
|
|
||||||
final Widget child;
|
|
||||||
|
|
||||||
const NoTransitionPage({
|
|
||||||
super.key,
|
|
||||||
required this.child,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Route<T> createRoute(BuildContext context) => NoTransitionRoute<T>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
class NoTransitionRoute<T> extends PageRoute<T> {
|
|
||||||
|
|
||||||
final NoTransitionPage<T> _page;
|
|
||||||
|
|
||||||
NoTransitionRoute(this._page) : super(settings: _page);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Color? get barrierColor => null;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? get barrierLabel => null;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Duration get transitionDuration => const Duration(milliseconds: 0);
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool get maintainState => true;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget buildPage(BuildContext context, Animation<double> animation,
|
|
||||||
Animation<double> secondaryAnimation) {
|
|
||||||
return (settings as NoTransitionPage).child;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget buildTransitions(BuildContext context, Animation<double> animation,
|
|
||||||
Animation<double> secondaryAnimation, Widget child) =>
|
|
||||||
child;
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:iroute/components/components.dart';
|
|
||||||
import '../router/app_router_delegate.dart';
|
|
||||||
|
|
||||||
class AppNavigationRail extends StatefulWidget {
|
|
||||||
const AppNavigationRail({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<AppNavigationRail> createState() => _AppNavigationRailState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _AppNavigationRailState extends State<AppNavigationRail> {
|
|
||||||
|
|
||||||
final List<MenuMeta> deskNavBarMenus = const [
|
|
||||||
MenuMeta(label: '颜色板', icon: Icons.color_lens_outlined),
|
|
||||||
MenuMeta(label: '计数器', icon: Icons.add_chart),
|
|
||||||
MenuMeta(label: '我的', icon: Icons.person),
|
|
||||||
MenuMeta(label: '设置', icon: Icons.settings),
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
router.addListener(_onRouterChange);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
router.removeListener(_onRouterChange);
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return DragToMoveWrap(
|
|
||||||
child: TolyNavigationRail(
|
|
||||||
items: deskNavBarMenus,
|
|
||||||
leading: const Padding(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 18.0),
|
|
||||||
child: FlutterLogo(),
|
|
||||||
),
|
|
||||||
tail: Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 6.0),
|
|
||||||
child: Text('V0.0.5',style: TextStyle(color: Colors.white,fontSize: 12),),
|
|
||||||
),
|
|
||||||
backgroundColor: const Color(0xff3975c6),
|
|
||||||
onDestinationSelected: _onDestinationSelected,
|
|
||||||
selectedIndex: router.activeIndex,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onDestinationSelected(int index) {
|
|
||||||
if(index==1){
|
|
||||||
router.changePath(kDestinationsPaths[index],keepAlive: true);
|
|
||||||
}else{
|
|
||||||
router.path = kDestinationsPaths[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onRouterChange() {
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'navigation/router/app_router_delegate.dart';
|
|
||||||
import 'navigation/views/app_navigation.dart';
|
|
||||||
import 'navigation/views/app_navigation_rail.dart';
|
|
||||||
|
|
||||||
class UnitApp extends StatelessWidget {
|
|
||||||
const UnitApp({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
|
|
||||||
return MaterialApp(
|
|
||||||
theme: ThemeData(
|
|
||||||
fontFamily: "宋体",
|
|
||||||
scaffoldBackgroundColor: Colors.white,
|
|
||||||
appBarTheme: const AppBarTheme(
|
|
||||||
elevation: 0,
|
|
||||||
iconTheme: IconThemeData(color: Colors.black),
|
|
||||||
titleTextStyle: TextStyle(
|
|
||||||
color: Colors.black,
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
))),
|
|
||||||
debugShowCheckedModeBanner: false,
|
|
||||||
home: AppNavigation()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class CounterPage extends StatefulWidget {
|
|
||||||
const CounterPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<CounterPage> createState() => _CounterPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _CounterPageState extends State<CounterPage> {
|
|
||||||
int _counter = 0;
|
|
||||||
|
|
||||||
void _incrementCounter() {
|
|
||||||
setState(() {
|
|
||||||
_counter++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
const Text(
|
|
||||||
'You have pushed the button this many times:',
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'$_counter',
|
|
||||||
style: Theme.of(context).textTheme.headlineMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
onPressed: _incrementCounter,
|
|
||||||
tooltip: 'Increment',
|
|
||||||
child: const Icon(Icons.add),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class EmptyPage extends StatelessWidget {
|
|
||||||
const EmptyPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
// appBar: AppBar(
|
|
||||||
// title: Text('界面走丢了'),
|
|
||||||
// ),
|
|
||||||
body: Scaffold(
|
|
||||||
body: Center(
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 16,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
direction: Axis.vertical,
|
|
||||||
children: [
|
|
||||||
Icon(Icons.nearby_error,size: 64, color: Colors.grey),
|
|
||||||
Text(
|
|
||||||
'404 界面丢失',
|
|
||||||
style: TextStyle(fontSize: 24, color: Colors.grey),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class SettingPage extends StatelessWidget {
|
|
||||||
const SettingPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body:Center(child: Text('SettingPage')));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class UserPage extends StatelessWidget {
|
|
||||||
const UserPage({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
body:Center(child: Text('UserPage')));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'iroute.dart';
|
import 'iroute.dart';
|
||||||
import 'route_history.dart';
|
import 'iroute_config.dart';
|
||||||
|
import 'route_history_manager.dart';
|
||||||
const List<String> kDestinationsPaths = [
|
import 'routes.dart';
|
||||||
'/color',
|
import 'views/not_find_view.dart';
|
||||||
'/counter',
|
|
||||||
'/user',
|
|
||||||
'/settings',
|
|
||||||
];
|
|
||||||
|
|
||||||
AppRouterDelegate router = AppRouterDelegate();
|
AppRouterDelegate router = AppRouterDelegate();
|
||||||
|
|
||||||
@@ -18,120 +13,82 @@ class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
|||||||
|
|
||||||
String get path => _path;
|
String get path => _path;
|
||||||
|
|
||||||
AppRouterDelegate() {
|
final IRoutePageBuilder? notFindPageBuilder;
|
||||||
// keepAlivePath.add('/color');
|
|
||||||
_histories.add(RouteHistory(path));
|
AppRouterDelegate({this.notFindPageBuilder}) {
|
||||||
|
_historyManager.recode(IRouteConfig(uri: Uri.parse(path)));
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<RouteHistory> _histories = [];
|
Page _defaultNotFindPageBuilder(_, __) => const MaterialPage(
|
||||||
final List<RouteHistory> _backHistories = [];
|
child: Material(child: NotFindPage()),
|
||||||
|
);
|
||||||
|
|
||||||
List<RouteHistory> get histories => _histories.reversed.toList();
|
final RouteHistoryManager _historyManager = RouteHistoryManager();
|
||||||
|
|
||||||
bool get hasHistory => _histories.length > 1;
|
RouteHistoryManager get historyManager => _historyManager;
|
||||||
|
|
||||||
bool get hasBackHistory => _backHistories.isNotEmpty;
|
|
||||||
|
|
||||||
/// 历史回退操作
|
/// 历史回退操作
|
||||||
/// 将当前顶层移除,并加入 _backHistories 撤销列表
|
/// 详见: [RouteHistoryManager.back]
|
||||||
/// 并转到前一路径
|
void back() => _historyManager.back(changeRoute);
|
||||||
void back() {
|
|
||||||
if (!hasHistory) return;
|
|
||||||
RouteHistory top = _histories.removeLast();
|
|
||||||
_backHistories.add(top);
|
|
||||||
if (_histories.isNotEmpty) {
|
|
||||||
_path = _histories.last.path;
|
|
||||||
if (_histories.last.extra != null) {
|
|
||||||
_pathExtraMap[_path] = _histories.last.extra;
|
|
||||||
}
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void toHistory(RouteHistory history) {
|
/// 撤销回退操作
|
||||||
_path = history.path;
|
/// 详见: [RouteHistoryManager.revocation]
|
||||||
if (history.extra != null) {
|
void revocation() => _historyManager.revocation(changeRoute);
|
||||||
_pathExtraMap[_path] = history.extra;
|
|
||||||
}
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void closeHistory(int index) {
|
void closeHistory(int index) {
|
||||||
_histories.removeAt(index);
|
_historyManager.close(index);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearHistory() {
|
void clearHistory() {
|
||||||
_histories.clear();
|
_historyManager.clear();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 撤销回退操作
|
|
||||||
/// 取出回退列表的最后元素,跳转到该路径
|
|
||||||
void revocation() {
|
|
||||||
RouteHistory target = _backHistories.removeLast();
|
|
||||||
_path = target.path;
|
|
||||||
if (target.extra != null) {
|
|
||||||
_pathExtraMap[_path] = target.extra;
|
|
||||||
}
|
|
||||||
_histories.add(target);
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
int? get activeIndex {
|
|
||||||
if (path.startsWith('/color')) return 0;
|
|
||||||
if (path.startsWith('/counter')) return 1;
|
|
||||||
if (path.startsWith('/user')) return 2;
|
|
||||||
if (path.startsWith('/settings')) return 3;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<String, Completer<dynamic>> _completerMap = {};
|
final Map<String, Completer<dynamic>> _completerMap = {};
|
||||||
|
|
||||||
Completer<dynamic>? completer;
|
|
||||||
|
|
||||||
final Map<String, dynamic> _pathExtraMap = {};
|
final Map<String, dynamic> _pathExtraMap = {};
|
||||||
|
|
||||||
final List<String> keepAlivePath = [];
|
final List<String> keepAlivePath = [];
|
||||||
|
|
||||||
FutureOr<dynamic> changePath(
|
FutureOr<dynamic> changeRoute(IRouteConfig config) {
|
||||||
String value, {
|
String value = config.uri.path;
|
||||||
bool forResult = false,
|
|
||||||
Object? extra,
|
|
||||||
bool keepAlive = false,
|
|
||||||
bool recordHistory = true,
|
|
||||||
}) {
|
|
||||||
if (_path == value) null;
|
if (_path == value) null;
|
||||||
if (forResult) {
|
if (config.forResult) {
|
||||||
_completerMap[value] = Completer();
|
_completerMap[value] = Completer();
|
||||||
}
|
}
|
||||||
if (keepAlive) {
|
if (config.keepAlive) {
|
||||||
if (keepAlivePath.contains(value)) {
|
if (keepAlivePath.contains(value)) {
|
||||||
keepAlivePath.remove(value);
|
keepAlivePath.remove(value);
|
||||||
}
|
}
|
||||||
keepAlivePath.add(value);
|
keepAlivePath.add(value);
|
||||||
}
|
}
|
||||||
if (extra != null) {
|
if (config.extra != null) {
|
||||||
_pathExtraMap[value] = extra;
|
_pathExtraMap[value] = config.extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recordHistory) {
|
if (config.recordHistory) {
|
||||||
_addPathToHistory(value,extra);
|
_historyManager.recode(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
_path = value;
|
_path = value;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
if (forResult) {
|
if (config.forResult) {
|
||||||
return _completerMap[value]!.future;
|
return _completerMap[value]!.future;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FutureOr<dynamic> changePath(
|
||||||
void _addPathToHistory(String value, Object? extra) {
|
String value, {
|
||||||
if (_histories.isNotEmpty && value == _histories.last.path) return;
|
bool forResult = false,
|
||||||
_histories.add(RouteHistory(
|
Object? extra,
|
||||||
value,
|
bool keepAlive = false,
|
||||||
extra: _pathExtraMap[path],
|
bool recordHistory = true,
|
||||||
|
}) {
|
||||||
|
return changeRoute(IRouteConfig(
|
||||||
|
uri: Uri.parse(value),
|
||||||
|
forResult: forResult,
|
||||||
|
extra: extra,
|
||||||
|
keepAlive: keepAlive,
|
||||||
|
recordHistory: recordHistory,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +113,7 @@ class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
|||||||
|
|
||||||
/// 去除和 topPages 中重复的界面
|
/// 去除和 topPages 中重复的界面
|
||||||
pages.removeWhere(
|
pages.removeWhere(
|
||||||
(element) => topPages.map((e) => e.key).contains(element.key));
|
(element) => topPages.map((e) => e.key).contains(element.key));
|
||||||
}
|
}
|
||||||
|
|
||||||
pages.addAll(topPages);
|
pages.addAll(topPages);
|
||||||
@@ -165,23 +122,26 @@ class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
|||||||
|
|
||||||
List<Page> _buildPageByPathFromTree(BuildContext context, String path) {
|
List<Page> _buildPageByPathFromTree(BuildContext context, String path) {
|
||||||
List<Page> result = [];
|
List<Page> result = [];
|
||||||
List<IRoute> iRoutes = root.find(path);
|
List<IRouteNode> iRoutes = rootRoute.find(path);
|
||||||
if (iRoutes.isNotEmpty) {
|
if (iRoutes.isNotEmpty) {
|
||||||
for (int i = 0; i < iRoutes.length; i++) {
|
for (int i = 0; i < iRoutes.length; i++) {
|
||||||
IRoute iroute = iRoutes[i];
|
IRouteNode iroute = iRoutes[i];
|
||||||
String path = iroute.path;
|
String path = iroute.path;
|
||||||
Object? extra = _pathExtraMap[path];
|
Object? extra = _pathExtraMap[path];
|
||||||
bool keepAlive = keepAlivePath.contains(path);
|
bool keepAlive = keepAlivePath.contains(path);
|
||||||
bool forResult = _completerMap.containsKey(path);
|
bool forResult = _completerMap.containsKey(path);
|
||||||
Page? page = iroute.builder?.call(
|
IRouteConfig config = IRouteConfig(
|
||||||
context,
|
uri: Uri.parse(path),
|
||||||
IRouteData(
|
extra: extra,
|
||||||
uri: Uri.parse(path),
|
keepAlive: keepAlive,
|
||||||
extra: extra,
|
forResult: forResult,
|
||||||
keepAlive: keepAlive,
|
|
||||||
forResult: forResult,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
Page? page;
|
||||||
|
if (iroute is NotFindNode) {
|
||||||
|
page = (notFindPageBuilder ?? _defaultNotFindPageBuilder)(context, config);
|
||||||
|
} else {
|
||||||
|
page = iroute.createPage(context, config);
|
||||||
|
}
|
||||||
if (page != null) {
|
if (page != null) {
|
||||||
result.add(page);
|
result.add(page);
|
||||||
}
|
}
|
||||||
@@ -201,8 +161,7 @@ class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
|||||||
_completerMap[path]?.complete(result);
|
_completerMap[path]?.complete(result);
|
||||||
_completerMap.remove(path);
|
_completerMap.remove(path);
|
||||||
}
|
}
|
||||||
|
changePath(backPath(path), recordHistory: false);
|
||||||
changePath(backPath(path),recordHistory: false);
|
|
||||||
return route.didPop(result);
|
return route.didPop(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,185 +1,105 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../../pages/color/color_add_page.dart';
|
import 'iroute_config.dart';
|
||||||
import '../../../pages/color/color_detail_page.dart';
|
|
||||||
import '../../../pages/color/color_page.dart';
|
|
||||||
import '../../../pages/counter/counter_page.dart';
|
|
||||||
import '../../../pages/user/user_page.dart';
|
|
||||||
import '../../../pages/settings/settings_page.dart';
|
|
||||||
import '../transition/fade_transition_page.dart';
|
|
||||||
|
|
||||||
class IRoute {
|
typedef IRoutePageBuilder = Page? Function(
|
||||||
|
BuildContext context,
|
||||||
|
IRouteConfig data,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef IRouteWidgetBuilder = Widget? Function(
|
||||||
|
BuildContext context,
|
||||||
|
IRouteConfig data,
|
||||||
|
);
|
||||||
|
|
||||||
|
abstract class IRouteNode {
|
||||||
final String path;
|
final String path;
|
||||||
final IRoutePageBuilder? builder;
|
final List<IRouteNode> children;
|
||||||
final List<IRoute> children;
|
|
||||||
|
|
||||||
const IRoute({
|
const IRouteNode({
|
||||||
required this.path,
|
required this.path,
|
||||||
this.children = const [],
|
required this.children,
|
||||||
this.builder,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
Page? createPage(BuildContext context, IRouteConfig config);
|
||||||
String toString() {
|
|
||||||
return 'IRoute{path: $path, children: $children}';
|
List<IRouteNode> find(String input,) {
|
||||||
|
return findNodes(this, Uri.parse(input), 0, '/', []);
|
||||||
}
|
}
|
||||||
|
|
||||||
IRoute? match(String path) {
|
List<IRouteNode> findNodes(
|
||||||
return matchRoute(this, path);
|
IRouteNode node,
|
||||||
}
|
Uri uri,
|
||||||
|
int deep,
|
||||||
List<IRoute> find(String input){
|
String prefix,
|
||||||
String fixInput = input.substring(1);
|
List<IRouteNode> result,
|
||||||
List<IRoute> nodes = findNodes(this,fixInput,0,'/',[]);
|
) {
|
||||||
if(nodes.isNotEmpty&&nodes.last.path!=input){
|
List<String> parts = uri.pathSegments;
|
||||||
return [];
|
if (deep > parts.length - 1) {
|
||||||
}
|
|
||||||
return nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IRoute> findNodes(IRoute node,String input,int deep,String prefix,List<IRoute> result){
|
|
||||||
String separator = '/';
|
|
||||||
|
|
||||||
List<String> parts = input.split(separator);
|
|
||||||
if(deep>parts.length-1){
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
String target = parts[deep];
|
String target = parts[deep];
|
||||||
if(node.children.isNotEmpty){
|
if (node.children.isNotEmpty) {
|
||||||
List<IRoute> nodes = node.children.where((e) => e.path==prefix+target).toList();
|
target = prefix + target;
|
||||||
|
List<IRouteNode> nodes = node.children.where((e) => e.path == target).toList();
|
||||||
bool match = nodes.isNotEmpty;
|
bool match = nodes.isNotEmpty;
|
||||||
if(match){
|
if (match) {
|
||||||
IRoute matched = nodes.first;
|
IRouteNode matched = nodes.first;
|
||||||
result.add(matched);
|
result.add(matched);
|
||||||
String nextPrefix = '${matched.path}$separator';
|
String nextPrefix = '${matched.path}/';
|
||||||
findNodes(matched, input, ++deep,nextPrefix,result);
|
findNodes(matched, uri, ++deep, nextPrefix, result);
|
||||||
|
}else{
|
||||||
|
result.add(NotFindNode(path: target));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// List<IRoute> findNodes(IRoute node,String input,int deep,String prefix,List<IRoute> result){
|
/// 优先调用 [pageBuilder] 构建 Page
|
||||||
// String separator = '/';
|
/// 没有 [pageBuilder] 时, 使用 [widgetBuilder] 构建组件
|
||||||
// List<String> parts = input.split(separator);
|
/// 没有 [pageBuilder] 和 [widgetBuilder] 时, 使用 [widget] 构建组件
|
||||||
// if(deep>parts.length-1){
|
class IRoute extends IRouteNode {
|
||||||
// return result;
|
final IRoutePageBuilder? pageBuilder;
|
||||||
// }
|
final IRouteWidgetBuilder? widgetBuilder;
|
||||||
// String target = parts[deep];
|
final Widget? widget;
|
||||||
// if(node.children.isNotEmpty){
|
final Map<String,dynamic>? mata;
|
||||||
// List<IRoute> nodes = node.children.where((e) => e.path==prefix+target).toList();
|
|
||||||
// bool match = nodes.isNotEmpty;
|
|
||||||
// if(match){
|
|
||||||
// IRoute matched = nodes.first;
|
|
||||||
// result.add(matched);
|
|
||||||
// String nextPrefix = '${matched.path}$separator';
|
|
||||||
// findNodes(matched, input, ++deep,nextPrefix,result);
|
|
||||||
// }
|
|
||||||
// }else{
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
|
|
||||||
IRoute? matchRoute(IRoute route, String path) {
|
const IRoute({
|
||||||
if (route.path == path) {
|
required super.path,
|
||||||
return route;
|
super.children = const [],
|
||||||
} else {
|
this.mata,
|
||||||
if (route.children.isNotEmpty) {
|
this.widget,
|
||||||
for (int i = 0; i < route.children.length; i++) {
|
this.pageBuilder,
|
||||||
IRoute current = route.children[i];
|
this.widgetBuilder,
|
||||||
IRoute? target = matchRoute(current, path);
|
});
|
||||||
if (target != null) {
|
|
||||||
return target;
|
@override
|
||||||
}
|
Page? createPage(BuildContext context, IRouteConfig config) {
|
||||||
}
|
if (pageBuilder != null) {
|
||||||
} else {
|
return pageBuilder!(context, config);
|
||||||
return null;
|
}
|
||||||
}
|
Widget? child;
|
||||||
|
if (widgetBuilder != null) {
|
||||||
|
child = widgetBuilder!(context, config);
|
||||||
|
}
|
||||||
|
child ??= widget;
|
||||||
|
if (child != null) {
|
||||||
|
return MaterialPage(child: child, key: config.pageKey);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef IRoutePageBuilder = Page? Function(
|
|
||||||
BuildContext context, IRouteData data);
|
|
||||||
|
|
||||||
class IRouteData {
|
|
||||||
final Object? extra;
|
|
||||||
final bool forResult;
|
|
||||||
final Uri uri;
|
|
||||||
final bool keepAlive;
|
|
||||||
|
|
||||||
IRouteData({
|
class NotFindNode extends IRouteNode{
|
||||||
this.extra,
|
NotFindNode({required super.path, super.children= const[]});
|
||||||
required this.uri,
|
|
||||||
this.forResult = false,
|
@override
|
||||||
this.keepAlive = false,
|
Page? createPage(BuildContext context, IRouteConfig config) {
|
||||||
});
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IRoute root = IRoute(path: 'root', children: kDestinationsIRoutes);
|
|
||||||
|
|
||||||
List<IRoute> kDestinationsIRoutes = [
|
|
||||||
IRoute(
|
|
||||||
path: '/color',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/color'),
|
|
||||||
child: ColorPage(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
children: [
|
|
||||||
IRoute(
|
|
||||||
path: '/color/detail',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
final Map<String, String> queryParams = data.uri.queryParameters;
|
|
||||||
String? selectedColor = queryParams['color'];
|
|
||||||
Color color = Colors.black;
|
|
||||||
if (selectedColor != null) {
|
|
||||||
color = Color(int.parse(selectedColor, radix: 16));
|
|
||||||
} else if (data.extra is Color) {
|
|
||||||
color = data.extra as Color;
|
|
||||||
}
|
|
||||||
return FadeTransitionPage(
|
|
||||||
key: const ValueKey('/color/detail'),
|
|
||||||
child: ColorDetailPage(color: color),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
IRoute(
|
|
||||||
path: '/color/add',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/color/add'),
|
|
||||||
child: ColorAddPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
IRoute(
|
|
||||||
path: '/counter',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/counter'),
|
|
||||||
child: CounterPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
IRoute(
|
|
||||||
path: '/user',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/user'),
|
|
||||||
child: UserPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
IRoute(
|
|
||||||
path: '/settings',
|
|
||||||
builder: (ctx, data) {
|
|
||||||
return const FadeTransitionPage(
|
|
||||||
key: ValueKey('/settings'),
|
|
||||||
child: SettingPage(),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|||||||
35
lib/v7/app/navigation/router/iroute_config.dart
Normal file
35
lib/v7/app/navigation/router/iroute_config.dart
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class IRouteConfig {
|
||||||
|
final Object? extra;
|
||||||
|
final bool forResult;
|
||||||
|
final Uri uri;
|
||||||
|
final bool keepAlive;
|
||||||
|
final bool recordHistory;
|
||||||
|
|
||||||
|
const IRouteConfig({
|
||||||
|
this.extra,
|
||||||
|
required this.uri,
|
||||||
|
this.forResult = false,
|
||||||
|
this.keepAlive = false,
|
||||||
|
this.recordHistory = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
String get path => uri.path;
|
||||||
|
|
||||||
|
IRouteConfig copyWith({
|
||||||
|
Object? extra,
|
||||||
|
bool? forResult,
|
||||||
|
bool? keepAlive,
|
||||||
|
bool? recordHistory,
|
||||||
|
}) =>
|
||||||
|
IRouteConfig(
|
||||||
|
extra: extra ?? this.extra,
|
||||||
|
forResult: forResult ?? this.forResult,
|
||||||
|
keepAlive: keepAlive ?? this.keepAlive,
|
||||||
|
recordHistory: recordHistory ?? this.recordHistory,
|
||||||
|
uri: uri,
|
||||||
|
);
|
||||||
|
|
||||||
|
ValueKey get pageKey => ValueKey(path);
|
||||||
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
class RouteHistory{
|
|
||||||
final String path;
|
|
||||||
final Object? extra;
|
|
||||||
|
|
||||||
RouteHistory(this.path, { this.extra});
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,47 @@
|
|||||||
// import 'route_history.dart';
|
import 'iroute_config.dart';
|
||||||
//
|
|
||||||
// class RouteHistoryManager{
|
typedef OnRouteChange = void Function(IRouteConfig config);
|
||||||
// final List<RouteHistory> _histories = [];
|
|
||||||
// final List<RouteHistory> _backHistories = [];
|
class RouteHistoryManager{
|
||||||
//
|
final List<IRouteConfig> _histories = [];
|
||||||
// List<RouteHistory> get histories => _histories.reversed.toList();
|
final List<IRouteConfig> _backHistories = [];
|
||||||
//
|
|
||||||
// bool get hasHistory => _histories.length > 1;
|
List<IRouteConfig> get histories => _histories.reversed.toList();
|
||||||
//
|
|
||||||
// bool get hasBackHistory => _backHistories.isNotEmpty;
|
bool get hasHistory => _histories.length > 1;
|
||||||
// }
|
|
||||||
|
bool get hasBackHistory => _backHistories.isNotEmpty;
|
||||||
|
|
||||||
|
/// 将 [config] 加入历史记录
|
||||||
|
void recode(IRouteConfig config){
|
||||||
|
if (_histories.isNotEmpty && config.path == _histories.last.path) return;
|
||||||
|
_histories.add(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 历史回退操作
|
||||||
|
/// 将当前顶层移除,并加入 [_backHistories] 撤销列表
|
||||||
|
/// 并转到前一路径 [_histories.last]
|
||||||
|
void back(OnRouteChange callback) {
|
||||||
|
if (!hasHistory) return;
|
||||||
|
IRouteConfig top = _histories.removeLast();
|
||||||
|
_backHistories.add(top);
|
||||||
|
if (_histories.isNotEmpty) {
|
||||||
|
callback(_histories.last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 撤销回退操作
|
||||||
|
/// 取出回退列表的最后元素,跳转到该路径
|
||||||
|
void revocation(OnRouteChange callback) {
|
||||||
|
IRouteConfig target = _backHistories.removeLast();
|
||||||
|
callback(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void close(int index) {
|
||||||
|
_histories.removeAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
_histories.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
41
lib/v7/app/navigation/router/routes.dart
Normal file
41
lib/v7/app/navigation/router/routes.dart
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'iroute_config.dart';
|
||||||
|
import 'iroute.dart';
|
||||||
|
import '../../../pages/color/color_add_page.dart';
|
||||||
|
import '../../../pages/color/color_detail_page.dart';
|
||||||
|
import '../../../pages/color/color_page.dart';
|
||||||
|
import '../../../pages/counter/counter_page.dart';
|
||||||
|
import '../../../pages/user/user_page.dart';
|
||||||
|
import '../../../pages/settings/settings_page.dart';
|
||||||
|
import '../../../pages/sort/views/sort_page.dart';
|
||||||
|
|
||||||
|
|
||||||
|
IRoute rootRoute = const IRoute(
|
||||||
|
path: 'root',
|
||||||
|
children: [
|
||||||
|
IRoute(
|
||||||
|
path: '/color',
|
||||||
|
widget: ColorPage(),
|
||||||
|
children: [
|
||||||
|
IRoute(path: '/color/detail', widgetBuilder: _buildColorDetail),
|
||||||
|
IRoute(path: '/color/add', widget: ColorAddPage()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
IRoute(path: '/counter', widget: CounterPage()),
|
||||||
|
IRoute(path: '/sort', widget: SortPage()),
|
||||||
|
IRoute(path: '/user', widget: UserPage()),
|
||||||
|
IRoute(path: '/settings', widget: SettingPage()),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget? _buildColorDetail(BuildContext context, IRouteConfig data) {
|
||||||
|
final Map<String, String> queryParams = data.uri.queryParameters;
|
||||||
|
String? selectedColor = queryParams['color'];
|
||||||
|
Color color = Colors.black;
|
||||||
|
if (selectedColor != null) {
|
||||||
|
color = Color(int.parse(selectedColor, radix: 16));
|
||||||
|
} else if (data.extra is Color) {
|
||||||
|
color = data.extra as Color;
|
||||||
|
}
|
||||||
|
return ColorDetailPage(color: color);
|
||||||
|
}
|
||||||
25
lib/v7/app/navigation/router/views/not_find_view.dart
Normal file
25
lib/v7/app/navigation/router/views/not_find_view.dart
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class NotFindPage extends StatelessWidget {
|
||||||
|
const NotFindPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return const Material(
|
||||||
|
child: Center(
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 16,
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
|
direction: Axis.vertical,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.nearby_error,size: 64, color: Colors.redAccent),
|
||||||
|
Text(
|
||||||
|
'404 Page Not Find',
|
||||||
|
style: TextStyle(fontSize: 24, color: Colors.grey),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class FadePageTransitionsBuilder extends PageTransitionsBuilder {
|
||||||
|
|
||||||
|
const FadePageTransitionsBuilder();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildTransitions<T>(
|
||||||
|
PageRoute<T>? route,
|
||||||
|
BuildContext? context,
|
||||||
|
Animation<double> animation,
|
||||||
|
Animation<double> secondaryAnimation,
|
||||||
|
Widget child,
|
||||||
|
) {
|
||||||
|
return _FadePagePageTransition(
|
||||||
|
animation: animation,
|
||||||
|
secondaryAnimation: secondaryAnimation,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FadePagePageTransition extends StatelessWidget {
|
||||||
|
|
||||||
|
const _FadePagePageTransition({
|
||||||
|
required this.animation,
|
||||||
|
required this.secondaryAnimation,
|
||||||
|
required this.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Animation<double> animation;
|
||||||
|
final Animation<double> secondaryAnimation;
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var curveTween = CurveTween(curve: Curves.easeIn);
|
||||||
|
return FadeTransition(
|
||||||
|
opacity: animation.drive(curveTween),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user