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

@@ -0,0 +1,29 @@
import 'package:flutter/material.dart';
import '../../functions.dart';
import '../../provider/state.dart';
class CodePage extends StatelessWidget {
const CodePage({super.key});
@override
Widget build(BuildContext context) {
SortState state = SortStateScope.of(context);
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
leading: BackButton(),
titleTextStyle: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.bold,
),
centerTitle: true,
title: Text(sortNameMap[state.config.name]!+'代码实现'),
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text('代码'*1000),
));
}
}

View File

@@ -0,0 +1,62 @@
import 'package:flutter/material.dart';
class DataPainter extends CustomPainter{
final List<int> data;
final MaterialColor color;
DataPainter( {required this.data,required this.color,});
@override
void paint(Canvas canvas, Size size) {
double itemWidth = size.width/data.length;
double height = size.height;
Paint paint = Paint();
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 = color.shade50;
} else if (value < 1000 * .20) {
paint.color = color.shade100;
} else if (value < 1000 * .30) {
paint.color = color.shade200;
} else if (value < 1000 * .40) {
paint.color = color.shade300;
} else if (value < 1000 * .50) {
paint.color = color.shade400;
} else if (value < 1000 * .60) {
paint.color = color.shade500;
} else if (value < 1000 * .70) {
paint.color = color.shade600;
} else if (value < 1000 * .80) {
paint.color = color.shade700;
} else if (value < 1000 * .90) {
paint.color = color.shade800;
} else {
paint.color = color.shade900;
}
canvas.drawLine(
Offset(i * itemWidth+itemWidth/2, 0),
Offset(
i * itemWidth+itemWidth/2,
size.height*(value/1000),
),
paint);
}
}
@override
bool shouldRepaint(covariant DataPainter oldDelegate) {
return true;
}
}

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

@@ -0,0 +1,57 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../provider/state.dart';
class SortButton extends StatelessWidget {
const SortButton({super.key});
@override
Widget build(BuildContext context) {
SortState state = SortStateScope.of(context);
VoidCallback? action;
IconData icon;
String text = '';
Color color;
switch (state.status) {
case SortStatus.none:
icon = Icons.not_started_outlined;
color = Colors.green;
action = state.sort;
text = '点击启动';
break;
case SortStatus.sorting:
icon = Icons.stop_circle_outlined;
color = Colors.grey;
action = null;
text = '排序中...';
break;
case SortStatus.sorted:
icon = CupertinoIcons.repeat;
color = Colors.black;
action = state.reset;
text = '点击重置';
break;
}
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: action,
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Icon(
icon,
color: color,
size: 18,
),
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),
),
),
),
),
);
}
}