Skip to content
This repository was archived by the owner on Nov 18, 2025. It is now read-only.

Commit a28ca22

Browse files
committed
Path
1 parent 3038f12 commit a28ca22

File tree

5 files changed

+178
-49
lines changed

5 files changed

+178
-49
lines changed

rema_1001/lib/map/cubit/map_cubit.dart

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class MapCubit extends Cubit<MapState> {
6565
width: a.width.toDouble(),
6666
height: a.height.toDouble(),
6767
status: status,
68+
id: a.id,
6869
);
6970
}).toList(),
7071
);
@@ -77,48 +78,83 @@ class MapCubit extends Cubit<MapState> {
7778
end: store.exit,
7879
);
7980

81+
// reorder aisleGroups based on path
82+
final orderedAisleGroups = path
83+
.where((w) => w.targetAisleIndex != null)
84+
.map(
85+
(waypoint) => aisleGroups.firstWhereOrNull(
86+
(group) => group.aisleId == aisles[waypoint.targetAisleIndex!].id,
87+
),
88+
)
89+
.whereType<ShoppingListAisleGroup>()
90+
.toList();
91+
92+
final targetAisleIdx = map.aisles.indexWhere(
93+
(aisle) => aisle.id == orderedAisleGroups.first.aisleId,
94+
);
95+
96+
final targetWaypointIdx = path.indexWhere(
97+
(w) => w.targetAisleIndex == targetAisleIdx,
98+
);
99+
80100
emit(
81101
MapPathfindingLoaded(
82102
map: map,
83103
path: path,
84104
currentStep: 0,
85-
aisleGroups: aisleGroups,
105+
aisleGroups: orderedAisleGroups,
106+
currentWaypointIndex: targetWaypointIdx,
86107
),
87108
);
88109
}
89110

90111
void next() {
91-
// emit(
92-
// MapLoaded(
93-
// map: MapModel(
94-
// walkPoints: [],
95-
// aisles: [
96-
// // Right tall vertical rectangle
97-
// Aisle(topLeft: Offset(46, 17), width: 4, height: 18),
98-
99-
// // Lower-middle left rectangle
100-
// Aisle(topLeft: Offset(10, 27), width: 18, height: 7),
101-
102-
// // Lower-middle center rectangle
103-
// Aisle(
104-
// topLeft: Offset(31, 27),
105-
// width: 12,
106-
// height: 7,
107-
// status: AisleStatus.white,
108-
// ),
109-
// ],
110-
// ),
111-
// path: [],
112-
// currentStep: 0,
113-
// ),
114-
// );
115-
}
112+
final s = state;
113+
if (s is! MapPathfindingLoaded) return;
114+
115+
final nextStep = s.currentStep + 1;
116+
if (nextStep >= s.aisleGroups.length) return;
117+
118+
// Get the current aisle group
119+
final currentAisleGroup = s.aisleGroups[nextStep];
120+
121+
final targetAisleIdx = s.map.aisles.indexWhere(
122+
(aisle) => aisle.id == currentAisleGroup.aisleId,
123+
);
124+
125+
final targetWaypointIdx = s.path.indexWhere(
126+
(w) => w.targetAisleIndex == targetAisleIdx,
127+
);
128+
129+
// Set the status of the aisles in the current aisle group to blinking
130+
final updatedAisles = s.map.aisles.mapIndexed((idx, aisle) {
131+
if (idx == targetAisleIdx) {
132+
return aisle.copyWith(status: AisleStatus.blinking);
133+
}
134+
if (aisle.status == AisleStatus.blinking) {
135+
return aisle.copyWith(status: AisleStatus.grey);
136+
}
137+
return aisle;
138+
});
139+
140+
final updatedMap = MapModel(aisles: updatedAisles.toList());
141+
142+
emit(
143+
MapPathfindingLoaded(
144+
map: updatedMap,
145+
aisleGroups: s.aisleGroups,
146+
currentStep: nextStep,
147+
path: s.path,
148+
currentWaypointIndex: targetWaypointIdx,
149+
),
150+
);
116151

117-
void checkItem() {}
152+
void checkItem() {}
118153

119-
@override
120-
void onChange(Change<MapState> change) {
121-
last = change.currentState;
122-
super.onChange(change);
154+
@override
155+
void onChange(Change<MapState> change) {
156+
last = change.currentState;
157+
super.onChange(change);
158+
}
123159
}
124160
}

