This commit is contained in:
toly
2023-11-08 09:35:29 +08:00
parent 88cd6fb3b4
commit 8fb4bf57d6
78 changed files with 4344 additions and 544 deletions

View File

@@ -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,
);
}

View File

@@ -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;

View File

@@ -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),

View 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()),
),
);
}
}

View 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(),
);
}
}

View 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('确定设置'))
],
),
),
);
}
}

View File

@@ -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))
],
);
}
}

View File

@@ -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
),
),
),
),
),
);
}
}

View File

@@ -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),),
],
),
),

View 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),
),
),
),
),
);
}
}

View File

@@ -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('确定设置'))
],
),
),
);
}
}