diff --git a/packages/cave/lib/widgets/text_field.dart b/packages/cave/lib/widgets/text_field.dart index e004671..dc80922 100644 --- a/packages/cave/lib/widgets/text_field.dart +++ b/packages/cave/lib/widgets/text_field.dart @@ -98,6 +98,8 @@ class DevfestTextFormField extends StatelessWidget { if (title != null) ...[ Text( title!, + maxLines: 1, + overflow: TextOverflow.ellipsis, style: DevfestTheme.of(context).textTheme?.bodyBody3Medium, ), Constants.smallVerticalGutter.verticalSpace, diff --git a/packages/conferenceapp/lib/src/features/more/presentation/map/grid.dart b/packages/conferenceapp/lib/src/features/more/presentation/map/grid.dart deleted file mode 100644 index 72dd7b3..0000000 --- a/packages/conferenceapp/lib/src/features/more/presentation/map/grid.dart +++ /dev/null @@ -1,524 +0,0 @@ -import 'dart:core'; -import 'dart:math'; -import 'dart:ui'; - -import 'package:cave/cave.dart'; -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart' hide Action; - -import '../widgets/map.dart'; -import 'map.dart'; - -class GridCell extends Equatable implements Comparable { - final int row; - final int column; - - const GridCell({required this.row, required this.column}); - - GridCell get left => GridCell(row: row, column: column - 1); - - GridCell get right => GridCell(row: row, column: column + 1); - - GridCell get above => GridCell(row: row - 1, column: column); - - GridCell get below => GridCell(row: row + 1, column: column); - - @override - int compareTo(GridCell other) { - return row.compareTo(other.row) + column.compareTo(other.column); - } - - @override - List get props => [row, column]; -} - -class GridPainter extends CustomPainter { - GridPainter({ - required this.grid, - required this.cellSize, - required this.progress, - this.cellTrackRange, - this.actions = const [], - this.showGrid = false, - this.showPath = false, - this.showBlocks = false, - this.onWalkerPosition, - }); - - final Grid grid; - final double cellSize; - final double progress; - final GridCellRange? cellTrackRange; - final List actions; - final bool showGrid; - final bool showPath; - final bool showBlocks; - final void Function(Offset walkerPostion, double angle)? onWalkerPosition; - - @override - void paint(Canvas canvas, Size size) { - final path = _paintRobotPath(canvas, size, grid); - - if (showGrid) _paintGrid(canvas, size); - if (showBlocks) _paintBlocks(canvas, size); - if (showPath) { - _paintProgressPath(path, canvas, const HSLColor.fromAHSL(1, 30, 1, 0.5)); - } - _paintWalker(path, canvas); - } - - Path _paintRobotPath(Canvas canvas, Size size, Grid grid) { - Path progressPath = Path(); - - if (cellTrackRange != null) { - final firstYOrigin = - (size.height / grid.rows * cellTrackRange!.start.row).floorToDouble(); - final firstXOrigin = - (size.width / grid.columns * cellTrackRange!.start.column) - .floorToDouble(); - for (int i = 0; i < actions.length; i++) { - final action = actions[i]; - - if (i == 0 && action == Action.doNothing) { - progressPath.moveTo( - firstXOrigin + cellSize / 2, firstYOrigin + cellSize / 2); - continue; - } - - switch (action) { - case Action.moveRight: - progressPath.relativeLineTo(cellSize, 0); - case Action.moveLeft: - progressPath.relativeLineTo(-cellSize, 0); - case Action.moveUp: - progressPath.relativeLineTo(0, -cellSize); - case Action.moveDown: - progressPath.relativeLineTo(0, cellSize); - case Action.doNothing: - } - } - } - - return progressPath; - } - - // for debugging purposes - // ignore: unused_element - void _paintProgressPath(Path path, Canvas canvas, HSLColor hue) { - canvas.drawPath( - path, - Paint() - ..color = hue.toColor() - ..style = PaintingStyle.stroke - ..strokeCap = StrokeCap.round - ..strokeJoin = StrokeJoin.round - ..strokeWidth = cellSize, - ); - } - - void _paintWalker(Path path, Canvas canvas) { - final pathMetrics = path.computeMetrics(); - - for (final pathMetric in pathMetrics) { - try { - final extractPath = pathMetric.extractPath( - 0, pathMetric.length * progress, - startWithMoveTo: false); - - final tangent = _computeTangentForPath(extractPath); - final offset = tangent.position; - - canvas.save(); - canvas.translate(offset.dx, offset.dy); - - double rotationAngle = tangent.angle.abs() - pi / 2; - - final isOnXAxis = rotationAngle == pi / 2 || rotationAngle == -pi / 2; - - if (isOnXAxis) { - rotationAngle = rotationAngle - pi; - } else { - // if the tangent angle is -90, then the rotation angle should be 180 - if (_getDegFromRad(tangent.angle) == -90) { - rotationAngle = pi; - } - } - - onWalkerPosition?.call(offset, rotationAngle); - canvas.rotate(rotationAngle); - - _walker(canvas, Size(cellSize * 1.5, cellSize * 1.5)); - if (!isOnXAxis) { - canvas.translate(0, cellSize / 2); - } - - Matrix4 matrix4 = Matrix4.identity(); - matrix4.scale(-1.0, 1.0); - canvas.transform(matrix4.storage); - _walker(canvas, Size(cellSize * 1.5, cellSize * 1.5)); - - canvas.restore(); - // canvas.drawOval( - // Rect.fromCircle(center: offset, radius: cellSize * 1.5), - // Paint() - // ..style = PaintingStyle.fill - // ..color = Colors.orange); - } catch (_) {} - } - } - - void _walker(Canvas canvas, Size size) { - Path path_0 = Path(); - path_0.moveTo(size.width * 0.3759985, size.height * 0.4896138); - path_0.cubicTo( - size.width * 0.4655944, - size.height * 0.5371670, - size.width * 0.5076371, - size.height * 0.6434983, - size.width * 0.4776357, - size.height * 0.7412578); - path_0.cubicTo( - size.width * 0.4721253, - size.height * 0.7588096, - size.width * 0.4672271, - size.height * 0.7769737, - size.width * 0.4633494, - size.height * 0.7951377); - path_0.cubicTo( - size.width * 0.4474303, - size.height * 0.8767741, - size.width * 0.4688598, - size.height * 0.9792276, - size.width * 0.5586598, - size.height * 0.9973917); - path_0.cubicTo( - size.width * 0.6039679, - size.height * 1.006984, - size.width * 0.6490720, - size.height * 0.9894322, - size.width * 0.6809102, - size.height * 0.9561654); - path_0.cubicTo( - size.width * 0.7758124, - size.height * 0.8530995, - size.width * 0.7468315, - size.height * 0.5426774, - size.width * 0.7460151, - size.height * 0.4649188); - path_0.cubicTo( - size.width * 0.7460151, - size.height * 0.4308357, - size.width * 0.7451988, - size.height * 0.3959361, - size.width * 0.7317288, - size.height * 0.3640980); - path_0.cubicTo( - size.width * 0.7015233, - size.height * 0.2926662, - size.width * 0.6166216, - size.height * 0.2640935, - size.width * 0.5413121, - size.height * 0.2442967); - path_0.cubicTo( - size.width * 0.4176330, - size.height * 0.1991926, - size.width * 0.3396704, - size.height * 0.2561339, - size.width * 0.3135467, - size.height * 0.2981767); - path_0.cubicTo( - size.width * 0.2874231, - size.height * 0.3402194, - size.width * 0.2684427, - size.height * 0.4336929, - size.width * 0.3759985, - size.height * 0.4896138); - path_0.close(); - - Paint paint0Fill = Paint()..style = PaintingStyle.fill; - paint0Fill.color = DevfestColors.primariesBlue70.withOpacity(1.0); - canvas.drawPath(path_0, paint0Fill); - - Paint paint1Fill = Paint()..style = PaintingStyle.fill; - paint1Fill.color = DevfestColors.primariesBlue70.withOpacity(1.0); - canvas.drawOval( - Rect.fromCenter( - center: Offset(size.width * 0.2894640, size.height * 0.09041222), - width: size.width * 0.1285772, - height: size.height * 0.1808244), - paint1Fill); - - Paint paint2Fill = Paint()..style = PaintingStyle.fill; - paint2Fill.color = DevfestColors.primariesBlue70.withOpacity(1.0); - canvas.drawOval( - Rect.fromCenter( - center: Offset(size.width * 0.4380421, size.height * 0.1055149), - width: size.width * 0.07632996, - height: size.height * 0.1077599), - paint2Fill); - - Paint paint3Fill = Paint()..style = PaintingStyle.fill; - paint3Fill.color = DevfestColors.primariesBlue70.withOpacity(1.0); - canvas.drawOval( - Rect.fromCenter( - center: Offset(size.width * 0.5570271, size.height * 0.1387817), - width: size.width * 0.06816633, - height: size.height * 0.09510631), - paint3Fill); - - Paint paint4Fill = Paint()..style = PaintingStyle.fill; - paint4Fill.color = DevfestColors.primariesBlue70.withOpacity(1.0); - canvas.drawOval( - Rect.fromCenter( - center: Offset(size.width * 0.6656034, size.height * 0.1667422), - width: size.width * 0.06041088, - height: size.height * 0.08408541), - paint4Fill); - - Paint paint5Fill = Paint()..style = PaintingStyle.fill; - paint5Fill.color = DevfestColors.primariesBlue70.withOpacity(1.0); - canvas.drawOval( - Rect.fromCenter( - center: Offset(size.width * 0.7473805, size.height * 0.2229039), - width: size.width * 0.07469723, - height: size.height * 0.05387997), - paint5Fill); - } - - void _paintGrid(Canvas canvas, Size size) { - for (int i = 0; i < grid.rows; i++) { - for (int j = 0; j < grid.columns; j++) { - final yOrigin = 0 + (size.height ~/ grid.rows * i).toDouble(); - final xOrigin = 0 + (size.width ~/ grid.columns * j).toDouble(); - final center = cellSize / 2; - Path path = Path() - ..moveTo(xOrigin, yOrigin) - ..addRect( - Rect.fromCenter( - center: Offset(xOrigin + center, yOrigin + center), - width: cellSize, - height: cellSize, - ), - ); - canvas.drawPath( - path, - Paint() - ..color = Colors.black - ..style = PaintingStyle.stroke - ..strokeWidth = 0.5, - ); - } - } - } - - void _paintBlocks(Canvas canvas, Size size) { - for (int i = 0; i < grid.rows; i++) { - for (int j = 0; j < grid.columns; j++) { - final state = grid.grid[i][j]; - - if (state > 0) { - final yOrigin = 0 + (size.height ~/ grid.rows * i).toDouble(); - final xOrigin = 0 + (size.width ~/ grid.columns * j).toDouble(); - final center = cellSize / 2; - Path path = Path() - ..moveTo(xOrigin, yOrigin) - ..addRect( - Rect.fromCenter( - center: Offset(xOrigin + center, yOrigin + center), - width: cellSize, - height: cellSize, - ), - ); - - HSLColor hue = HSLColor.fromAHSL(1, state.toDouble(), 1, 0.5); - - canvas.drawPath( - path, - Paint() - ..color = hue.toColor() - ..style = PaintingStyle.fill, - ); - } - } - } - } - - Tangent _computeTangentForPath(Path path) { - final metric = path.computeMetrics().first; - return metric.getTangentForOffset(metric.length)!; - } - - @override - bool shouldRepaint(covariant CustomPainter oldDelegate) { - if (oldDelegate is! GridPainter) return false; - - if (oldDelegate.grid != grid) return true; - if (oldDelegate.cellSize != cellSize) return true; - if (oldDelegate.progress != progress) return true; - if (oldDelegate.cellTrackRange != cellTrackRange) return true; - if (oldDelegate.actions != actions) return true; - if (oldDelegate.showGrid != showGrid) return true; - if (oldDelegate.showPath != showPath) return true; - if (oldDelegate.showBlocks != showBlocks) return true; - return false; - } -} - -class Grid extends Equatable { - final List> grid; - - final T initialValue; - - const Grid._(this.grid, this.initialValue); - - factory Grid.make(int rows, int columns, T initialValue) { - return Grid._( - List.generate( - rows, - (index) => List.generate(columns, (index) => initialValue), - ), - initialValue, - ); - } - - ({int rows, int columns}) get size { - return (rows: rows, columns: columns); - } - - int get rows { - return grid.length; - } - - int get columns { - return grid.first.length; - } - - int filledCellsCount(bool Function(T state) filter) { - return filledCells(filter).length; - } - - List filledCells(bool Function(T state) filter) { - List cells = []; - for (int i = 0; i <= rows - 1; i++) { - for (int j = 0; j <= columns - 1; j++) { - final state = grid[i][j]; - - if (filter(state)) cells.add(GridCell(row: i, column: j)); - } - } - return cells; - } - - void resetCells(List cells) { - for (final cell in cells) { - grid[cell.row][cell.column] = initialValue; - } - } - - void fillCells(List cells, T state) { - for (final cell in cells) { - grid[cell.row][cell.column] = state; - } - } - - bool filter(GridCell cell, bool Function(T state) filter) { - return filter(grid[cell.row][cell.column]); - } - - bool filterCells(List cells, bool Function(T state) filter) { - for (final cell in cells) { - if (!filter(grid[cell.row][cell.column])) return false; - } - return true; - } - - GridCell? firstWhereOrNull(bool Function(T state) filter) { - for (int i = 0; i <= rows - 1; i++) { - for (int j = 0; j <= columns - 1; j++) { - final state = grid[i][j]; - - if (filter(state)) return GridCell(row: i, column: j); - } - } - return null; - } - - Map getNeighbourPositions(GridCell cell) { - final neighbours = {}; - - if (validPosition(cell.above)) { - neighbours['above'] = cell.above; - } else { - neighbours['above'] = null; - } - - if (validPosition(cell.below)) { - neighbours['below'] = cell.below; - } else { - neighbours['below'] = null; - } - - if (validPosition(cell.left)) { - neighbours['left'] = cell.left; - } else { - neighbours['left'] = null; - } - - if (validPosition(cell.right)) { - neighbours['right'] = cell.right; - } else { - neighbours['right'] = null; - } - - return neighbours; - } - - bool validPosition(GridCell cell) { - return cell.row >= 0 && - cell.row < rows && - cell.column >= 0 && - cell.column < columns; - } - - /// Due to the vector nature of the grid(2x2 matrix), to ensure the equality - /// works properly and to help dart infer that a new grid object is created - /// we use the grid factory to create a new instance and copy the grid values - /// to this new grid before returning the instance - Grid copyWith({List>? grid}) { - if (grid != null) { - Grid nextGrid = Grid.make(rows, columns, initialValue); - - for (int i = 0; i <= rows - 1; i++) { - for (int j = 0; j <= columns - 1; j++) { - nextGrid.grid[i][j] = grid[i][j]; - } - } - - return nextGrid; - } - - return Grid._(grid ?? this.grid, initialValue); - } - - @override - List get props => [grid]; -} - -//Copy this CustomPainter code to the Bottom of the File -class RPSCustomPainter extends CustomPainter { - @override - void paint(Canvas canvas, Size size) {} - - @override - bool shouldRepaint(covariant CustomPainter oldDelegate) { - return true; - } -} - -double _getDegFromRad(double radians) { - return radians * (180 / pi); -} - -double getRadFromDeg(double angle) { - return angle * (pi / 180); -} diff --git a/packages/conferenceapp/lib/src/features/more/presentation/map/map.dart b/packages/conferenceapp/lib/src/features/more/presentation/map/map.dart index a3178c5..6c5ee89 100644 --- a/packages/conferenceapp/lib/src/features/more/presentation/map/map.dart +++ b/packages/conferenceapp/lib/src/features/more/presentation/map/map.dart @@ -1,5 +1,5 @@ //GENERATED BARREL FILE export 'action.dart'; -export 'grid.dart'; -export 'map_utils.dart'; export 'robot.dart'; +export 'room.dart'; +export 'walker_grid_painter.dart'; diff --git a/packages/conferenceapp/lib/src/features/more/presentation/map/map_utils.dart b/packages/conferenceapp/lib/src/features/more/presentation/map/map_utils.dart deleted file mode 100644 index 5c8bca6..0000000 --- a/packages/conferenceapp/lib/src/features/more/presentation/map/map_utils.dart +++ /dev/null @@ -1,212 +0,0 @@ -import 'package:cave/cave.dart'; -import 'package:devfest24/src/features/more/presentation/widgets/map_layout.dart'; -import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; - -enum HideFenceBorder { - none, - top, - right, - bottom, - left, - all; -} - -final class Block extends Equatable { - final double width; - final double height; - final HideFenceBorder hideFenceBorder; - final String? entranceLabel; - final TextStyle? entranceLabelStyle; - final String blockLabel; - final TextStyle? blockLabelStyle; - final Color? blockColor; - final Offset? position; - final List openingPositions; - final List openingSizes; - - const Block({ - this.width = 100, - this.height = 100, - this.hideFenceBorder = HideFenceBorder.none, - this.entranceLabel, - this.entranceLabelStyle, - required this.blockLabel, - this.blockLabelStyle, - this.blockColor, - this.position, - this.openingPositions = const [], - this.openingSizes = const [], - }); - - factory Block.fromContext( - BuildContext context, { - double width = 100, - double height = 100, - HideFenceBorder hideFenceBorder = HideFenceBorder.none, - String? entranceLabel, - TextStyle? entranceLabelStyle, - required String blockLabel, - TextStyle? blockLabelStyle, - Color? blockColor, - Offset? position, - List openingPositions = const [], - List openingSizes = const [], - }) { - return Block( - entranceLabel: entranceLabel, - blockLabel: blockLabel, - blockColor: blockColor, - height: height, - width: width, - hideFenceBorder: hideFenceBorder, - entranceLabelStyle: DevfestTheme.of(context) - .textTheme - ?.bodyBody4Regular - ?.medium - .applyColor(DevfestColors.grey10) - .merge(entranceLabelStyle), - blockLabelStyle: DevfestTheme.of(context) - .textTheme - ?.bodyBody2Regular - ?.semi - .applyColor(DevfestColors.grey10) - .merge(blockLabelStyle), - position: position, - openingPositions: openingPositions, - openingSizes: openingSizes, - ); - } - - @override - List get props => [ - width, - height, - hideFenceBorder, - entranceLabel, - entranceLabelStyle, - blockLabel, - blockLabelStyle, - blockColor, - position, - openingPositions, - openingSizes, - ]; -} - -typedef BlockLayoutArea = ({ - RoomType room, - Offset start, - Offset end, - HideFenceBorder hideFenceBorder, - List<({Offset start, Offset end})> openings, -}); - -enum RoomType { - exhibitionRoom, - room1, - room2, - hallway, - toilet, - stairs, - room3, - room4; - - const RoomType(); - - List get directionInstructions => switch (this) { - RoomType.exhibitionRoom => [RoomType.room1], - RoomType.room1 => [RoomType.exhibitionRoom, RoomType.room2], - RoomType.room2 => [RoomType.room1, RoomType.hallway], - RoomType.hallway => [RoomType.room2, RoomType.toilet, RoomType.stairs], - RoomType.toilet => [RoomType.hallway], - RoomType.stairs => [RoomType.hallway, RoomType.room3, RoomType.room4], - RoomType.room3 => [RoomType.stairs], - RoomType.room4 => [RoomType.stairs], - }; - - @override - String toString() => switch (this) { - RoomType.exhibitionRoom => 'Exhibition Room', - RoomType.room1 => 'Room 1', - RoomType.room2 => 'Room 2', - RoomType.hallway => 'Hallway', - RoomType.toilet => 'Toilet', - RoomType.stairs => 'Stairs', - RoomType.room3 => 'Room 3', - RoomType.room4 => 'Room 4', - }; -} - -// DFS algorithm to get the directions from one room to another -List getOverviewDirections(RoomType start, RoomType end) { - final adj = {}; - - adj.add(_getNextDirection(start, end, {}, adj)); - - return adj.toList(); -} - -RoomType _getNextDirection( - RoomType next, RoomType end, Set visited, Set adj) { - if (next == end) return next; - - visited.add(next); - adj.add(next); - - final nextBlockDirections = next.directionInstructions.toList() - ..removeWhere((element) => element == next || visited.contains(element)); - - // backtrack - if (nextBlockDirections.isEmpty) { - adj.remove(next); - return _getNextDirection(adj.last, end, visited, adj); - } - - late RoomType nextDirection; - for (final direction in nextBlockDirections) { - if (direction == end) { - return direction; - } - - if (direction.directionInstructions.length == 1 && - direction.directionInstructions.first == next) { - nextDirection = direction; - continue; - } - - if (!visited.contains(direction)) { - return _getNextDirection(direction, end, visited, adj); - } - } - - return _getNextDirection(nextDirection, end, visited, adj); -} - -extension BlockLayouts on List { - BlockLayoutArea getRoomLayout(RoomType room) { - return firstWhere((layout) => layout.room == room); - } - - String printLayout() { - final buffer = StringBuffer(); - for (final layout in this) { - buffer.write('Room: ${layout.room}\t'); - buffer.write('Start: ${layout.start}\t'); - buffer.writeln('End: ${layout.end}'); - buffer.write( - 'Start GridCell(row: ${(layout.start.dy / cellSize).floor()}, column: ${(layout.start.dx / cellSize).floor()})\t', - ); - buffer.writeln( - 'End GridCell(row: ${(layout.end.dy / cellSize).floor()}, column: ${(layout.end.dx / cellSize).floor()})', - ); - } - return buffer.toString(); - } -} - -extension RoomListX on List { - String chainString() { - return map((room) => room.toString().split('.').last).join(' -> '); - } -} diff --git a/packages/conferenceapp/lib/src/features/more/presentation/map/path_finder.dart b/packages/conferenceapp/lib/src/features/more/presentation/map/path_finder.dart index a690f3a..4ebee98 100644 --- a/packages/conferenceapp/lib/src/features/more/presentation/map/path_finder.dart +++ b/packages/conferenceapp/lib/src/features/more/presentation/map/path_finder.dart @@ -2,9 +2,11 @@ import 'dart:async'; import 'dart:math'; import 'package:flutter/foundation.dart'; +import 'package:schematics/schematics.dart'; -import '../widgets/map.dart'; -import 'map.dart'; +import 'walker_grid_painter.dart'; +import 'action.dart'; +import 'robot.dart'; class _PathFinderRequest { final Completer> completer = Completer(); diff --git a/packages/conferenceapp/lib/src/features/more/presentation/map/robot.dart b/packages/conferenceapp/lib/src/features/more/presentation/map/robot.dart index 1849649..cf9240f 100644 --- a/packages/conferenceapp/lib/src/features/more/presentation/map/robot.dart +++ b/packages/conferenceapp/lib/src/features/more/presentation/map/robot.dart @@ -2,7 +2,7 @@ import 'dart:math'; -import 'package:devfest24/src/features/more/presentation/map/grid.dart'; +import 'package:schematics/schematics.dart'; import 'action.dart'; diff --git a/packages/conferenceapp/lib/src/features/more/presentation/map/room.dart b/packages/conferenceapp/lib/src/features/more/presentation/map/room.dart new file mode 100644 index 0000000..bd262c1 --- /dev/null +++ b/packages/conferenceapp/lib/src/features/more/presentation/map/room.dart @@ -0,0 +1,30 @@ +enum RoomType { + entranceHallway, + exhibitionRoom, + room1, + room2, + room3, + networkZone, + hallway, + restroom, + stairs, + room4, + greenRoom; + + const RoomType(); + + @override + String toString() => switch (this) { + RoomType.exhibitionRoom => 'Exhibition Room', + RoomType.room1 => 'Room 1', + RoomType.room2 => 'Room 2', + RoomType.hallway => 'Hallway', + RoomType.restroom => 'Restroom', + RoomType.stairs => 'Stairs', + RoomType.room3 => 'Room 3', + RoomType.room4 => 'Room 4', + RoomType.entranceHallway => 'Entrance Hallway', + RoomType.networkZone => 'Network Zone', + RoomType.greenRoom => 'Green Room', + }; +} diff --git a/packages/conferenceapp/lib/src/features/more/presentation/map/walker_grid_painter.dart b/packages/conferenceapp/lib/src/features/more/presentation/map/walker_grid_painter.dart new file mode 100644 index 0000000..ef0ffee --- /dev/null +++ b/packages/conferenceapp/lib/src/features/more/presentation/map/walker_grid_painter.dart @@ -0,0 +1,115 @@ +import 'package:cave/cave.dart'; +import 'package:flutter/material.dart' hide Action; +import 'package:schematics/schematics.dart'; + +import 'action.dart'; + +typedef GridCellRange = ({GridCell start, GridCell end}); + +class WalkerGridPainter extends CustomPainter { + WalkerGridPainter({ + required this.grid, + required this.cellSize, + required this.progress, + this.cellTrackRange, + this.actions = const [], + this.showPath = false, + }); + + final Grid grid; + final double cellSize; + final double progress; + final GridCellRange? cellTrackRange; + final List actions; + final bool showPath; + + @override + void paint(Canvas canvas, Size size) { + final path = _robotWalkPath(canvas, size, grid); + if (showPath) { + _paintProgressPath(path, canvas, const HSLColor.fromAHSL(1, 30, 1, 0.5)); + } + _paintWalker(path, canvas); + } + + Path _robotWalkPath(Canvas canvas, Size size, Grid grid) { + Path progressPath = Path(); + + if (cellTrackRange != null) { + final firstYOrigin = + (size.height / grid.rows * cellTrackRange!.start.row).floorToDouble(); + final firstXOrigin = + (size.width / grid.columns * cellTrackRange!.start.column) + .floorToDouble(); + for (int i = 0; i < actions.length; i++) { + final action = actions[i]; + + if (i == 0 && action == Action.doNothing) { + progressPath.moveTo( + firstXOrigin + cellSize / 2, firstYOrigin + cellSize / 2); + continue; + } + + switch (action) { + case Action.moveRight: + progressPath.relativeLineTo(cellSize, 0); + case Action.moveLeft: + progressPath.relativeLineTo(-cellSize, 0); + case Action.moveUp: + progressPath.relativeLineTo(0, -cellSize); + case Action.moveDown: + progressPath.relativeLineTo(0, cellSize); + case Action.doNothing: + } + } + } + + return progressPath; + } + + void _paintProgressPath(Path path, Canvas canvas, HSLColor hue) { + canvas.drawPath( + path, + Paint() + ..color = hue.toColor() + ..style = PaintingStyle.stroke + ..strokeCap = StrokeCap.round + ..strokeJoin = StrokeJoin.round + ..strokeWidth = cellSize, + ); + } + + void _paintWalker(Path path, Canvas canvas) { + final pathMetrics = path.computeMetrics(); + + for (final pathMetric in pathMetrics) { + try { + final extractPath = + pathMetric.extractPath(0, pathMetric.length * progress); + + final metric = extractPath.computeMetrics().first; + final tangent = metric.getTangentForOffset(metric.length)!; + final offset = tangent.position; + + canvas.drawOval( + Rect.fromCircle(center: offset, radius: cellSize), + Paint() + ..style = PaintingStyle.fill + ..color = DevfestColors.primariesBlue70.withOpacity(1.0)); + } catch (_) {} + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + if (oldDelegate is! WalkerGridPainter) return false; + + if (oldDelegate.grid != grid) return true; + if (oldDelegate.cellSize != cellSize) return true; + if (oldDelegate.progress != progress) return true; + if (oldDelegate.cellTrackRange != cellTrackRange) return true; + if (oldDelegate.actions != actions) return true; + if (oldDelegate.showPath != showPath) return true; + return false; + } +} diff --git a/packages/conferenceapp/lib/src/features/more/presentation/screens/venue_map.dart b/packages/conferenceapp/lib/src/features/more/presentation/screens/venue_map.dart index f44b24b..e26c54d 100644 --- a/packages/conferenceapp/lib/src/features/more/presentation/screens/venue_map.dart +++ b/packages/conferenceapp/lib/src/features/more/presentation/screens/venue_map.dart @@ -1,12 +1,13 @@ import 'package:cave/cave.dart'; -import 'package:devfest24/src/features/more/presentation/map/map.dart'; -import 'package:devfest24/src/features/more/presentation/widgets/map.dart'; import 'package:devfest24/src/routing/routing.dart'; import 'package:flutter/material.dart' hide Action; +import 'package:flutter/physics.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:schematics/schematics.dart'; import '../../../../shared/shared.dart'; -import '../widgets/map_layout.dart'; +import '../map/path_finder.dart'; +import '../map/map.dart'; final showGridStateProvider = StateProvider.autoDispose((ref) { return false; @@ -29,17 +30,22 @@ class VenueMapScreen extends ConsumerStatefulWidget { ConsumerState createState() => _VenueMapScreenState(); } -class _VenueMapScreenState extends ConsumerState { +class _VenueMapScreenState extends ConsumerState + with SingleTickerProviderStateMixin { + final cellSize = 8.0; + late final AnimationController controller; + + late Animation speedProgressAnim; + late List roomsLayouts; GridCellRange? navigationBlock; ({RoomType? from, RoomType? to}) instructions = (from: null, to: null); Grid? grid; - List roomByRoomInstructions = []; + List actions = []; void _fromOnChanged(RoomType? room) { setState(() { instructions = (from: room, to: instructions.to); - navigationBlock = null; }); } @@ -56,61 +62,94 @@ class _VenueMapScreenState extends ConsumerState { setState(() { navigationBlock = null; }); + controller.stop(); Future.delayed(const Duration(milliseconds: 50), () { final newNavigationBlock = ( start: getFirstAvailableCellFromBottomInRoom(instructions.from!), end: getCenterAvailableCellInRoom(instructions.to!), ); - roomByRoomInstructions = - getOverviewDirections(instructions.from!, instructions.to!); - debugPrint('walk path: ${roomByRoomInstructions.chainString()}'); setState(() { navigationBlock = newNavigationBlock; }); + _navigateToDestination(newNavigationBlock); }); } - GridCell getCenterAvailableCellInRoom(RoomType room) { - final roomBlock = roomsLayouts.firstWhere( - (block) => block.room == room, - ); + void _navigateToDestination(GridCellRange movementRange) async { + if (grid == null) return; + int movementPathState = 30; - final startTouchColumn = (roomBlock.start.dx / cellSize).floor(); - final endTouchColumn = (roomBlock.end.dx / cellSize).floor(); - final startTouchRow = (roomBlock.start.dy / cellSize).floor(); - final endTouchRow = (roomBlock.end.dy / cellSize).floor(); + controller.reset(); - final randomRow = startTouchRow + (endTouchRow - startTouchRow) ~/ 2; - final randomColumn = - startTouchColumn + (endTouchColumn - startTouchColumn) ~/ 2; + Grid newGrid = grid!.copyWith(); - return GridCell(row: randomRow, column: randomColumn); - } - - GridCell getFirstAvailableCellFromBottomInRoom(RoomType room) { - final roomBlock = roomsLayouts.firstWhere( - (block) => block.room == room, + final navigationActions = await getActions( + grid: newGrid, + moveRange: movementRange, ); + if (!mounted) return; - final startTouchColumn = (roomBlock.start.dx / cellSize).floor(); - final endTouchColumn = (roomBlock.end.dx / cellSize).floor(); - final startTouchRow = (roomBlock.start.dy / cellSize).floor(); - final endTouchRow = (roomBlock.end.dy / cellSize).floor(); + GridCell start = movementRange.start; + for (final action in navigationActions) { + switch (action) { + case Action.moveUp: + start = start.above; + newGrid.grid[start.row][start.column] = movementPathState; + break; + case Action.moveRight: + start = start.right; + newGrid.grid[start.row][start.column] = movementPathState; + break; + case Action.moveLeft: + start = start.left; + newGrid.grid[start.row][start.column] = movementPathState; + break; + case Action.moveDown: + start = start.below; + newGrid.grid[start.row][start.column] = movementPathState; + break; + case Action.doNothing: + newGrid.grid[start.row][start.column] = movementPathState; + break; + } + } - final startAndEndColDiff = (endTouchColumn - startTouchColumn - 1); - final column = - startTouchColumn + startAndEndColDiff - (startAndEndColDiff ~/ 8); - final row = startTouchRow + (endTouchRow - startTouchRow) ~/ 2; + if (!mounted) return; + setState(() { + if (!mounted) return; + grid = newGrid; + actions = navigationActions; + }); - GridCell cell = GridCell(row: row, column: column); + _runAnimation(navigationActions.length); + } - while (grid!.filter(cell, (state) => state <= 0)) { - cell = GridCell(row: cell.row - 1, column: cell.column - 1); + void _animationListener() { + // stop animation controller when simulation is done + // at controller value greater than 1, friction simulation is done + if (controller.value > 1) { + controller.stop(); } + } - return cell; + @override + void initState() { + super.initState(); + controller = AnimationController.unbounded(vsync: this); + speedProgressAnim = ConstantTween(0).animate(controller); + + controller.addListener(_animationListener); + } + + void _runAnimation(int distance) { + speedProgressAnim = controller.drive(Tween(begin: 0, end: 1)); + + final speed = switch (distance) { <= 50 => 0.38, <= 100 => 0.2, _ => 0.05 }; + final simulation = + FrictionSimulation.through(0, distance.toDouble(), speed, 0); + controller.animateWith(simulation); } @override @@ -224,120 +263,320 @@ class _VenueMapScreenState extends ConsumerState { ), ], ), - body: Stack( + body: Column( children: [ - Positioned.fill( - child: Column( + Padding( + padding: const EdgeInsets.symmetric( + horizontal: Constants.horizontalMargin) + .r, + child: Row( children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: Constants.horizontalMargin) - .r, - child: Column( - children: [ - DevfestDropDown( - title: 'Where are you in Landmark?', - hint: 'Current Location', - items: RoomType.values - .where((room) => room != instructions.to) - .toList(), - prefixIcon: const Icon(IconsaxOutline.location), - suffixIcon: const Icon(IconsaxOutline.arrow_down_1), - onChanged: _fromOnChanged, - ), - Constants.verticalGutter.verticalSpace, - DevfestDropDown( - title: 'Where are you headed?', - hint: 'Desired destination', - items: RoomType.values - .where((room) => room != instructions.from) - .toList(), - prefixIcon: const Icon(IconsaxOutline.location_tick), - suffixIcon: const Icon(IconsaxOutline.arrow_down_1), - onChanged: _toOnChanged, - ), - ], + Flexible( + child: DevfestDropDown( + title: 'Where are you in Landmark?', + hint: 'Current Location', + items: RoomType.values + .where((room) => room != instructions.to) + .toList(), + prefixIcon: const Icon(IconsaxOutline.location), + suffixIcon: const Icon(IconsaxOutline.arrow_down_1), + onChanged: _fromOnChanged, ), ), - Constants.verticalGutter.verticalSpace, - Expanded( - child: DecoratedBox( - decoration: BoxDecoration( - color: DevfestTheme.of(context).backgroundColor, - border: Border( - top: BorderSide( - color: DevfestColors.grey80.possibleDarkVariant, - ), - ), - ), - child: Padding( - padding: const EdgeInsets.only( - left: Constants.largeHorizontalGutter, - right: Constants.smallVerticalGutter, - top: Constants.verticalGutter, - bottom: Constants.verticalGutter, - ).r, - child: LayoutBuilder( - builder: (context, constraints) { - return RepaintBoundary( - child: SizedBox( - height: constraints.maxHeight, - child: LandmarkMap( - mapConstraints: constraints, - getDirections: navigationBlock, - onBlocksLayout: (layout) { - roomsLayouts = layout; - }, - onGridUpdate: (newGrid) { - grid = newGrid; - }, - ), - ), - ); - }, - ), - ), + Constants.verticalGutter.horizontalSpace, + Flexible( + child: DevfestDropDown( + title: 'Where are you headed?', + hint: 'Desired destination', + items: RoomType.values + .where((room) => room != instructions.from) + .toList(), + prefixIcon: const Icon(IconsaxOutline.location_tick), + suffixIcon: const Icon(IconsaxOutline.arrow_down_1), + onChanged: _toOnChanged, ), ), - Material( - elevation: 5, - shape: const RoundedRectangleBorder( - borderRadius: - BorderRadius.vertical(top: Radius.circular(16)), + ], + ), + ), + Constants.verticalGutter.verticalSpace, + Expanded( + child: DecoratedBox( + decoration: BoxDecoration( + color: Color(0xfffffaeb).possibleDarkVariant, + border: Border( + top: BorderSide( + color: DevfestColors.grey80.possibleDarkVariant, ), - child: DecoratedBox( - decoration: BoxDecoration( - color: DevfestTheme.of(context).backgroundColor, - borderRadius: - const BorderRadius.vertical(top: Radius.circular(16)), - border: Border( - top: BorderSide( - color: DevfestColors.grey80.possibleDarkVariant, - ), + ), + ), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 28.w) + .copyWith(top: 20.h, bottom: 16.h) + .subtract(EdgeInsets.only(right: 4.w)), + child: Stack( + children: [ + Positioned.fill( + child: SchemaWidget( + onInitiateAxesScale: (blockAreaConstraints) => + (xScale: 1.w, yScale: 0.85.h, openingScale: 1.w), + schemaSize: (cellSize: 8, openingRadius: 22), + layoutDirection: LayoutDirection.bottomRight, + showGrid: ref.watch(showGridStateProvider), + showBlocks: ref.watch(showBlocksProvider), + onBlocksLayout: (blocksLayout) { + WidgetsFlutterBinding.ensureInitialized() + .addPostFrameCallback((_) { + setState(() { + roomsLayouts = blocksLayout; + }); + }); + }, + onGridUpdate: (newGrid) { + WidgetsFlutterBinding.ensureInitialized() + .addPostFrameCallback((_) { + setState(() { + grid = newGrid; + }); + }); + }, + blocks: [ + DevfestBlock.withContext( + context, + blockLabel: 'Room 2', + room: RoomType.room2, + width: 244, + height: 106, + position: Offset(30, 0), + blockColor: const Color(0xffd8f3df), + openings: [const Offset(207, 0).opening], + ), + DevfestBlock.withContext( + context, + blockLabel: 'Room 3', + room: RoomType.room3, + height: 348, + width: 96, + blockColor: Color(0xffffdebf), + alignmentToPreviousBlock: + BlockAlignment.bottomLeft.alignTop.alignRight, + openings: [const Offset(32, 0).oSize(32)], + ), + DevfestBlock.withContext( + context, + blockLabel: 'Network\nZone', + room: RoomType.networkZone, + alignmentToPreviousBlock: + BlockAlignment.topLeft.alignTop, + width: 96, + height: 86, + blockColor: Color(0xffb6b0dd), + openings: [ + Offset(32, 86).oSize(32), + Offset(96, 31).opening, + ], + ), + DevfestBlock.withContext( + context, + blockLabel: 'Exhibition Room', + room: RoomType.exhibitionRoom, + width: 244, + height: 86, + alignmentToPreviousBlock: + BlockAlignment.topRight.alignLeft, + blockColor: Color(0xffffb6c8), + openings: [ + Offset(0, 31).opening, + Offset(71, 0).oSize(46), + Offset(90, 86).oSize(36), + Offset(194, 86).oSize(50), + ], + ), + DevfestBlock.withContext( + context, + height: 242, + width: 76, + blockLabel: 'HALLWAY', + room: RoomType.entranceHallway, + blockLabelStyle: TextStyle(fontSize: 10).medium, + alignmentToPreviousBlock: + BlockAlignment.bottomRight.alignRight - + BlockAlignment(0.4, 0), + entranceLabel: 'ENTRANCE/EXIT', + hideFenceBorder: HideFenceBorder.right, + entranceOpeningRadius: 16.5, + blockColor: Color(0xffd9d0c3), + openings: [ + Offset(39, 242).opening, + Offset(0, 124).oSize(33), + Offset(0.001, 0).oSize(76), + ], + ), + DevfestBlock.withContext( + context, + blockLabel: 'Room 1', + room: RoomType.room1, + alignmentToPreviousBlock: + BlockAlignment.bottomLeft.alignTop.alignRight, + height: 242, + width: 195, + blockColor: Color(0xffffffff), + openings: [ + Offset(195, 124).oSize(33), + Offset(90, 0).oSize(36), + ], + ), + DevfestBlock.withContext( + context, + room: RoomType.hallway, + blockLabel: 'HALLWAY', + blockLabelStyle: TextStyle(fontSize: 12.sp).medium, + width: 45, + height: 189, + position: Offset(158, 434), + hideFenceBorder: HideFenceBorder.all, + blockColor: Color(0xffd9d0c3), + ), + DevfestBlock.withContext( + context, + room: RoomType.restroom, + blockLabel: 'Restroom', + blockLabelStyle: TextStyle(fontSize: 16.sp).medium, + alignmentToPreviousBlock: + BlockAlignment.centerRight.alignVCenter, + height: 52, + width: 112, + hideFenceBorder: HideFenceBorder.all, + ), + DevfestBlock.withContext( + context, + room: RoomType.greenRoom, + blockLabel: 'Green Room', + position: Offset(255, 506), + height: 45, + width: 118, + hideFenceBorder: HideFenceBorder.all, + blockColor: Color(0xffc7ebcc), + ), + DevfestBlock.withContext( + context, + room: RoomType.stairs, + blockLabel: 'STAIRWAY', + blockLabelStyle: TextStyle(fontSize: 12.sp).medium, + alignmentToPreviousBlock: + BlockAlignment.topLeft.alignTop, + height: 45, + width: 170, + hideFenceBorder: HideFenceBorder.all, + blockColor: Color(0xffd9d9d9), + ), + DevfestBlock.withContext( + context, + room: RoomType.room4, + blockLabel: 'Room 4', + height: 45, + alignmentToPreviousBlock: + BlockAlignment.topLeft.alignTop, + hideFenceBorder: HideFenceBorder.all, + blockColor: Color(0xff4285f4), + ), + ], ), ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: Constants.verticalGutter, - horizontal: Constants.horizontalMargin) - .r - .add(EdgeInsets.only( - bottom: - MediaQuery.viewPaddingOf(context).bottom)), - child: DevfestFilledButton( - title: const Text('Get Directions'), - onPressed: _getDirections, + if (grid != null) + Positioned.fill( + child: AnimatedBuilder( + animation: controller, + builder: (context, child) { + return CustomPaint( + painter: WalkerGridPainter( + grid: grid!, + cellSize: cellSize, + cellTrackRange: navigationBlock, + progress: speedProgressAnim.value, + actions: actions, + showPath: ref.watch(showPathStateProvider), + ), + ); + }, + ), ), - ), + ], + ), + ), + ), + ), + Material( + elevation: 5, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16)), + ), + child: DecoratedBox( + decoration: BoxDecoration( + color: DevfestTheme.of(context).backgroundColor, + borderRadius: + const BorderRadius.vertical(top: Radius.circular(16)), + border: Border( + top: BorderSide( + color: DevfestColors.grey80.possibleDarkVariant, ), ), - ], + ), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: Constants.horizontalMargin) + .r + .add(EdgeInsets.only( + top: Constants.verticalGutter, + bottom: MediaQuery.viewPaddingOf(context).bottom)), + child: DevfestFilledButton( + title: const Text('Get Directions'), + onPressed: _getDirections, + ), + ), ), ), ], ), ); } + + GridCell getCenterAvailableCellInRoom(RoomType room) { + final roomBlock = roomsLayouts.getLayoutForIdentifier(room); + + final startTouchColumn = (roomBlock.start.dx / cellSize).floor(); + final endTouchColumn = (roomBlock.end.dx / cellSize).floor(); + final startTouchRow = (roomBlock.start.dy / cellSize).floor(); + final endTouchRow = (roomBlock.end.dy / cellSize).floor(); + + final randomRow = startTouchRow + (endTouchRow - startTouchRow) ~/ 2; + final randomColumn = + startTouchColumn + (endTouchColumn - startTouchColumn) ~/ 2; + + return GridCell(row: randomRow, column: randomColumn); + } + + GridCell getFirstAvailableCellFromBottomInRoom(RoomType room) { + final roomBlock = roomsLayouts.getLayoutForIdentifier(room); + + final startTouchColumn = (roomBlock.start.dx / cellSize).floor(); + final endTouchColumn = (roomBlock.end.dx / cellSize).floor(); + final startTouchRow = (roomBlock.start.dy / cellSize).floor(); + final endTouchRow = (roomBlock.end.dy / cellSize).floor(); + + final startAndEndColDiff = (endTouchColumn - startTouchColumn - 1); + final column = + startTouchColumn + startAndEndColDiff - (startAndEndColDiff ~/ 8); + final row = startTouchRow + (endTouchRow - startTouchRow) ~/ 2; + + GridCell cell = GridCell(row: row, column: column); + + while (grid!.filter(cell, (state) => state <= 0)) { + cell = GridCell(row: cell.row - 1, column: cell.column - 1); + } + + return cell; + } } class DevfestSwitch extends StatelessWidget { @@ -372,3 +611,48 @@ class DevfestSwitch extends StatelessWidget { ); } } + +extension type DevfestBlock._(Block i) implements Block { + DevfestBlock.withContext( + BuildContext context, { + required RoomType room, + double width = 100, + double height = 100, + HideFenceBorder hideFenceBorder = HideFenceBorder.none, + String? entranceLabel, + TextStyle? entranceLabelStyle, + double? entranceOpeningRadius, + required String blockLabel, + TextStyle? blockLabelStyle, + Color? blockColor, + Offset? position, + List openings = const [], + BlockAlignment? alignmentToPreviousBlock, + }) : this._( + Block( + identifier: room, + blockLabel: blockLabel, + entranceLabel: entranceLabel, + blockColor: blockColor ?? DevfestColors.primariesYellow60, + height: height, + width: width, + hideFenceBorder: hideFenceBorder, + entranceLabelStyle: DevfestTheme.of(context) + .textTheme + ?.bodyBody4Regular + ?.medium + .applyColor(DevfestColors.grey10) + .merge(entranceLabelStyle), + entranceOpeningRadius: entranceOpeningRadius, + blockLabelStyle: DevfestTheme.of(context) + .textTheme + ?.bodyBody3Regular + ?.semi + .applyColor(DevfestColors.grey10) + .merge(blockLabelStyle), + position: position, + openings: openings, + alignmentToPreviousBlock: alignmentToPreviousBlock, + ), + ); +} diff --git a/packages/conferenceapp/lib/src/features/more/presentation/widgets/foot.dart b/packages/conferenceapp/lib/src/features/more/presentation/widgets/foot.dart deleted file mode 100644 index 1f0f5d6..0000000 --- a/packages/conferenceapp/lib/src/features/more/presentation/widgets/foot.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:cave/cave.dart'; -import 'package:flutter/material.dart'; - -class MapFoot extends StatelessWidget { - const MapFoot({super.key, required this.isRightFoot, this.color}); - - const MapFoot.left({super.key, this.color}) : isRightFoot = false; - - const MapFoot.right({super.key, this.color}) : isRightFoot = true; - - final bool isRightFoot; - final Color? color; - - @override - Widget build(BuildContext context) { - Widget child = SvgPicture.string( - _footSvg, - height: 20.h, - colorFilter: color != null // - ? ColorFilter.mode(color!, BlendMode.srcIn) - : null, - ); - - if (isRightFoot) return child; - return Transform.flip( - flipX: true, - child: child, - ); - } -} - -const _footSvg = ''' - - - - - - - - - -'''; diff --git a/packages/conferenceapp/lib/src/features/more/presentation/widgets/map.dart b/packages/conferenceapp/lib/src/features/more/presentation/widgets/map.dart deleted file mode 100644 index c5e7296..0000000 --- a/packages/conferenceapp/lib/src/features/more/presentation/widgets/map.dart +++ /dev/null @@ -1,422 +0,0 @@ -import 'package:cave/cave.dart'; -import 'package:devfest24/src/features/more/presentation/screens/venue_map.dart'; -import 'package:flutter/material.dart' hide Action; -import 'package:flutter/physics.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -import '../map/map.dart'; -import '../map/path_finder.dart'; -import 'map_block.dart'; -import 'map_layout.dart'; - -typedef BlockLayoutCallback = void Function(List areas); -typedef GridCallback = void Function(Grid grid); - -typedef GridCellRange = ({GridCell start, GridCell end}); - -class LandmarkMap extends ConsumerStatefulWidget { - const LandmarkMap({ - super.key, - required this.mapConstraints, - required this.onBlocksLayout, - this.getDirections, - this.onGridUpdate, - }); - - final BoxConstraints mapConstraints; - final BlockLayoutCallback onBlocksLayout; - final GridCallback? onGridUpdate; - final GridCellRange? getDirections; - - @override - ConsumerState createState() => _LandmarkMapState(); -} - -class _LandmarkMapState extends ConsumerState - with SingleTickerProviderStateMixin { - late final AnimationController controller; - late double largeRoomHeight = widget.mapConstraints.maxWidth * 0.206; - late double mediumRoomHeight = widget.mapConstraints.maxHeight * 0.09; - late List roomsLayouts; - late Animation speedProgressAnim; - - late List mapSchematics = [ - Block.fromContext( - context, - width: widget.mapConstraints.maxWidth, - height: largeRoomHeight, - hideFenceBorder: HideFenceBorder.right, - entranceLabel: 'ENTRANCE', - blockLabel: 'Exhibition Room', - blockColor: const Color(0xffb6b0dd), - openingPositions: [ - Offset(56.w, 0), - Offset(335.w, 0), - ], - ), - Block.fromContext( - context, - width: widget.mapConstraints.maxWidth, - height: largeRoomHeight, - hideFenceBorder: HideFenceBorder.right, - entranceLabel: 'ENTRANCE', - blockLabel: 'Room 1', - blockColor: const Color(0xffffd3bf), - openingPositions: [ - Offset(335.w, largeRoomHeight), - Offset(56.w, largeRoomHeight), - Offset(335.w, 0), - ], - ), - Block.fromContext( - context, - width: widget.mapConstraints.maxWidth, - height: largeRoomHeight, - hideFenceBorder: HideFenceBorder.right, - entranceLabel: 'Exit', - blockLabel: 'Room 2', - blockColor: const Color(0xff88cd83), - openingSizes: [null, widget.mapConstraints.maxWidth * 0.082], - openingPositions: [ - Offset(335.w, largeRoomHeight), - Offset(307.w, 0), - ], - ), - Block.fromContext( - context, - width: widget.mapConstraints.maxWidth * 0.082, - height: widget.mapConstraints.maxHeight * 0.293, - hideFenceBorder: HideFenceBorder.all, - blockLabel: 'HALLWAY', - blockLabelStyle: DevfestTheme.of(context) - .textTheme - ?.bodyBody4Regular - ?.medium - .applyColor(DevfestColors.grey10), - blockColor: const Color(0xffd9d0c3), - position: Offset(280.w, largeRoomHeight * 3), - ), - Block.fromContext( - context, - width: widget.mapConstraints.maxWidth * 0.190, - height: widget.mapConstraints.maxHeight * 0.14, - hideFenceBorder: HideFenceBorder.all, - blockLabel: 'Toilet', - blockColor: const Color(0xffbee673), - position: Offset( - 313.w, - largeRoomHeight * 3 + widget.mapConstraints.maxHeight * 0.064, - ), - ), - Block.fromContext( - context, - width: widget.mapConstraints.maxWidth * 0.638, - height: mediumRoomHeight, - hideFenceBorder: HideFenceBorder.all, - blockLabel: 'STAIRWAY', - blockLabelStyle: DevfestTheme.of(context) - .textTheme - ?.bodyBody4Regular - ?.medium - .applyColor(DevfestColors.grey10), - blockColor: const Color(0xffd9d9d9), - position: Offset( - 22.w, - largeRoomHeight * 3 + - widget.mapConstraints.maxHeight * 0.293 - - widget.mapConstraints.maxHeight * 0.09, - ), - ), - Block.fromContext( - context, - width: widget.mapConstraints.maxWidth * 0.344, - height: mediumRoomHeight, - hideFenceBorder: HideFenceBorder.all, - blockLabel: 'Room 3', - blockColor: const Color(0xffbee673), - position: Offset( - 22.w, - largeRoomHeight * 3 + widget.mapConstraints.maxHeight * 0.114, - ), - ), - Block.fromContext( - context, - width: widget.mapConstraints.maxWidth * 0.344, - height: mediumRoomHeight, - hideFenceBorder: HideFenceBorder.all, - blockLabel: 'Room 4', - blockColor: const Color(0xffbbddc9), - position: Offset( - 22.w, - largeRoomHeight * 3 + widget.mapConstraints.maxHeight * 0.293, - ), - ), - ]; - - List actions = []; - - int hueValue = 200; - int movementPathState = 30; - int allowedState = 150; - - late Grid grid = Grid.make( - widget.mapConstraints.maxHeight ~/ cellSize, - widget.mapConstraints.maxWidth ~/ cellSize, - 0, - ); - - late Grid baseGrid = Grid.make( - widget.mapConstraints.maxHeight ~/ cellSize, - widget.mapConstraints.maxWidth ~/ cellSize, - 0, - ); - - void _animationListener() { - // stop animation controller when simulation is done - // at controller value greater than 1, friction simulation is done - if (controller.value > 1) { - controller.stop(); - } - } - - Offset? walkerPosition; - - @override - void initState() { - super.initState(); - - controller = AnimationController.unbounded(vsync: this); - speedProgressAnim = ConstantTween(0).animate(controller); - - controller.addListener(_animationListener); - - WidgetsFlutterBinding.ensureInitialized().addPostFrameCallback((_) { - if (widget.getDirections != null) { - _navigateToDestination(); - } - }); - } - - @override - void didUpdateWidget(covariant LandmarkMap oldWidget) { - super.didUpdateWidget(oldWidget); - - if (widget.getDirections != null && - widget.getDirections != oldWidget.getDirections) { - _navigateToDestination(); - } - } - - @override - void dispose() { - controller.dispose(); - super.dispose(); - } - - void _resetGrid() { - setState(() { - grid = Grid.make(grid.rows, grid.columns, 0); - }); - roomsLayouts.forEach(_fillPositionOnGrid); - } - - void _runAnimation(int distance) { - speedProgressAnim = controller.drive(Tween(begin: 0, end: 1)); - - final speed = switch (distance) { <= 50 => 0.38, <= 100 => 0.2, _ => 0.05 }; - final simulation = - FrictionSimulation.through(0, distance.toDouble(), speed, 0); - controller.animateWith(simulation); - } - - void _navigateToDestination() async { - if (widget.getDirections == null) return; - - _resetGrid(); - controller.reset(); - - Grid newGrid = Grid.make(widget.mapConstraints.maxHeight ~/ cellSize, - widget.mapConstraints.maxWidth ~/ cellSize, 0); - - newGrid = newGrid.copyWith(grid: grid.grid.toList()); - - final navigationActions = await getActions( - grid: newGrid, - moveRange: widget.getDirections!, - ); - if (!mounted) return; - - GridCell start = widget.getDirections!.start; - for (final action in navigationActions) { - switch (action) { - case Action.moveUp: - start = start.above; - newGrid.grid[start.row][start.column] = movementPathState; - break; - case Action.moveRight: - start = start.right; - newGrid.grid[start.row][start.column] = movementPathState; - break; - case Action.moveLeft: - start = start.left; - newGrid.grid[start.row][start.column] = movementPathState; - break; - case Action.moveDown: - start = start.below; - newGrid.grid[start.row][start.column] = movementPathState; - break; - case Action.doNothing: - newGrid.grid[start.row][start.column] = movementPathState; - break; - } - } - - if (!mounted) return; - setState(() { - if (!mounted) return; - grid = newGrid; - actions = navigationActions; - }); - - _runAnimation(navigationActions.length); - } - - @override - Widget build(BuildContext context) { - return Stack( - fit: StackFit.expand, - children: [ - Positioned.fill( - child: AnimatedBuilder( - animation: controller, - builder: (context, child) { - return CustomPaint( - foregroundPainter: GridPainter( - grid: grid, - cellSize: cellSize, - progress: speedProgressAnim.value, - cellTrackRange: widget.getDirections, - actions: actions, - showGrid: ref.watch(showGridStateProvider), - showPath: ref.watch(showPathStateProvider), - ), - child: CustomPaint( - foregroundPainter: GridPainter( - grid: baseGrid, - cellSize: cellSize, - progress: 0, - showBlocks: ref.watch(showBlocksProvider), - ), - child: child, - ), - ); - }, - child: CustomMultiChildLayout( - delegate: MapLayoutDelegate( - blocks: mapSchematics, - onBlocksLayout: (areas) { - widget.onBlocksLayout(areas.toList()); - roomsLayouts = areas; - WidgetsFlutterBinding.ensureInitialized() - .addPostFrameCallback((_) { - areas.forEach(_fillPositionOnGrid); - }); - }, - ), - children: [ - for (int i = 0; i < mapSchematics.length; i++) - LayoutId( - id: i, - child: CustomPaint( - painter: MapBlockPainter(block: mapSchematics[i]), - ), - ), - ], - ), - ), - ), - ], - ); - } - - void _fillPositionOnGrid(BlockLayoutArea area) { - Grid newGrid = Grid.make(widget.mapConstraints.maxHeight ~/ cellSize, - widget.mapConstraints.maxWidth ~/ cellSize, 0); - - newGrid = newGrid.copyWith(grid: grid.grid.toList()); - - final startTouchColumn = (area.start.dx / cellSize).floor(); - final endTouchColumn = (area.end.dx / cellSize).floor(); - final startTouchRow = (area.start.dy / cellSize).floor(); - final endTouchRow = (area.end.dy / cellSize).floor(); - - for (int i = startTouchRow; i < endTouchRow; i++) { - for (int j = startTouchColumn; j < endTouchColumn; j++) { - final leftEdge = j == startTouchColumn; - final rightEdge = j == endTouchColumn; - final topEdge = i == startTouchRow; - final bottomEdge = i == endTouchRow - 1; - - // deal with edges - if (leftEdge || rightEdge || topEdge || bottomEdge) { - if (area.hideFenceBorder != HideFenceBorder.all) { - if (area.hideFenceBorder == HideFenceBorder.right && !rightEdge) { - final openingsGridPoints = area.openings.map((opening) { - final startTouchColumn = (opening.start.dx / cellSize).floor(); - final endTouchColumn = (opening.end.dx / cellSize).floor(); - final startTouchRow = (opening.start.dy / cellSize).floor(); - final endTouchRow = (opening.end.dy / cellSize).floor(); - - return ( - startGridColumn: startTouchColumn, - endGridColumn: endTouchColumn, - startGridRow: startTouchRow, - endGridRow: endTouchRow, - ); - }); - - for (final gridPoint in openingsGridPoints) { - final isWithinColumnRange = j >= gridPoint.startGridColumn && - j <= gridPoint.endGridColumn; - final isWithinRowRange = - i >= gridPoint.startGridRow && i <= gridPoint.endGridRow; - - if (isWithinColumnRange && isWithinRowRange) { - newGrid.grid[i][j] = hueValue; - continue; - } - } - - continue; - } - - if (area.hideFenceBorder == HideFenceBorder.left && !leftEdge) { - continue; - } - - if (area.hideFenceBorder == HideFenceBorder.top && !topEdge) { - continue; - } - - if (area.hideFenceBorder == HideFenceBorder.bottom && !bottomEdge) { - continue; - } - } - } - - newGrid.grid[i][j] = hueValue; - } - } - - setState(() { - grid = newGrid; - baseGrid = newGrid; - }); - widget.onGridUpdate?.call(grid); - - hueValue += 20; - if (hueValue > 360) { - hueValue = 1; - } - } -} diff --git a/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_block.dart b/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_block.dart deleted file mode 100644 index 51b5dab..0000000 --- a/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_block.dart +++ /dev/null @@ -1,328 +0,0 @@ -import 'package:cave/cave.dart'; -import 'package:flutter/material.dart'; - -import '../map/grid.dart'; -import '../map/map_utils.dart'; - -double openingRadius = 32.w; - -class MapBlockPainter extends CustomPainter { - final Block block; - - const MapBlockPainter({required this.block}); - - static const double _fenceStrokeWidth = 1.5; - - @override - void paint(Canvas canvas, Size size) { - _drawBlock(canvas, size); - } - - void _drawBlock(Canvas canvas, Size size) { - final paint = Paint() - ..color = block.blockColor ?? DevfestColors.grey10 - ..style = PaintingStyle.fill; - - final entranceLabelExists = block.entranceLabel != null; - const textHeightFactor = 20.0; - final textPainter = TextPainter( - text: TextSpan( - text: block.entranceLabel ?? '', - style: block.entranceLabelStyle ?? - const TextStyle( - color: DevfestColors.grey10, - fontWeight: FontWeight.w500, - fontSize: 12, - ), - ), - textDirection: TextDirection.ltr, - ); - - textPainter.layout(); - - // render entrance label - if (entranceLabelExists) { - canvas.save(); - canvas.rotate(getRadFromDeg(-90)); - textPainter.paint( - canvas, - Offset(-(size.height + textPainter.width) / 2, - size.width - textHeightFactor), - ); - - canvas.restore(); - } - - // 5 is padding between entrance label and block - final blockStartFromEnd = - entranceLabelExists ? textHeightFactor + 5.0 : 0.0; - final blockWidth = size.width - blockStartFromEnd; - - assert(() { - final openingPositionAligned = () { - return block.openingPositions.map((openingPosition) { - // opening position must be aligned correctly at the horizontal edges of the block - if (openingPosition.dx == 0 || - openingPosition.dx - blockStartFromEnd == blockWidth) { - return openingPosition.dy >= 0 && openingPosition.dy <= size.height; - } - - // opening position must be aligned correctly at the vertical edges of the block - if (openingPosition.dy == 0 || openingPosition.dy == size.height) { - return openingPosition.dx >= 0 && - openingPosition.dx - blockStartFromEnd <= blockWidth; - } - - return false; - }).fold(true, (prev, current) => prev && current); - }(); - - if (!openingPositionAligned) { - throw FlutterError( - 'Opening position must be aligned correctly at the edges of the block', - ); - } - return openingPositionAligned; - }()); - - // paint inside - late Path path; - if (entranceLabelExists) { - path = Path() - ..moveTo(0, 0) - ..lineTo(0, size.height) - ..lineTo(blockWidth, size.height) - ..lineTo(blockWidth, size.height * 0.75) - ..arcToPoint(Offset(blockWidth, size.height * 0.25), - radius: const Radius.circular(22)) - ..lineTo(blockWidth, 0) - ..close(); - } else { - path = Path() - ..moveTo(0, 0) - ..lineTo(0, size.height) - ..lineTo(blockWidth, size.height) - ..lineTo(blockWidth, 0) - ..close(); - } - canvas.drawPath(path, paint); - - // paint border - paint - ..color = Colors.black - ..style = PaintingStyle.stroke - ..strokeCap = StrokeCap.round - ..strokeWidth = _fenceStrokeWidth; - - path = switch (block.hideFenceBorder) { - HideFenceBorder.none => _getPathWithOpenings( - block.openingPositions, - Size(blockWidth, size.height), - _defaultAllowedEdges, - blockStartFromEnd, - ), - HideFenceBorder.top => _getPathWithOpenings( - block.openingPositions, - Size(blockWidth, size.height), - _defaultAllowedEdges.copyWith(top: false), - blockStartFromEnd, - ), - HideFenceBorder.right => _getPathWithOpenings( - block.openingPositions, - Size(blockWidth, size.height), - _defaultAllowedEdges.copyWith(right: false), - blockStartFromEnd, - ), - HideFenceBorder.bottom => _getPathWithOpenings( - block.openingPositions, - Size(blockWidth, size.height), - _defaultAllowedEdges.copyWith(bottom: false), - blockStartFromEnd, - ), - HideFenceBorder.left => _getPathWithOpenings( - block.openingPositions, - Size(blockWidth, size.height), - _defaultAllowedEdges.copyWith(left: false), - blockStartFromEnd, - ), - HideFenceBorder.all => _getPathWithOpenings( - [], - Size(blockWidth, size.height), - (left: false, right: false, top: false, bottom: false), - ), - }; - - canvas.drawPath(path, paint); - - canvas.save(); - // render block label - final labelPainter = TextPainter( - text: TextSpan( - text: block.blockLabel, - style: block.blockLabelStyle ?? - const TextStyle( - color: DevfestColors.grey10, - fontWeight: FontWeight.w600, - fontSize: 12, - ), - ), - textDirection: TextDirection.ltr, - ); - - labelPainter.layout(); - // render block label - if (labelPainter.width > blockWidth) { - canvas.rotate(getRadFromDeg(-90)); - labelPainter.paint( - canvas, - Offset(-(size.height + labelPainter.width) / 2, - (blockWidth - labelPainter.height) / 2), - ); - } else { - labelPainter.paint( - canvas, - Offset((blockWidth - labelPainter.width) / 2, - (size.height - labelPainter.height) / 2), - ); - } - - canvas.restore(); - } - - Path _getPathWithOpenings(List openings, Size size, - [_AllowedEdges edges = _defaultAllowedEdges, - double horizontalPaddingFactor = 0]) { - final path = Path(); - - if (edges.left) { - final edgeOpenings = openings.where((opening) => opening.dx == 0).toList() - ..sort((a, b) => a.dy.compareTo(b.dy)); - - if (edgeOpenings.isNotEmpty) { - path.moveTo(0, 0); - for (int i = 0; i < edgeOpenings.length; i++) { - path.lineTo(0, edgeOpenings[i].dy); - path.moveTo( - 0, - edgeOpenings[i].dy + - (block.openingSizes.elementAtOrNull(i) ?? openingRadius), - ); - } - path.lineTo(0, size.height); - } else { - path.moveTo(0, 0); - path.lineTo(0, size.height); - } - } else { - path.moveTo(0, 0); - path.moveTo(0, size.height); - } - - if (edges.bottom) { - final bottomEdgeOpenings = openings - .where((opening) => opening.dy == size.height) - .toList() - ..sort((a, b) => a.dx.compareTo(b.dx)); - - if (bottomEdgeOpenings.isNotEmpty) { - path.moveTo(0, size.height); - for (int i = 0; i < bottomEdgeOpenings.length; i++) { - path.lineTo( - bottomEdgeOpenings[i].dx - horizontalPaddingFactor, size.height); - path.moveTo( - bottomEdgeOpenings[i].dx - - horizontalPaddingFactor + - (block.openingSizes.elementAtOrNull(i) ?? openingRadius), - size.height); - } - path.lineTo(size.width, size.height); - } else { - path.moveTo(0, size.height); - path.lineTo(size.width, size.height); - } - } else { - path.moveTo(0, size.height); - path.moveTo(size.width, size.height); - } - - if (edges.right) { - final edgeOpenings = openings - .where( - (opening) => opening.dx - horizontalPaddingFactor == size.width) - .toList() - ..sort((a, b) => b.dy.compareTo(a.dy)); - - if (edgeOpenings.isNotEmpty) { - path.moveTo(size.width, size.height); - for (int i = 0; i < edgeOpenings.length; i++) { - path.lineTo( - size.width, - edgeOpenings[i].dy + - (block.openingSizes.elementAtOrNull(i) ?? openingRadius)); - path.moveTo(size.width, edgeOpenings[i].dy); - } - path.lineTo(size.width, 0); - } else { - path.lineTo(size.width, 0); - } - } else { - path.moveTo(size.width, size.height); - path.moveTo(size.width, 0); - } - - if (edges.top) { - final topEdgeOpenings = openings - .where((opening) => opening.dy == 0) - .toList() - ..sort((a, b) => b.dx.compareTo(a.dx)); - - if (topEdgeOpenings.isNotEmpty) { - path.moveTo(size.width, 0); - for (int i = 0; i < topEdgeOpenings.length; i++) { - path.lineTo( - topEdgeOpenings[i].dx - - horizontalPaddingFactor + - (block.openingSizes.elementAtOrNull(i) ?? openingRadius), - 0); - path.moveTo(topEdgeOpenings[i].dx - horizontalPaddingFactor, 0); - } - - path.lineTo(0, 0); - } else { - path.moveTo(size.width, 0); - path.lineTo(0, 0); - } - } else { - path.moveTo(size.width, 0); - path.moveTo(0, 0); - } - - return path; - } - - @override - bool shouldRepaint(MapBlockPainter oldDelegate) { - return oldDelegate.block != block; - } -} - -typedef _AllowedEdges = ({bool left, bool right, bool top, bool bottom}); - -const _AllowedEdges _defaultAllowedEdges = - (left: true, right: true, top: true, bottom: true); - -extension on _AllowedEdges { - _AllowedEdges copyWith({ - bool? left, - bool? right, - bool? top, - bool? bottom, - }) { - return ( - left: left ?? this.left, - right: right ?? this.right, - top: top ?? this.top, - bottom: bottom ?? this.bottom, - ); - } -} diff --git a/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_layout.dart b/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_layout.dart deleted file mode 100644 index 5b4770b..0000000 --- a/packages/conferenceapp/lib/src/features/more/presentation/widgets/map_layout.dart +++ /dev/null @@ -1,102 +0,0 @@ -import 'package:cave/cave.dart'; - -import 'map_block.dart'; -import 'package:flutter/material.dart'; - -import '../map/map_utils.dart'; - -double cellSize = 8; - -class MapLayoutDelegate extends MultiChildLayoutDelegate { - final List blocks; - final ValueChanged>? onBlocksLayout; - - MapLayoutDelegate({ - this.blocks = const [], - this.onBlocksLayout, - }); - - double _sumBlocHeightsToIndex(int index) { - double sum = 0; - for (int i = 0; i < index; i++) { - sum += blocks[i].height; - } - return sum; - } - - @override - void performLayout(Size size) { - final blockLayouts = []; - for (int i = 0; i < blocks.length; i++) { - final block = blocks[i]; - final childId = i; - final childSize = Size(block.width, block.height); - final currentSize = layoutChild(childId, BoxConstraints.tight(childSize)); - - final childOffset = Offset( - block.position?.dx ?? 0, - size.height - - currentSize.height - - (block.position?.dy ?? _sumBlocHeightsToIndex(i)), - ); - - blockLayouts.add( - ( - room: RoomType.values[i], - start: childOffset, - end: Offset(childOffset.dx + currentSize.width, - childOffset.dy + currentSize.height), - hideFenceBorder: block.hideFenceBorder, - openings: block.openingPositions - .asMap() - .map((index, openingPosition) { - final startX = childOffset.dx + openingPosition.dx; - final startY = childOffset.dy + openingPosition.dy; - - final openingSize = - block.openingSizes.elementAtOrNull(index) ?? openingRadius; - late Offset start; - late Offset end; - - final blockStartFromEnd = - (block.entranceLabel?.isNotEmpty ?? false) ? 25.0 : 0.0; - // if is at left edge - if (openingPosition.dx == 0) { - start = Offset(startX, startY); - end = Offset(startX, startY + openingSize); - } // if is at right edge - else if (openingPosition.dx - blockStartFromEnd == - block.width) { - start = Offset(startX, startY); - end = Offset(startX, startY + openingSize); - } // if is at top edge - else if (openingPosition.dy == 0) { - start = Offset(startX - blockStartFromEnd, startY); - end = - Offset(startX + openingSize - blockStartFromEnd, startY); - } // if is at bottom edge - else { - start = - Offset(startX - blockStartFromEnd, startY - cellSize.w); - end = Offset(startX + openingSize - blockStartFromEnd, - startY - cellSize.w); - } - - return MapEntry(index, (start: start, end: end)); - }) - .values - .toList(), - ), - ); - - positionChild(childId, childOffset); - } - - onBlocksLayout?.call(blockLayouts); - } - - @override - bool shouldRelayout(MapLayoutDelegate oldDelegate) { - return oldDelegate.blocks != blocks; - } -} diff --git a/packages/conferenceapp/lib/src/shared/extensions.dart b/packages/conferenceapp/lib/src/shared/extensions.dart index 4ea5b24..b192a35 100644 --- a/packages/conferenceapp/lib/src/shared/extensions.dart +++ b/packages/conferenceapp/lib/src/shared/extensions.dart @@ -25,6 +25,7 @@ extension DevfestColorsX on Color { DevfestColors.grey80 || DevfestColors.warning100 => DevfestColors.backgroundDark, + const Color(0xfffffaeb) => DevfestColors.backgroundDark, _ => this, }; } diff --git a/packages/conferenceapp/pubspec.lock b/packages/conferenceapp/pubspec.lock index daa616b..536b6ca 100644 --- a/packages/conferenceapp/pubspec.lock +++ b/packages/conferenceapp/pubspec.lock @@ -647,6 +647,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.28.0" + schematics: + dependency: "direct main" + description: + name: schematics + sha256: "4914d8f85b4462b8d61bedfd26a4656bb32ec1bceec920ed792d0f5edc112c2c" + url: "https://pub.dev" + source: hosted + version: "1.0.0-dev.1.5" shared_preferences: dependency: "direct main" description: diff --git a/packages/conferenceapp/pubspec.yaml b/packages/conferenceapp/pubspec.yaml index 2554fbf..fe28f1d 100644 --- a/packages/conferenceapp/pubspec.yaml +++ b/packages/conferenceapp/pubspec.yaml @@ -30,6 +30,7 @@ dependencies: shared_preferences: ^2.3.3 shorebird_code_push: ^1.1.6 url_launcher: ^6.3.1 + schematics: ^1.0.0-dev.1.5 dependency_overrides: firebase_core: 3.3.0 diff --git a/packages/conferenceapp/test/map_directions_instructions_test.dart b/packages/conferenceapp/test/map_directions_instructions_test.dart deleted file mode 100644 index 123cc4c..0000000 --- a/packages/conferenceapp/test/map_directions_instructions_test.dart +++ /dev/null @@ -1,701 +0,0 @@ -import 'package:devfest24/src/features/more/presentation/map/map_utils.dart'; -import 'package:flutter_test/flutter_test.dart'; - -void main() { - group('Landmark map directions test suite', () { - test('Exhibition room to destination rooms', () { - RoomType start = RoomType.exhibitionRoom; - RoomType end = RoomType.room4; - - List directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.exhibitionRoom, - RoomType.room1, - RoomType.room2, - RoomType.hallway, - RoomType.stairs, - RoomType.room4 - ], - ); - - // room 1 - end = RoomType.room3; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.exhibitionRoom, - RoomType.room1, - RoomType.room2, - RoomType.hallway, - RoomType.stairs, - RoomType.room3 - ], - ); - - // stairway - end = RoomType.stairs; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.exhibitionRoom, - RoomType.room1, - RoomType.room2, - RoomType.hallway, - RoomType.stairs - ], - ); - - // hallway - end = RoomType.hallway; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.exhibitionRoom, - RoomType.room1, - RoomType.room2, - RoomType.hallway - ], - ); - - // toilet - end = RoomType.toilet; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.exhibitionRoom, - RoomType.room1, - RoomType.room2, - RoomType.hallway, - RoomType.toilet - ], - ); - - // room 2 - end = RoomType.room2; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.exhibitionRoom, RoomType.room1, RoomType.room2], - ); - - // room 1 - end = RoomType.room1; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.exhibitionRoom, RoomType.room1], - ); - }); - - test('Room 1 to destination rooms', () { - RoomType start = RoomType.room1; - RoomType end = RoomType.room4; - - List directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.room1, - RoomType.room2, - RoomType.hallway, - RoomType.stairs, - RoomType.room4, - ], - ); - - // room 3 - end = RoomType.room3; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.room1, - RoomType.room2, - RoomType.hallway, - RoomType.stairs, - RoomType.room3, - ], - ); - - // stairway - end = RoomType.stairs; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.room1, - RoomType.room2, - RoomType.hallway, - RoomType.stairs, - ], - ); - - // hallway - end = RoomType.hallway; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.room1, - RoomType.room2, - RoomType.hallway, - ], - ); - - // toilet - end = RoomType.toilet; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.room1, - RoomType.room2, - RoomType.hallway, - RoomType.toilet, - ], - ); - - // hallway - end = RoomType.hallway; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.room1, - RoomType.room2, - RoomType.hallway, - ], - ); - - // room 2 - end = RoomType.room2; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room1, RoomType.room2], - ); - - // room 1 - end = RoomType.room1; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room1], - ); - - // exhibition room - end = RoomType.exhibitionRoom; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room1, RoomType.exhibitionRoom], - ); - }); - - test('Room 2 to destination rooms', () { - RoomType start = RoomType.room2; - RoomType end = RoomType.room4; - - List directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room2, RoomType.hallway, RoomType.stairs, RoomType.room4], - ); - - // room 3 - end = RoomType.room3; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room2, RoomType.hallway, RoomType.stairs, RoomType.room3], - ); - - // stairway - end = RoomType.stairs; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room2, RoomType.hallway, RoomType.stairs], - ); - - // hallway - end = RoomType.hallway; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room2, RoomType.hallway], - ); - - // toilet - end = RoomType.toilet; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room2, RoomType.hallway, RoomType.toilet], - ); - - // room 1 - end = RoomType.room1; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room2, RoomType.room1], - ); - - // exhibition room - end = RoomType.exhibitionRoom; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room2, RoomType.room1, RoomType.exhibitionRoom], - ); - }); - - test('Hallway to destination rooms', () { - RoomType start = RoomType.hallway; - RoomType end = RoomType.room4; - - List directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.hallway, RoomType.stairs, RoomType.room4], - ); - - // room 3 - end = RoomType.room3; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.hallway, RoomType.stairs, RoomType.room3], - ); - - // stairway - end = RoomType.stairs; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.hallway, RoomType.stairs], - ); - - // toilet - end = RoomType.toilet; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.hallway, RoomType.toilet], - ); - - // hallway - end = RoomType.hallway; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.hallway], - ); - - // room 2 - end = RoomType.room2; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.hallway, RoomType.room2], - ); - - // room 1 - end = RoomType.room1; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.hallway, RoomType.room2, RoomType.room1], - ); - - // exhibition room - end = RoomType.exhibitionRoom; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.hallway, - RoomType.room2, - RoomType.room1, - RoomType.exhibitionRoom - ], - ); - }); - - test('Stairway to destination rooms', () { - RoomType start = RoomType.stairs; - RoomType end = RoomType.room4; - - List directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.stairs, RoomType.room4], - ); - - // room 3 - end = RoomType.room3; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.stairs, RoomType.room3], - ); - - // stairway - end = RoomType.stairs; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.stairs], - ); - - // toilet - end = RoomType.toilet; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.stairs, RoomType.hallway, RoomType.toilet], - ); - - // hallway - end = RoomType.hallway; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.stairs, RoomType.hallway], - ); - - // room 2 - end = RoomType.room2; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.stairs, RoomType.hallway, RoomType.room2], - ); - - // room 1 - end = RoomType.room1; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.stairs, RoomType.hallway, RoomType.room2, RoomType.room1], - ); - - // exhibition room - end = RoomType.exhibitionRoom; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.stairs, - RoomType.hallway, - RoomType.room2, - RoomType.room1, - RoomType.exhibitionRoom - ], - ); - }); - - test('Toilet to destination rooms', () { - RoomType start = RoomType.toilet; - RoomType end = RoomType.room4; - - List directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.toilet, RoomType.hallway, RoomType.stairs, RoomType.room4], - ); - - // room 3 - end = RoomType.room3; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.toilet, RoomType.hallway, RoomType.stairs, RoomType.room3], - ); - - // stairway - end = RoomType.stairs; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.toilet, RoomType.hallway, RoomType.stairs], - ); - - // hallway - end = RoomType.hallway; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.toilet, RoomType.hallway], - ); - - // toilet - end = RoomType.toilet; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.toilet], - ); - - // room 2 - end = RoomType.room2; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.toilet, RoomType.hallway, RoomType.room2], - ); - - // room 1 - end = RoomType.room1; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.toilet, RoomType.hallway, RoomType.room2, RoomType.room1], - ); - - // exhibition room - end = RoomType.exhibitionRoom; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.toilet, - RoomType.hallway, - RoomType.room2, - RoomType.room1, - RoomType.exhibitionRoom - ], - ); - }); - - test('Room 3 to destination rooms', () { - RoomType start = RoomType.room3; - RoomType end = RoomType.room4; - - List directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room3, RoomType.stairs, RoomType.room4], - ); - - // room 3 - end = RoomType.room3; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room3], - ); - - // stairway - end = RoomType.stairs; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room3, RoomType.stairs], - ); - - // hallway - end = RoomType.hallway; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room3, RoomType.stairs, RoomType.hallway], - ); - - // toilet - end = RoomType.toilet; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room3, RoomType.stairs, RoomType.hallway, RoomType.toilet], - ); - - // room 2 - end = RoomType.room2; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room3, RoomType.stairs, RoomType.hallway, RoomType.room2], - ); - - // room 1 - end = RoomType.room1; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.room3, - RoomType.stairs, - RoomType.hallway, - RoomType.room2, - RoomType.room1 - ], - ); - - // exhibition room - end = RoomType.exhibitionRoom; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.room3, - RoomType.stairs, - RoomType.hallway, - RoomType.room2, - RoomType.room1, - RoomType.exhibitionRoom - ], - ); - }); - - test('Room 4 to destination rooms', () { - RoomType start = RoomType.room4; - RoomType end = RoomType.room4; - - List directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room4], - ); - - // room 3 - end = RoomType.room3; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room4, RoomType.stairs, RoomType.room3], - ); - - // stairway - end = RoomType.stairs; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room4, RoomType.stairs], - ); - - // hallway - end = RoomType.hallway; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room4, RoomType.stairs, RoomType.hallway], - ); - - // toilet - end = RoomType.toilet; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room4, RoomType.stairs, RoomType.hallway, RoomType.toilet], - ); - - // room 2 - end = RoomType.room2; - directions = getOverviewDirections(start, end); - - expect( - directions, - [RoomType.room4, RoomType.stairs, RoomType.hallway, RoomType.room2], - ); - - // room 1 - end = RoomType.room1; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.room4, - RoomType.stairs, - RoomType.hallway, - RoomType.room2, - RoomType.room1 - ], - ); - - // exhibition room - end = RoomType.exhibitionRoom; - directions = getOverviewDirections(start, end); - - expect( - directions, - [ - RoomType.room4, - RoomType.stairs, - RoomType.hallway, - RoomType.room2, - RoomType.room1, - RoomType.exhibitionRoom - ], - ); - }); - }); -}