Skip to content

Commit a6bcc16

Browse files
author
Vivek Chib
committed
reorderable animated_boxes.dart
1 parent 5ad448f commit a6bcc16

File tree

6 files changed

+140
-43
lines changed

6 files changed

+140
-43
lines changed

lib/main.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,19 @@ import 'package:provider/provider.dart';
66
import 'package:shared_preferences/shared_preferences.dart';
77
import 'utils/theme/theme_provider.dart';
88
import 'views/home_page.dart';
9+
import 'views/widgets/animated_box/provider.dart';
910

1011
Future<void> main() async {
1112
WidgetsFlutterBinding.ensureInitialized();
1213

1314
final pref = await SharedPreferences.getInstance();
1415

1516
runApp(
16-
ChangeNotifierProvider(
17-
create: (context) => ThemeProvider(pref: pref),
17+
MultiProvider(
18+
providers: [
19+
ChangeNotifierProvider(create: (context) => ThemeProvider(pref: pref)),
20+
ChangeNotifierProvider(create: (context) => AnimatedBoxesProvider(pref: pref)),
21+
],
1822
child: const MyApp(),
1923
),
2024
);

lib/views/home_page.dart

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_animate/flutter_animate.dart';
33
import 'package:flutter_curve_visualizer/model/curve_model.dart';
4+
import 'package:flutter_curve_visualizer/views/widgets/animated_box/animated_box_widget.dart';
45
import 'package:flutter_curve_visualizer/views/widgets/screen_mode.dart';
56
import 'package:flutter_curve_visualizer/utils/curves_enum.dart';
67
import 'package:flutter_curve_visualizer/views/widgets/appbar.dart';
78
import 'package:flutter_curve_visualizer/views/widgets/dropdown_menu.dart';
89
import 'package:flutter_curve_visualizer/views/widgets/graph/graph_widget.dart';
10+
import 'package:provider/provider.dart';
911
import 'widgets/animated_box/animated_boxes.dart';
12+
import 'widgets/animated_box/provider.dart';
1013
import 'widgets/code_block.dart';
1114
import 'widgets/cubic_curve_input_widget.dart';
1215

@@ -152,7 +155,26 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
152155
),
153156

154157
// Box Animations
155-
AnimationBoxes(curveAnimation: curveAnimation),
158+
Consumer<AnimatedBoxesProvider>(
159+
builder: (context, value, child) {
160+
final list = value.animationBoxReordableList;
161+
162+
return AnimationBoxes(
163+
curveAnimation: curveAnimation,
164+
animationTypes: list,
165+
onAcceptWithDetails: (details, item) {
166+
final oldIndex = list.indexOf(details.data);
167+
final newIndex = list.indexOf(item);
168+
169+
if (oldIndex != -1 && newIndex != -1) {
170+
list.removeAt(oldIndex);
171+
list.insert(newIndex, details.data);
172+
value.saveList(list);
173+
}
174+
},
175+
);
176+
},
177+
),
156178
SizedBox(height: spacing * 2),
157179
],
158180
);

lib/views/widgets/animated_box/animated_boxes.dart

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,82 @@
11
import 'package:flutter/material.dart';
2+
import 'package:flutter_animate/flutter_animate.dart';
23
import 'package:flutter_curve_visualizer/utils/extension/string.dart';
34
import 'package:flutter_curve_visualizer/views/widgets/screen_mode.dart';
4-
55
import 'animated_box_widget.dart';
66