rema_1001/lib/map/cubit/map_state.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,16 @@ final class ShoppingListAisleItem extends Equatable {
7777

7878
final class MapPathfindingLoaded extends MapLoaded {
7979
final List<Waypoint> path;
80+
final int currentWaypointIndex;
8081

8182
const MapPathfindingLoaded({
8283
required super.map,
84+
required this.currentWaypointIndex,
8385
required this.path,
8486
required super.currentStep,
8587
required super.aisleGroups,
8688
});
8789

8890
@override
89-
List<Object?> get props => [...super.props, path, currentStep];
91+
List<Object?> get props => [...super.props, path, currentWaypointIndex];
9092
}

rema_1001/lib/map/map.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class _MapWidgetState extends State<MapWidget> with TickerProviderStateMixin {
8888
Widget build(BuildContext context) {
8989
return BlocConsumer<MapCubit, MapState>(
9090
listener: (BuildContext context, MapState state) {
91+
print(state.runtimeType);
9192
if (state is MapLoaded && context.read<MapCubit>().last is MapInitial) {
9293
// Entrance animation
9394
_entranceAnimationController.forward(from: 0);
@@ -114,6 +115,9 @@ class _MapWidgetState extends State<MapWidget> with TickerProviderStateMixin {
114115
aspectRatio: 1,
115116
child: CustomPaint(
116117
painter: MapPainter(
118+
currentPathStep: state is MapPathfindingLoaded
119+
? state.currentWaypointIndex
120+
: 0,
117121
path: state is MapPathfindingLoaded ? state.path : null,
118122
map: MapModel(
119123
aisles: state.map.aisles.mapIndexed((idx, aisle) {

rema_1001/lib/map/map_painter.dart

Lines changed: 99 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:math' as math;
12
import 'package:flutter/widgets.dart';
23
import 'package:rema_1001/map/model.dart' as map_model;
34
import 'package:rema_1001/map/pathfinding/pathfinding_aisle.dart';
@@ -20,8 +21,9 @@ Offset getSoftShadowOffset(double scaleX, double scaleY) {
2021
final class MapPainter implements CustomPainter {
2122
final map_model.MapModel map;
2223
final List<Waypoint>? path;
24+
final int currentPathStep;
2325

24-
MapPainter({required this.map, required this.path});
26+
MapPainter({required this.map, required this.path, this.currentPathStep = 0});
2527

2628
@override
2729
void paint(Canvas canvas, Size size) {
@@ -57,33 +59,113 @@ final class MapPainter implements CustomPainter {
5759
}
5860

5961
void _paintPath(Canvas canvas, Size size, List<Waypoint> path) {
60-
// Paint a dot for each point in the path (in red)
61-
final paint = Paint()..color = const Color(0xFFFF0000);
6262
final scaleX = size.width / dimension;
6363
final scaleY = size.height / dimension;
6464

65-
final drawPath = Path();
66-
drawPath.moveTo(path[0].position.dx * scaleX, path[0].position.dy * scaleY);
65+
// Create the full path
66+
final fullPath = Path();
67+
fullPath.moveTo(path[0].position.dx * scaleX, path[0].position.dy * scaleY);
6768

68-
for (final waypoint in path) {
69-
final position = Offset(
70-
waypoint.position.dx * scaleX,
71-
waypoint.position.dy * scaleY,
69+
for (int i = 1; i < path.length; i++) {
70+
fullPath.lineTo(
71+
path[i].position.dx * scaleX,
72+
path[i].position.dy * scaleY,
7273
);
73-
drawPath.lineTo(
74-
waypoint.position.dx * scaleX,
75-
waypoint.position.dy * scaleY,
74+
}
75+
76+
// Paint the full path in gray
77+
final grayPathPaint = Paint()
78+
..color = const Color(0xFF5A5A5A)
79+
..style = PaintingStyle.stroke
80+
..strokeWidth = 5
81+
..strokeCap = StrokeCap.round
82+
..strokeJoin = StrokeJoin.round;
83+
84+
canvas.drawPath(fullPath, grayPathPaint);
85+
86+
// Paint the active path (up to current step) in white
87+
if (currentPathStep > 0 && currentPathStep < path.length) {
88+
final activePath = Path();
89+
activePath.moveTo(
90+
path[0].position.dx * scaleX,
91+
path[0].position.dy * scaleY,
7692
);
77-
canvas.drawCircle(position, 4, paint);
93+
94+
for (int i = 1; i <= currentPathStep && i < path.length; i++) {
95+
activePath.lineTo(
96+
path[i].position.dx * scaleX,
97+
path[i].position.dy * scaleY,
98+
);
99+
}
100+
101+
final whitePathPaint = Paint()
102+
..color = const Color(0xFFFFFFFF)
103+
..style = PaintingStyle.stroke
104+
..strokeWidth = 5
105+
..strokeCap = StrokeCap.round
106+
..strokeJoin = StrokeJoin.round;
107+
108+
canvas.drawPath(activePath, whitePathPaint);
78109
}
79110

80-
final pathPaint = Paint()
81-
..color = const Color(0x88FF0000)
111+
// Draw a dot at the current position
112+
if (currentPathStep >= 0 && currentPathStep < path.length) {
113+
final currentPosition = Offset(
114+
path[currentPathStep].position.dx * scaleX,
115+
path[currentPathStep].position.dy * scaleY,
116+
);
117+
118+
final dotPaint = Paint()..color = const Color(0xFFFFFFFF);
119+
canvas.drawCircle(currentPosition, 6, dotPaint);
120+
}
121+
122+
// Draw arrow at the end of the path
123+
_paintArrow(canvas, size, path);
124+
}
125+
126+
void _paintArrow(Canvas canvas, Size size, List<Waypoint> path) {
127+
if (path.length < 2) return;
128+
129+
final scaleX = size.width / dimension;
130+
final scaleY = size.height / dimension;
131+
132+
// Get the last two points to determine arrow direction
133+
final lastPoint = Offset(
134+
path[path.length - 1].position.dx * scaleX,
135+
path[path.length - 1].position.dy * scaleY,
136+
);
137+
final secondLastPoint = Offset(
138+
path[path.length - 2].position.dx * scaleX,
139+
path[path.length - 2].position.dy * scaleY,
140+
);
141+
142+
// Calculate direction vector
143+
final direction = lastPoint - secondLastPoint;
144+
final angle = direction.direction;
145+
146+
// Arrow dimensions
147+
final arrowLength = 12.0;
148+
149+
// Create arrow path
150+
final arrowPath = Path();
151+
arrowPath.moveTo(lastPoint.dx, lastPoint.dy);
152+
arrowPath.lineTo(
153+
lastPoint.dx - arrowLength * math.cos(angle - math.pi / 6),
154+
lastPoint.dy - arrowLength * math.sin(angle - math.pi / 6),
155+
);
156+
arrowPath.moveTo(lastPoint.dx, lastPoint.dy);
157+
arrowPath.lineTo(
158+
lastPoint.dx - arrowLength * math.cos(angle + math.pi / 6),
159+
lastPoint.dy - arrowLength * math.sin(angle + math.pi / 6),
160+
);
161+
162+
final arrowPaint = Paint()
163+
..color = const Color(0xFF5A5A5A)
82164
..style = PaintingStyle.stroke
83-
..strokeWidth = 4
165+
..strokeWidth = 3
84166
..strokeCap = StrokeCap.round;
85167

86-
canvas.drawPath(drawPath, pathPaint);
168+
canvas.drawPath(arrowPath, arrowPaint);
87169
}
88170

89171
void _paintIsle(Canvas canvas, Size size, map_model.Aisle aisle) {

rema_1001/lib/map/model.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ final class Aisle extends Equatable {
1919
final double height;
2020
final AisleStatus status;
2121
final double hardShadowHeight;
22+
final String id;
2223

2324
late final Paint paint;
2425
late final Paint hardShadowPaint;
2526
late final Paint softShadowPaint;
2627
late final Paint glowPaint;
2728

2829
Aisle({
30+
required this.id,
2931
required this.topLeft,
3032
required this.width,
3133
required this.height,
@@ -51,6 +53,7 @@ final class Aisle extends Equatable {
5153
required this.softShadowPaint,
5254
required this.glowPaint,
5355
required this.hardShadowHeight,
56+
required this.id,
5457
});
5558

5659
Aisle copyWith({
@@ -74,6 +77,7 @@ final class Aisle extends Equatable {
7477
softShadowPaint: softShadowPaint ?? this.softShadowPaint,
7578
glowPaint: glowPaint ?? this.glowPaint,
7679
hardShadowHeight: hardShadowHeight ?? this.hardShadowHeight,
80+
id: id,
7781
);
7882
}
7983

@@ -87,5 +91,6 @@ final class Aisle extends Equatable {
8791
paint,
8892
softShadowPaint,
8993
glowPaint,
94+
id,
9095
];
9196
}

0 commit comments

Comments
 (0)