v8
This commit is contained in:
@@ -6,17 +6,27 @@ import 'route_history_manager.dart';
|
||||
import 'routes.dart';
|
||||
import 'views/not_find_view.dart';
|
||||
|
||||
AppRouterDelegate router = AppRouterDelegate();
|
||||
AppRouterDelegate router = AppRouterDelegate(
|
||||
initial: IRouteConfig(uri: Uri.parse('/color')),
|
||||
);
|
||||
|
||||
class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
||||
String _path = '/color';
|
||||
|
||||
String get path => _path;
|
||||
/// 核心数据,路由配置数据列表
|
||||
final List<IRouteConfig> _configs = [];
|
||||
|
||||
String get path => current.uri.path;
|
||||
|
||||
IRouteConfig get current => _configs.last;
|
||||
|
||||
final IRoutePageBuilder? notFindPageBuilder;
|
||||
|
||||
AppRouterDelegate({this.notFindPageBuilder}) {
|
||||
_historyManager.recode(IRouteConfig(uri: Uri.parse(path)));
|
||||
AppRouterDelegate({
|
||||
this.notFindPageBuilder,
|
||||
required IRouteConfig initial,
|
||||
}) {
|
||||
_configs.add(initial);
|
||||
_historyManager.recode(initial);
|
||||
}
|
||||
|
||||
Page _defaultNotFindPageBuilder(_, __) => const MaterialPage(
|
||||
@@ -45,48 +55,60 @@ class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// final List<IRouteConfig> _pathStack = [];
|
||||
|
||||
bool get canPop => _configs.where((e) => e.routeStyle==RouteStyle.push).isNotEmpty;
|
||||
|
||||
final Map<String, Completer<dynamic>> _completerMap = {};
|
||||
final Map<String, dynamic> _pathExtraMap = {};
|
||||
final List<String> keepAlivePath = [];
|
||||
|
||||
FutureOr<dynamic> changeRoute(IRouteConfig config) {
|
||||
String value = config.uri.path;
|
||||
if (_path == value) null;
|
||||
if (current == config) null;
|
||||
_handleChangeStyle(config);
|
||||
|
||||
if (config.forResult) {
|
||||
_completerMap[value] = Completer();
|
||||
}
|
||||
if (config.keepAlive) {
|
||||
if (keepAlivePath.contains(value)) {
|
||||
keepAlivePath.remove(value);
|
||||
}
|
||||
keepAlivePath.add(value);
|
||||
}
|
||||
if (config.extra != null) {
|
||||
_pathExtraMap[value] = config.extra;
|
||||
}
|
||||
|
||||
if (config.recordHistory) {
|
||||
_historyManager.recode(config);
|
||||
}
|
||||
|
||||
_path = value;
|
||||
notifyListeners();
|
||||
if (config.forResult) {
|
||||
return _completerMap[value]!.future;
|
||||
}
|
||||
}
|
||||
|
||||
void _handleChangeStyle(IRouteConfig config){
|
||||
switch (config.routeStyle) {
|
||||
case RouteStyle.push:
|
||||
if (_configs.contains(config)) {
|
||||
_configs.remove(config);
|
||||
}
|
||||
_configs.add(config);
|
||||
break;
|
||||
case RouteStyle.replace:
|
||||
List<IRouteConfig> liveRoutes = _configs.where((e) => e.keepAlive&&e!=config).toList();
|
||||
_configs.clear();
|
||||
_configs.addAll([...liveRoutes,config]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<dynamic> changePath(
|
||||
String value, {
|
||||
bool forResult = false,
|
||||
Object? extra,
|
||||
bool keepAlive = false,
|
||||
bool recordHistory = true,
|
||||
RouteStyle style = RouteStyle.replace,
|
||||
}) {
|
||||
return changeRoute(IRouteConfig(
|
||||
uri: Uri.parse(value),
|
||||
forResult: forResult,
|
||||
extra: extra,
|
||||
routeStyle: style,
|
||||
keepAlive: keepAlive,
|
||||
recordHistory: recordHistory,
|
||||
));
|
||||
@@ -96,46 +118,47 @@ class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
||||
Widget build(BuildContext context) {
|
||||
return Navigator(
|
||||
onPopPage: _onPopPage,
|
||||
pages: _buildPages(context, path),
|
||||
pages: _buildPages(context, _configs),
|
||||
);
|
||||
}
|
||||
|
||||
List<Page> _buildPages(BuildContext context, String path) {
|
||||
List<Page> _buildPages(BuildContext context, List<IRouteConfig> configs) {
|
||||
IRouteConfig top = configs.last;
|
||||
List<IRouteConfig> bottoms = _configs.sublist(0,_configs.length-1).toList();
|
||||
List<Page> pages = [];
|
||||
List<Page> topPages = _buildPageByPathFromTree(context, path);
|
||||
|
||||
if (keepAlivePath.isNotEmpty) {
|
||||
for (String alivePath in keepAlivePath) {
|
||||
if (alivePath != path) {
|
||||
pages.addAll(_buildPageByPathFromTree(context, alivePath));
|
||||
}
|
||||
}
|
||||
|
||||
/// 去除和 topPages 中重复的界面
|
||||
pages.removeWhere(
|
||||
(element) => topPages.map((e) => e.key).contains(element.key));
|
||||
}
|
||||
|
||||
List<Page> topPages = _buildPageByPathFromTree(context, top);
|
||||
pages = _buildLivePageByPathList(context, bottoms, top, topPages);
|
||||
pages.addAll(topPages);
|
||||
return pages;
|
||||
}
|
||||
|
||||
List<Page> _buildPageByPathFromTree(BuildContext context, String path) {
|
||||
List<Page> _buildLivePageByPathList(
|
||||
BuildContext context,
|
||||
List<IRouteConfig> paths,
|
||||
IRouteConfig curConfig,
|
||||
List<Page> curPages,
|
||||
) {
|
||||
List<Page> pages = [];
|
||||
if (paths.isNotEmpty) {
|
||||
for (IRouteConfig path in paths) {
|
||||
if (path != curConfig) {
|
||||
pages.addAll(_buildPageByPathFromTree(context, path));
|
||||
}
|
||||
}
|
||||
/// 去除和 curPages 中重复的界面
|
||||
pages.removeWhere((page) => curPages.map((e) => e.key).contains(page.key));
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
|
||||
List<Page> _buildPageByPathFromTree(
|
||||
BuildContext context, IRouteConfig config) {
|
||||
List<Page> result = [];
|
||||
List<IRouteNode> iRoutes = rootRoute.find(path);
|
||||
List<IRouteNode> iRoutes = rootRoute.find(config.path);
|
||||
if (iRoutes.isNotEmpty) {
|
||||
for (int i = 0; i < iRoutes.length; i++) {
|
||||
IRouteNode iroute = iRoutes[i];
|
||||
String path = iroute.path;
|
||||
Object? extra = _pathExtraMap[path];
|
||||
bool keepAlive = keepAlivePath.contains(path);
|
||||
bool forResult = _completerMap.containsKey(path);
|
||||
IRouteConfig config = IRouteConfig(
|
||||
uri: Uri.parse(path),
|
||||
extra: extra,
|
||||
keepAlive: keepAlive,
|
||||
forResult: forResult,
|
||||
);
|
||||
config = config.copyWith(path: iroute.path);
|
||||
Page? page;
|
||||
if (iroute is NotFindNode) {
|
||||
page = (notFindPageBuilder ?? _defaultNotFindPageBuilder)(context, config);
|
||||
@@ -145,6 +168,9 @@ class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
||||
if (page != null) {
|
||||
result.add(page);
|
||||
}
|
||||
if(iroute is CellIRoute){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -156,12 +182,29 @@ class AppRouterDelegate extends RouterDelegate<Object> with ChangeNotifier {
|
||||
return true;
|
||||
}
|
||||
|
||||
void backStack() {
|
||||
if (_configs.isNotEmpty) {
|
||||
_configs.removeLast();
|
||||
if (_configs.isNotEmpty) {
|
||||
changeRoute(_configs.last);
|
||||
} else {
|
||||
changeRoute(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool _onPopPage(Route route, result) {
|
||||
if (_completerMap.containsKey(path)) {
|
||||
_completerMap[path]?.complete(result);
|
||||
_completerMap.remove(path);
|
||||
}
|
||||
changePath(backPath(path), recordHistory: false);
|
||||
|
||||
if (_configs.isNotEmpty) {
|
||||
_configs.removeLast();
|
||||
notifyListeners();
|
||||
} else {
|
||||
changePath(backPath(path), recordHistory: false);
|
||||
}
|
||||
return route.didPop(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
import 'iroute_config.dart';
|
||||
|
||||
typedef IRoutePageBuilder = Page? Function(
|
||||
@@ -24,7 +23,9 @@ abstract class IRouteNode {
|
||||
|
||||
Page? createPage(BuildContext context, IRouteConfig config);
|
||||
|
||||
List<IRouteNode> find(String input,) {
|
||||
List<IRouteNode> find(
|
||||
String input,
|
||||
) {
|
||||
return findNodes(this, Uri.parse(input), 0, '/', []);
|
||||
}
|
||||
|
||||
@@ -41,15 +42,16 @@ abstract class IRouteNode {
|
||||
}
|
||||
String target = parts[deep];
|
||||
if (node.children.isNotEmpty) {
|
||||
target = prefix + target;
|
||||
List<IRouteNode> nodes = node.children.where((e) => e.path == target).toList();
|
||||
target = prefix + target;
|
||||
List<IRouteNode> nodes =
|
||||
node.children.where((e) => e.path == target).toList();
|
||||
bool match = nodes.isNotEmpty;
|
||||
if (match) {
|
||||
IRouteNode matched = nodes.first;
|
||||
result.add(matched);
|
||||
String nextPrefix = '${matched.path}/';
|
||||
findNodes(matched, uri, ++deep, nextPrefix, result);
|
||||
}else{
|
||||
} else {
|
||||
result.add(NotFindNode(path: target));
|
||||
return result;
|
||||
}
|
||||
@@ -92,8 +94,8 @@ class IRoute extends IRouteNode {
|
||||
}
|
||||
|
||||
/// 未知路由
|
||||
class NotFindNode extends IRouteNode{
|
||||
NotFindNode({required super.path, super.children= const[]});
|
||||
class NotFindNode extends IRouteNode {
|
||||
NotFindNode({required super.path, super.children = const []});
|
||||
|
||||
@override
|
||||
Page? createPage(BuildContext context, IRouteConfig config) {
|
||||
@@ -101,15 +103,14 @@ class NotFindNode extends IRouteNode{
|
||||
}
|
||||
}
|
||||
|
||||
class CellIRouter extends IRoute {
|
||||
final CellBuilder cellBuilder;
|
||||
|
||||
CellIRouter(
|
||||
{required super.path,
|
||||
super.pageBuilder,
|
||||
super.children,
|
||||
required this.cellBuilder});
|
||||
class CellIRoute extends IRoute {
|
||||
const CellIRoute({
|
||||
required super.path,
|
||||
super.pageBuilder,
|
||||
super.children,
|
||||
super.widget,
|
||||
});
|
||||
}
|
||||
|
||||
typedef CellBuilder = Widget Function(BuildContext context, Widget child);
|
||||
|
||||
typedef CellBuilder = Widget Function(BuildContext context,IRouteConfig config, CellIRoute cell);
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum RouteStyle{
|
||||
push,
|
||||
replace,
|
||||
}
|
||||
|
||||
|
||||
class IRouteConfig {
|
||||
final Object? extra;
|
||||
final bool forResult;
|
||||
final Uri uri;
|
||||
final bool keepAlive;
|
||||
final RouteStyle routeStyle;
|
||||
final bool recordHistory;
|
||||
|
||||
const IRouteConfig({
|
||||
@@ -12,6 +19,7 @@ class IRouteConfig {
|
||||
required this.uri,
|
||||
this.forResult = false,
|
||||
this.keepAlive = false,
|
||||
this.routeStyle = RouteStyle.replace,
|
||||
this.recordHistory = false,
|
||||
});
|
||||
|
||||
@@ -22,14 +30,42 @@ class IRouteConfig {
|
||||
bool? forResult,
|
||||
bool? keepAlive,
|
||||
bool? recordHistory,
|
||||
String? path,
|
||||
}) =>
|
||||
IRouteConfig(
|
||||
extra: extra ?? this.extra,
|
||||
forResult: forResult ?? this.forResult,
|
||||
keepAlive: keepAlive ?? this.keepAlive,
|
||||
recordHistory: recordHistory ?? this.recordHistory,
|
||||
uri: uri,
|
||||
uri: path!=null?Uri.parse(path):uri,
|
||||
);
|
||||
|
||||
ValueKey get pageKey => ValueKey(path);
|
||||
ValueKey get pageKey => ValueKey(hashCode);
|
||||
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'IRouteConfig{extra: $extra, forResult: $forResult, uri: $uri, keepAlive: $keepAlive, routeStyle: $routeStyle, recordHistory: $recordHistory}';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is IRouteConfig &&
|
||||
runtimeType == other.runtimeType &&
|
||||
extra == other.extra &&
|
||||
forResult == other.forResult &&
|
||||
uri == other.uri &&
|
||||
keepAlive == other.keepAlive &&
|
||||
routeStyle == other.routeStyle &&
|
||||
recordHistory == other.recordHistory;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
extra.hashCode ^
|
||||
forResult.hashCode ^
|
||||
uri.hashCode ^
|
||||
keepAlive.hashCode ^
|
||||
routeStyle.hashCode ^
|
||||
recordHistory.hashCode;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../pages/sort/views/player/sort_player.dart';
|
||||
import 'iroute_config.dart';
|
||||
import 'iroute.dart';
|
||||
import '../../../pages/color/color_add_page.dart';
|
||||
@@ -7,8 +8,8 @@ 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';
|
||||
|
||||
import '../../../pages/sort/views/sort_page/sort_page.dart';
|
||||
import '../../../pages/sort/views/settings/sort_setting.dart';
|
||||
|
||||
IRoute rootRoute = const IRoute(
|
||||
path: 'root',
|
||||
@@ -22,7 +23,20 @@ IRoute rootRoute = const IRoute(
|
||||
],
|
||||
),
|
||||
IRoute(path: '/counter', widget: CounterPage()),
|
||||
IRoute(path: '/sort', widget: SortPage()),
|
||||
CellIRoute(
|
||||
path: '/sort',
|
||||
widget: SortPage(),
|
||||
children: [
|
||||
IRoute(
|
||||
path: '/sort/settings',
|
||||
widget: SortSettings(),
|
||||
),
|
||||
IRoute(
|
||||
path: '/sort/player',
|
||||
widget: SortPlayer(),
|
||||
),
|
||||
],
|
||||
),
|
||||
IRoute(path: '/user', widget: UserPage()),
|
||||
IRoute(path: '/settings', widget: SettingPage()),
|
||||
],
|
||||
|
||||
52
lib/v8/app/navigation/router/views/route_back_indicator.dart
Normal file
52
lib/v8/app/navigation/router/views/route_back_indicator.dart
Normal file
@@ -0,0 +1,52 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../app_router_delegate.dart';
|
||||
class RouteBackIndicator extends StatefulWidget {
|
||||
const RouteBackIndicator({super.key});
|
||||
|
||||
@override
|
||||
State<RouteBackIndicator> createState() => _RouteBackIndicatorState();
|
||||
}
|
||||
|
||||
class _RouteBackIndicatorState extends State<RouteBackIndicator> {
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
router.addListener(_onChange);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
router.removeListener(_onChange);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if(router.canPop){
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: router.backStack,
|
||||
child: Container(
|
||||
width: 26,
|
||||
height: 26,
|
||||
margin: EdgeInsets.only(right: 8),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xffE3E5E7),
|
||||
borderRadius: BorderRadius.circular(6)
|
||||
),
|
||||
child: Icon(Icons.arrow_back_ios_new,size: 14,)),
|
||||
),
|
||||
);
|
||||
}
|
||||
return SizedBox();
|
||||
}
|
||||
|
||||
void _onChange() {
|
||||
setState(() {
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:iroute/components/components.dart';
|
||||
import '../router/app_router_delegate.dart';
|
||||
import '../router/iroute_config.dart';
|
||||
|
||||
class AppNavigationRail extends StatefulWidget {
|
||||
const AppNavigationRail({super.key});
|
||||
@@ -10,13 +11,12 @@ class AppNavigationRail extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _AppNavigationRailState extends State<AppNavigationRail> {
|
||||
|
||||
final List<MenuMeta> deskNavBarMenus = const [
|
||||
MenuMeta(label: '颜色板', icon: Icons.color_lens_outlined,path: '/color'),
|
||||
MenuMeta(label: '计数器', icon: Icons.add_chart,path: '/counter'),
|
||||
MenuMeta(label: '排序', icon: Icons.sort,path: '/sort'),
|
||||
MenuMeta(label: '我的', icon: Icons.person,path: '/user'),
|
||||
MenuMeta(label: '设置', icon: Icons.settings,path: '/settings'),
|
||||
MenuMeta(label: '颜色板', icon: Icons.color_lens_outlined, path: '/color'),
|
||||
MenuMeta(label: '计数器', icon: Icons.add_chart, path: '/counter'),
|
||||
MenuMeta(label: '排序', icon: Icons.sort, path: '/sort'),
|
||||
MenuMeta(label: '我的', icon: Icons.person, path: '/user'),
|
||||
MenuMeta(label: '设置', icon: Icons.settings, path: '/settings'),
|
||||
];
|
||||
|
||||
@override
|
||||
@@ -42,7 +42,10 @@ class _AppNavigationRailState extends State<AppNavigationRail> {
|
||||
),
|
||||
tail: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 6.0),
|
||||
child: Text('V0.0.7',style: TextStyle(color: Colors.white,fontSize: 12),),
|
||||
child: Text(
|
||||
'V0.0.8',
|
||||
style: TextStyle(color: Colors.white, fontSize: 12),
|
||||
),
|
||||
),
|
||||
backgroundColor: const Color(0xff3975c6),
|
||||
onDestinationSelected: _onDestinationSelected,
|
||||
@@ -53,21 +56,26 @@ class _AppNavigationRailState extends State<AppNavigationRail> {
|
||||
|
||||
RegExp _segReg = RegExp(r'/\w+');
|
||||
|
||||
int? get activeIndex{
|
||||
int? get activeIndex {
|
||||
String path = router.path;
|
||||
RegExpMatch? match = _segReg.firstMatch(path);
|
||||
if(match==null) return null;
|
||||
if (match == null) return null;
|
||||
String? target = match.group(0);
|
||||
int index = deskNavBarMenus.indexWhere((menu) => menu.path==target);
|
||||
if(index==-1) return null;
|
||||
int index = deskNavBarMenus.indexWhere((menu) => menu.path == target);
|
||||
if (index == -1) return null;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
void _onDestinationSelected(int index) {
|
||||
String path = deskNavBarMenus[index].path!;
|
||||
if(index==1){
|
||||
router.changePath(path,keepAlive: true);
|
||||
}else{
|
||||
if (index == 1) {
|
||||
router.changePath(path, keepAlive: true);
|
||||
return;
|
||||
}
|
||||
if (index == 4) {
|
||||
router.changePath(path, style: RouteStyle.push);
|
||||
return;
|
||||
} else {
|
||||
router.changePath(path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:iroute/components/components.dart';
|
||||
import '../../router/app_router_delegate.dart';
|
||||
import '../../router/views/route_back_indicator.dart';
|
||||
import 'app_router_editor.dart';
|
||||
import 'history_view_icon.dart';
|
||||
import 'route_history_button.dart';
|
||||
@@ -17,6 +18,7 @@ class AppTopBar extends StatelessWidget {
|
||||
child: Row(
|
||||
children: [
|
||||
const SizedBox(width: 16),
|
||||
const RouteBackIndicator(),
|
||||
const RouterIndicator(),
|
||||
Expanded(
|
||||
child: Row(children: [
|
||||
@@ -58,6 +60,7 @@ Map<String, String> kRouteLabelMap = {
|
||||
'/color/detail': '颜色详情',
|
||||
'/counter': '计数器',
|
||||
'/sort': '可视化排序算法',
|
||||
'/sort/settings': '排序配置',
|
||||
'/user': '我的',
|
||||
'/settings': '系统设置',
|
||||
};
|
||||
|
||||
@@ -7,17 +7,20 @@ class SortConfig {
|
||||
final int seed;
|
||||
final Duration duration;
|
||||
final String name;
|
||||
final int colorIndex;
|
||||
|
||||
SortConfig({
|
||||
this.count = 100,
|
||||
this.duration = const Duration(microseconds: 1500),
|
||||
this.seed = -1,
|
||||
this.colorIndex = 0,
|
||||
this.name = 'insertion',
|
||||
});
|
||||
|
||||
SortConfig copyWith({
|
||||
int? count,
|
||||
int? seed,
|
||||
int? colorIndex,
|
||||
Duration? duration,
|
||||
String? name,
|
||||
}) =>
|
||||
@@ -26,6 +29,7 @@ class SortConfig {
|
||||
seed:seed??this.seed,
|
||||
duration:duration??this.duration,
|
||||
name:name??this.name,
|
||||
colorIndex:colorIndex??this.colorIndex,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../functions.dart';
|
||||
import 'sort_config.dart';
|
||||
@@ -11,6 +11,20 @@ enum SortStatus{
|
||||
sorted, // 排序完成
|
||||
}
|
||||
|
||||
List<MaterialColor> kColorSupport = [
|
||||
Colors.blue,
|
||||
Colors.lightBlue,
|
||||
Colors.cyan,
|
||||
Colors.red,
|
||||
Colors.pink,
|
||||
Colors.orange,
|
||||
Colors.yellow,
|
||||
Colors.green,
|
||||
Colors.indigo,
|
||||
Colors.purple,
|
||||
Colors.deepPurple,
|
||||
];
|
||||
|
||||
class SortState with ChangeNotifier{
|
||||
|
||||
SortState(){
|
||||
@@ -37,6 +51,11 @@ class SortState with ChangeNotifier{
|
||||
config = config.copyWith(name: name);
|
||||
}
|
||||
|
||||
void selectColor(int colorIndex){
|
||||
if(colorIndex==config.colorIndex) return;
|
||||
config = config.copyWith(colorIndex: colorIndex);
|
||||
}
|
||||
|
||||
void reset(){
|
||||
data.clear();
|
||||
status = SortStatus.none;
|
||||
|
||||
@@ -5,8 +5,9 @@ import 'package:flutter/material.dart';
|
||||
class DataPainter extends CustomPainter{
|
||||
|
||||
final List<int> data;
|
||||
final MaterialColor color;
|
||||
|
||||
DataPainter({required this.data});
|
||||
DataPainter( {required this.data,required this.color,});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
@@ -17,28 +18,29 @@ class DataPainter extends CustomPainter{
|
||||
paint.strokeWidth = itemWidth;
|
||||
paint.strokeCap = StrokeCap.round;
|
||||
|
||||
|
||||
for(int i=0;i<data.length;i++){
|
||||
int value = data[i];
|
||||
if (value < 1000 * .10) {
|
||||
paint.color = Colors.blue.shade100;
|
||||
paint.color = color.shade50;
|
||||
} else if (value < 1000 * .20) {
|
||||
paint.color = Colors.blue.shade200;
|
||||
paint.color = color.shade100;
|
||||
} else if (value < 1000 * .30) {
|
||||
paint.color = Colors.blue.shade300;
|
||||
paint.color = color.shade200;
|
||||
} else if (value < 1000 * .40) {
|
||||
paint.color = Colors.blue.shade400;
|
||||
paint.color = color.shade300;
|
||||
} else if (value < 1000 * .50) {
|
||||
paint.color = Colors.blue.shade500;
|
||||
paint.color = color.shade400;
|
||||
} else if (value < 1000 * .60) {
|
||||
paint.color = Colors.blue.shade600;
|
||||
paint.color = color.shade500;
|
||||
} else if (value < 1000 * .70) {
|
||||
paint.color = Colors.blue.shade700;
|
||||
paint.color = color.shade600;
|
||||
} else if (value < 1000 * .80) {
|
||||
paint.color = Colors.blue.shade800;
|
||||
paint.color = color.shade700;
|
||||
} else if (value < 1000 * .90) {
|
||||
paint.color = Colors.blue.shade900;
|
||||
paint.color = color.shade800;
|
||||
} else {
|
||||
paint.color = const Color(0xFF011E51);
|
||||
paint.color = color.shade900;
|
||||
}
|
||||
canvas.drawLine(
|
||||
Offset(i * itemWidth+itemWidth/2, 0),
|
||||
22
lib/v8/pages/sort/views/player/sort_player.dart
Normal file
22
lib/v8/pages/sort/views/player/sort_player.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../provider/state.dart';
|
||||
import 'data_painter.dart';
|
||||
|
||||
class SortPlayer extends StatelessWidget {
|
||||
const SortPlayer({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SortState state = SortStateScope.of(context);
|
||||
List<int> numbers = state.data;
|
||||
MaterialColor color = kColorSupport[state.config.colorIndex];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: CustomPaint(
|
||||
painter: DataPainter(data: numbers,color: color),
|
||||
child: ConstrainedBox(constraints: const BoxConstraints.expand()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
41
lib/v8/pages/sort/views/settings/color_picker.dart
Normal file
41
lib/v8/pages/sort/views/settings/color_picker.dart
Normal file
@@ -0,0 +1,41 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ColorPicker extends StatelessWidget {
|
||||
final List<MaterialColor> colors;
|
||||
final ValueChanged<int> onSelected;
|
||||
final int activeIndex;
|
||||
|
||||
const ColorPicker({
|
||||
super.key,
|
||||
required this.colors,
|
||||
required this.activeIndex,
|
||||
required this.onSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Wrap(
|
||||
children: colors
|
||||
.asMap()
|
||||
.keys
|
||||
.map((int index) => MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: ()=>onSelected(index),
|
||||
child: Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
color: colors[index],
|
||||
child: activeIndex == index
|
||||
? const Icon(
|
||||
Icons.check,
|
||||
color: Colors.white,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
169
lib/v8/pages/sort/views/settings/sort_setting.dart
Normal file
169
lib/v8/pages/sort/views/settings/sort_setting.dart
Normal file
@@ -0,0 +1,169 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../provider/state.dart';
|
||||
import 'color_picker.dart';
|
||||
class SortSettings extends StatefulWidget {
|
||||
|
||||
const SortSettings({super.key,});
|
||||
|
||||
@override
|
||||
State<SortSettings> createState() => _SortSettingsState();
|
||||
}
|
||||
|
||||
class _SortSettingsState extends State<SortSettings> {
|
||||
final TextEditingController _count = TextEditingController();
|
||||
final TextEditingController _duration = TextEditingController();
|
||||
final TextEditingController _seed = TextEditingController();
|
||||
int _colorIndex = 0;
|
||||
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
SortState state = SortStateScope.of(context);
|
||||
_count.text = state.config.count.toString();
|
||||
_duration.text = state.config.duration.inMicroseconds.toString();
|
||||
_seed.text = state.config.seed.toString();
|
||||
_colorIndex = state.config.colorIndex;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SortState state = SortStateScope.of(context);
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
leading: Align(
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: (){
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Container(
|
||||
width: 28,
|
||||
height: 28,
|
||||
margin: EdgeInsets.only(right: 8,left: 8),
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xffE3E5E7),
|
||||
borderRadius: BorderRadius.circular(6)
|
||||
),
|
||||
child: Icon(Icons.arrow_back_ios_new,size: 18,)),
|
||||
),
|
||||
),
|
||||
),
|
||||
// leading: BackButton(),
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8.0),
|
||||
child: IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: (){
|
||||
SortState state = SortStateScope.of(context);
|
||||
state.config =state.config.copyWith(
|
||||
count: int.parse(_count.text),
|
||||
duration: Duration(
|
||||
microseconds: int.parse(_duration.text),
|
||||
),
|
||||
seed: int.parse(_seed.text),
|
||||
colorIndex: _colorIndex
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
}, icon: Icon(Icons.check)),
|
||||
)],
|
||||
iconTheme: IconThemeData(color: Colors.black),
|
||||
titleTextStyle: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
centerTitle: true,
|
||||
title: Text('排序算法配置'),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text('数据数量(个数):'),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _count,
|
||||
)),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text('时间间隔(微秒):'),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _duration,
|
||||
)),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text('随机种子:'),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _seed,
|
||||
)),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20,),
|
||||
|
||||
Row(
|
||||
children: [
|
||||
Text('选择颜色:'),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Expanded(
|
||||
child: ColorPicker(
|
||||
colors: kColorSupport,
|
||||
onSelected: (index){
|
||||
setState(() {
|
||||
_colorIndex = index;
|
||||
});
|
||||
},
|
||||
activeIndex: _colorIndex,
|
||||
),),
|
||||
],
|
||||
),
|
||||
|
||||
Spacer(),
|
||||
// ElevatedButton(
|
||||
// onPressed: () {
|
||||
// SortState state = SortStateScope.of(context);
|
||||
// state.config =state.config.copyWith(
|
||||
// count: int.parse(_count.text),
|
||||
// duration: Duration(
|
||||
// microseconds: int.parse(_duration.text),
|
||||
// ),
|
||||
// seed: int.parse(_seed.text)
|
||||
// );
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// child: Text('确定设置'))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:iroute/components/components.dart';
|
||||
|
||||
import '../provider/state.dart';
|
||||
import '../functions.dart';
|
||||
import 'sort_button.dart';
|
||||
|
||||
class SortBar extends StatelessWidget {
|
||||
const SortBar({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SortState state = SortStateScope.of(context);
|
||||
return Row(
|
||||
children: [
|
||||
const SortButton(),
|
||||
const SizedBox(width: 10,),
|
||||
DropSelectableWidget(
|
||||
value: sortNameMap[state.config.name]!,
|
||||
fontSize: 12,
|
||||
data: sortNameMap.values.toList(),
|
||||
iconSize: 20,
|
||||
height: 28,
|
||||
width: 200,
|
||||
disableColor: const Color(0xff1F425F),
|
||||
onDropSelected: (int index) async {
|
||||
SortState state = SortStateScope.of(context);
|
||||
state.config =state.config.copyWith(
|
||||
name: sortNameMap.keys.toList()[index]
|
||||
);
|
||||
// curveAnim = CurvedAnimation(
|
||||
// parent: _ctrl, curve: maps.values.toList()[index]);
|
||||
// _startAnim();
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 10,),
|
||||
GestureDetector(
|
||||
onTap: (){
|
||||
Scaffold.of(context).openEndDrawer();
|
||||
// showDialog(
|
||||
// useRootNavigator: false,
|
||||
// context: context, builder: (ctx)=>AlertDialog());
|
||||
},
|
||||
child: const Icon(Icons.settings))
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'sort_setting.dart';
|
||||
import 'code_page/code_page.dart';
|
||||
import 'sort_button.dart';
|
||||
|
||||
import '../functions.dart';
|
||||
import '../provider/state.dart';
|
||||
import 'data_painter.dart';
|
||||
|
||||
class SortPage extends StatelessWidget {
|
||||
const SortPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SortState state = SortStateScope.of(context);
|
||||
List<int> numbers = state.data;
|
||||
return Scaffold(
|
||||
body: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 220,
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
// color: Color(0xffF4F4F4),
|
||||
padding: EdgeInsets.symmetric(horizontal: 12,vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
SortButton(),
|
||||
Spacer(),
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: (){
|
||||
(key.currentState as NavigatorState).push(MaterialPageRoute(builder: (_)=>CodePage()));
|
||||
},
|
||||
child: const Icon(CupertinoIcons.chevron_left_slash_chevron_right,size: 18,)),
|
||||
),
|
||||
SizedBox(width: 8,),
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: (){
|
||||
|
||||
(key.currentState as NavigatorState).push(MaterialPageRoute(builder: (_)=>SortSettings()));
|
||||
},
|
||||
child: Icon(CupertinoIcons.settings,size: 18,)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Divider(height: 1,),
|
||||
Expanded(
|
||||
child: SortSelectorPanel(
|
||||
active: state.config.name,
|
||||
options: sortNameMap.values.toList(),
|
||||
onSelected: state.selectName,
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
VerticalDivider(width: 1,),
|
||||
Expanded(
|
||||
child: NavigatorScope(),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onSelected(String value) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
final GlobalKey key = GlobalKey();
|
||||
|
||||
class NavigatorScope extends StatefulWidget {
|
||||
const NavigatorScope({super.key});
|
||||
|
||||
@override
|
||||
State<NavigatorScope> createState() => _NavigatorScopeState();
|
||||
}
|
||||
|
||||
class _NavigatorScopeState extends State<NavigatorScope> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SortState state = SortStateScope.of(context);
|
||||
List<int> numbers = state.data;
|
||||
return Navigator(
|
||||
onPopPage: _onPopPage,
|
||||
key: key,
|
||||
pages: [
|
||||
MaterialPage(child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: CustomPaint(
|
||||
painter: DataPainter(data: numbers),
|
||||
child: ConstrainedBox(constraints: BoxConstraints.expand()),
|
||||
),
|
||||
))
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
bool _onPopPage(Route<dynamic> route, result) {
|
||||
return route.didPop(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class SortSelectorPanel extends StatelessWidget {
|
||||
final String active;
|
||||
final ValueChanged<String> onSelected;
|
||||
final List<String> options;
|
||||
|
||||
const SortSelectorPanel(
|
||||
{super.key, required this.active, required this.options, required this.onSelected});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
padding: EdgeInsets.symmetric(vertical: 8),
|
||||
itemExtent: 46,
|
||||
itemCount: sortNameMap.length,
|
||||
itemBuilder: _buildByIndex,
|
||||
);
|
||||
}
|
||||
|
||||
Widget? _buildByIndex(BuildContext context, int index) {
|
||||
String key = sortNameMap.keys.toList()[index];
|
||||
bool selected = sortNameMap.keys.toList()[index] == active;
|
||||
return SortItemTile(
|
||||
selected: selected,
|
||||
onTap: ()=>onSelected(key),
|
||||
title: options[index],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SortItemTile extends StatefulWidget {
|
||||
final String title;
|
||||
final VoidCallback onTap;
|
||||
final bool selected;
|
||||
const SortItemTile({super.key, required this.title, required this.selected, required this.onTap});
|
||||
|
||||
@override
|
||||
State<SortItemTile> createState() => _SortItemTileState();
|
||||
}
|
||||
|
||||
class _SortItemTileState extends State<SortItemTile> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0,vertical: 2),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
color: widget.selected?Color(0xffE6F0FF):null
|
||||
),
|
||||
padding: EdgeInsets.only(left: 12),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
widget.title,
|
||||
style: TextStyle(fontSize: 14,
|
||||
fontWeight: widget.selected?FontWeight.bold:null
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../provider/state.dart';
|
||||
import '../../provider/state.dart';
|
||||
|
||||
class SortButton extends StatelessWidget {
|
||||
const SortButton({super.key});
|
||||
@@ -49,7 +49,6 @@ class SortButton extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(width: 4,),
|
||||
Text(text,style: TextStyle(fontSize: 12,fontWeight: FontWeight.bold,color: color),),
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
230
lib/v8/pages/sort/views/sort_page/sort_page.dart
Normal file
230
lib/v8/pages/sort/views/sort_page/sort_page.dart
Normal file
@@ -0,0 +1,230 @@
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../player/sort_player.dart';
|
||||
import '../../../../app/navigation/router/app_router_delegate.dart';
|
||||
import '../settings/sort_setting.dart';
|
||||
import 'sort_button.dart';
|
||||
|
||||
import '../../functions.dart';
|
||||
import '../../provider/state.dart';
|
||||
|
||||
class SortPage extends StatefulWidget {
|
||||
const SortPage({super.key});
|
||||
|
||||
@override
|
||||
State<SortPage> createState() => _SortPageState();
|
||||
}
|
||||
|
||||
class _SortPageState extends State<SortPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 220,
|
||||
child: SortRailPanel(),
|
||||
),
|
||||
VerticalDivider(
|
||||
width: 1,
|
||||
),
|
||||
Expanded(
|
||||
child: SortNavigatorScope(),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SortRailPanel extends StatelessWidget {
|
||||
const SortRailPanel({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SortState state = SortStateScope.of(context);
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
child: Row(
|
||||
children: [
|
||||
const SortButton(),
|
||||
const Spacer(),
|
||||
const MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: Icon(
|
||||
CupertinoIcons.chevron_left_slash_chevron_right,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 8,
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
router.changePath('/sort/settings');
|
||||
},
|
||||
child: const Icon(
|
||||
CupertinoIcons.settings,
|
||||
size: 18,
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
height: 1,
|
||||
),
|
||||
Expanded(
|
||||
child: SortSelectorPanel(
|
||||
active: state.config.name,
|
||||
options: sortNameMap.values.toList(),
|
||||
onSelected: (name) {
|
||||
state.selectName(name);
|
||||
router.changePath('/sort');
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SortNavigatorScope extends StatefulWidget {
|
||||
const SortNavigatorScope({super.key});
|
||||
|
||||
@override
|
||||
State<SortNavigatorScope> createState() => _SortNavigatorScopeState();
|
||||
}
|
||||
|
||||
class _SortNavigatorScopeState extends State<SortNavigatorScope> {
|
||||
@override
|
||||
void initState() {
|
||||
router.addListener(_update);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
router.removeListener(_update);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
String path = router.path;
|
||||
List<Page> pages = buildPagesByPath(context, path);
|
||||
return Navigator(
|
||||
onPopPage: _onPopPage,
|
||||
pages: pages,
|
||||
);
|
||||
}
|
||||
|
||||
bool _onPopPage(Route<dynamic> route, result) {
|
||||
return route.didPop(result);
|
||||
}
|
||||
|
||||
List<Page> buildPagesByPath(BuildContext context, String path) {
|
||||
if (path == '/sort/settings') {
|
||||
return [
|
||||
const MaterialPage(key: ValueKey('/sort/player'), child: SortPlayer()),
|
||||
const MaterialPage(
|
||||
key: ValueKey('/sort/settings'),
|
||||
child: SortSettings(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
const MaterialPage(
|
||||
key: ValueKey('/sort/player'),
|
||||
child: SortPlayer(),
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
void _update() {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
||||
class SortSelectorPanel extends StatelessWidget {
|
||||
final String active;
|
||||
final ValueChanged<String> onSelected;
|
||||
final List<String> options;
|
||||
|
||||
const SortSelectorPanel(
|
||||
{super.key,
|
||||
required this.active,
|
||||
required this.options,
|
||||
required this.onSelected});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
itemExtent: 46,
|
||||
itemCount: sortNameMap.length,
|
||||
itemBuilder: _buildByIndex,
|
||||
);
|
||||
}
|
||||
|
||||
Widget? _buildByIndex(BuildContext context, int index) {
|
||||
String key = sortNameMap.keys.toList()[index];
|
||||
bool selected = sortNameMap.keys.toList()[index] == active;
|
||||
return SortItemTile(
|
||||
selected: selected,
|
||||
onTap: () => onSelected(key),
|
||||
title: options[index],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SortItemTile extends StatefulWidget {
|
||||
final String title;
|
||||
final VoidCallback onTap;
|
||||
final bool selected;
|
||||
|
||||
const SortItemTile(
|
||||
{super.key,
|
||||
required this.title,
|
||||
required this.selected,
|
||||
required this.onTap});
|
||||
|
||||
@override
|
||||
State<SortItemTile> createState() => _SortItemTileState();
|
||||
}
|
||||
|
||||
class _SortItemTileState extends State<SortItemTile> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: GestureDetector(
|
||||
onTap: widget.onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 2),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
color: widget.selected ? const Color(0xffE6F0FF) : null),
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
widget.title,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: widget.selected ? FontWeight.bold : null),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../provider/sort_config.dart';
|
||||
import '../provider/state.dart';
|
||||
|
||||
class SortSettings extends StatefulWidget {
|
||||
|
||||
const SortSettings({super.key,});
|
||||
|
||||
@override
|
||||
State<SortSettings> createState() => _SortSettingsState();
|
||||
}
|
||||
|
||||
class _SortSettingsState extends State<SortSettings> {
|
||||
late TextEditingController _count =
|
||||
TextEditingController();
|
||||
late TextEditingController _duration = TextEditingController();
|
||||
late TextEditingController _seed =
|
||||
TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
print('========_SortSettingsState#didChangeDependencies=============');
|
||||
super.didChangeDependencies();
|
||||
SortState state = SortStateScope.of(context);
|
||||
_count.text = state.config.count.toString();
|
||||
_duration.text = state.config.duration.inMicroseconds.toString();
|
||||
_seed.text = state.config.seed.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
leading: BackButton(),
|
||||
titleTextStyle: TextStyle(
|
||||
color: Colors.black,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
centerTitle: true,
|
||||
title: Text('排序算法配置'),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text('数据数量(个数):'),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _count,
|
||||
)),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text('时间间隔(微秒):'),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _duration,
|
||||
)),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text('随机种子:'),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _seed,
|
||||
)),
|
||||
],
|
||||
),
|
||||
Spacer(),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
SortState state = SortStateScope.of(context);
|
||||
state.config =state.config.copyWith(
|
||||
count: int.parse(_count.text),
|
||||
duration: Duration(
|
||||
microseconds: int.parse(_duration.text),
|
||||
),
|
||||
seed: int.parse(_seed.text)
|
||||
);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text('确定设置'))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user