77
class AnimationBoxes extends StatelessWidget {
8-
const AnimationBoxes({super.key, required this.curveAnimation});
8+
const AnimationBoxes({
9+
super.key,
10+
required this.curveAnimation,
11+
required this.animationTypes,
12+
required this.onAcceptWithDetails,
13+
});
914

15+
final List<int> animationTypes;
1016
final CurvedAnimation curveAnimation;
17+
final void Function(DragTargetDetails<int> details, int newIndex)?
18+
onAcceptWithDetails;
1119

1220
@override
1321
Widget build(BuildContext context) {
1422
final screenMode = ScreenModeWidget.of(context);
1523

1624
final spacing = screenMode.spacing;
1725

26+
const boxSize = 100.0;
27+
1828
return SizedBox(
1929
width: MediaQuery.of(context).size.width /
2030
(screenMode.isMobileOrTablet ? 1 : 2),
2131
child: Wrap(
32+
key: ValueKey(animationTypes),
2233
spacing: spacing / 2,
2334
runSpacing: spacing / 2,
2435
runAlignment: WrapAlignment.center,
2536
alignment: WrapAlignment.center,
26-
children: AnimationType.values.map(
27-
(animationType) {
28-
return Column(
29-
mainAxisAlignment: MainAxisAlignment.start,
30-
spacing: 8.0,
31-
children: [
32-
Text(animationType.name.capitalizeFirst()),
33-
SizedBox.square(
34-
dimension: 100,
35-
child: AnimatedBoxWidget(
36-
animationType: animationType,
37-
animation: curveAnimation,
37+
children: animationTypes.map(
38+
(index) {
39+
return DragTarget<int>(
40+
onWillAcceptWithDetails: (_) => true,
41+
onAcceptWithDetails: (details) =>
42+
onAcceptWithDetails?.call(details, index),
43+
builder: (_, __, ___) {
44+
final child = Column(
45+
mainAxisAlignment: MainAxisAlignment.start,
46+
spacing: 8.0,
47+
children: [
48+
Text(AnimationType.values[index].name.capitalizeFirst()),
49+
SizedBox.square(
50+
dimension: boxSize,
51+
child: AnimatedBoxWidget(
52+
animationType: AnimationType.values[index],
53+
animation: curveAnimation,
54+
),
55+
),
56+
],
57+
);
58+
59+
return MouseRegion(
60+
cursor: SystemMouseCursors.grab,
61+
child: Draggable(
62+
data: index,
63+
childWhenDragging: Column(
64+
children: [
65+
Text(""),
66+
SizedBox.square(dimension: boxSize),
67+
],
68+
),
69+
feedback: AnimatedScale(
70+
scale: 1.150,
71+
duration: 200.ms,
72+
child: Material(
73+
child: child,
74+
),
75+
),
76+
child: child,
3877
),
39-
),
40-
],
78+
);
79+
},
4180
);
4281
},
4382
).toList(),
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:shared_preferences/shared_preferences.dart';
3+
4+
import 'animated_box_widget.dart';
5+
6+
const key = 'animationBoxReordableList';
7+
8+
class AnimatedBoxesProvider extends ChangeNotifier {
9+
final SharedPreferences pref;
10+
11+
AnimatedBoxesProvider({required this.pref}) {
12+
getList();
13+
}
14+
15+
late List<int> animationBoxReordableList;
16+
17+
void getList() {
18+
final list = pref.getStringList(key);
19+
20+
if (list != null && list.isNotEmpty) {
21+
animationBoxReordableList = list.map((e) => int.parse(e)).toList();
22+
} else {
23+
animationBoxReordableList =
24+
List.generate(AnimationType.values.length, (index) => index);
25+
}
26+
27+
notifyListeners();
28+
}
29+
30+
void saveList(List<int> list) {
31+
pref.setStringList(key, list.map((e) => e.toString()).toList());
32+
animationBoxReordableList = list;
33+
notifyListeners();
34+
}
35+
}

lib/views/widgets/code_block.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ class CodeBlock extends StatelessWidget {
1212

1313
if (!context.mounted) return;
1414

15-
ScaffoldMessenger.of(context).showSnackBar(
16-
const SnackBar(content: Text('Copied to clipboard')),
17-
);
15+
ScaffoldMessenger.of(context)
16+
..clearSnackBars()
17+
..showSnackBar(
18+
const SnackBar(content: Text('Copied to clipboard')),
19+
);
1820
}
1921

2022
@override

lib/views/widgets/cubic_graph.dart

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import 'package:flutter/material.dart';
22

3+
import 'screen_mode.dart';
4+
35
class CubicGraph extends StatefulWidget {
46
const CubicGraph({super.key});
57

@@ -13,18 +15,6 @@ class _CubicGraphState extends State<CubicGraph> {
1315
bool isDraggingX2 = false;
1416
bool isDraggingY2 = false;
1517

16-
// Size of the actual graph area
17-
static const graphSize = Size(350, 300);
18-
19-
// Size of the draggable area
20-
static const containerSize = Size(500, 500);
21-
22-
// Offset to center the graph in the container
23-
static final graphOffset = Offset(
24-
(containerSize.width - graphSize.width) / 2,
25-
(containerSize.height - graphSize.height) / 2,
26-
);
27-
2818
void _updatePosition(Offset position) {
2919
setState(() {
3020
if (isDraggingX2) {
@@ -37,20 +27,25 @@ class _CubicGraphState extends State<CubicGraph> {
3727

3828
@override
3929
Widget build(BuildContext context) {
30+
final screenSize = MediaQuery.sizeOf(context);
31+
32+
// Size of the actual graph area
33+
final graphSize = Size(350, 300);
34+
35+
// Size of the draggable area
36+
final containerSize = Size(screenSize.width, screenSize.height);
37+
38+
// Offset to center the graph in the container
39+
final graphOffset = Offset(
40+
(containerSize.width - graphSize.width) / 2,
41+
(containerSize.height - graphSize.height) / 2,
42+
);
43+
4044
return MouseRegion(
4145
cursor: isDraggingX2 || isDraggingY2
4246
? SystemMouseCursors.grabbing
4347
: SystemMouseCursors.basic,
4448
child: GestureDetector(
45-
onTapDown: (details) {
46-
final pos = details.localPosition;
47-
if ((pos - (x2Position + graphOffset)).distance < 20) {
48-
setState(() => isDraggingX2 = true);
49-
} else if ((pos - (y2Position + graphOffset)).distance < 20) {
50-
setState(() => isDraggingY2 = true);
51-
}
52-
_updatePosition(details.localPosition - graphOffset);
53-
},
5449
onPanStart: (details) {
5550
final pos = details.localPosition;
5651
if ((pos - (x2Position + graphOffset)).distance < 20) {

0 commit comments

Comments
 (0)