From 35ef78d69ccb77ea8dd2b2a15f2e118d5e3ddb1d Mon Sep 17 00:00:00 2001 From: CodeDoctorDE Date: Fri, 9 Aug 2024 23:29:21 +0200 Subject: [PATCH] Add colorscheme system to states --- app/lib/bloc/board.dart | 4 + app/lib/bloc/board_event.dart | 9 +++ app/lib/bloc/board_event.mapper.dart | 111 +++++++++++++++++++++++++++ app/lib/bloc/board_state.dart | 3 + app/lib/bloc/board_state.mapper.dart | 9 +++ app/lib/board/cell.dart | 4 +- app/lib/board/game.dart | 7 +- app/lib/board/hand/item.dart | 37 ++++++--- app/lib/board/hand/view.dart | 22 +++--- app/lib/models/translation.dart | 2 +- 10 files changed, 182 insertions(+), 26 deletions(-) diff --git a/app/lib/bloc/board.dart b/app/lib/bloc/board.dart index adbef7a..9ee71ca 100644 --- a/app/lib/bloc/board.dart +++ b/app/lib/bloc/board.dart @@ -18,6 +18,10 @@ class BoardBloc extends Bloc { data: data ?? QuokkaData.empty(), table: table ?? data?.getTable() ?? const GameTable(), )) { + on((event, emit) { + emit(state.copyWith(colorScheme: event.colorScheme)); + return save(); + }); on((event, emit) { emit(state.copyWith( showHand: event.show ?? (!state.showHand), diff --git a/app/lib/bloc/board_event.dart b/app/lib/bloc/board_event.dart index 61b4cbd..5685d3d 100644 --- a/app/lib/bloc/board_event.dart +++ b/app/lib/bloc/board_event.dart @@ -1,4 +1,5 @@ import 'package:dart_mappable/dart_mappable.dart'; +import 'package:flutter/material.dart'; import 'package:quokka/models/table.dart'; import 'package:quokka/models/vector.dart'; @@ -15,6 +16,14 @@ final class CellSwitched extends BoardEvent with CellSwitchedMappable { CellSwitched(this.cell, {this.toggle = false}); } +@MappableClass() +final class ColorSchemeChanged extends BoardEvent + with ColorSchemeChangedMappable { + final ColorScheme? colorScheme; + + ColorSchemeChanged(this.colorScheme); +} + @MappableClass() final class HandChanged extends BoardEvent with HandChangedMappable { final ItemLocation? deck; diff --git a/app/lib/bloc/board_event.mapper.dart b/app/lib/bloc/board_event.mapper.dart index bef60fc..0da3479 100644 --- a/app/lib/bloc/board_event.mapper.dart +++ b/app/lib/bloc/board_event.mapper.dart @@ -14,6 +14,7 @@ class BoardEventMapper extends ClassMapperBase { if (_instance == null) { MapperContainer.globals.use(_instance = BoardEventMapper._()); CellSwitchedMapper.ensureInitialized(); + ColorSchemeChangedMapper.ensureInitialized(); HandChangedMapper.ensureInitialized(); ObjectsSpawnedMapper.ensureInitialized(); ObjectsMovedMapper.ensureInitialized(); @@ -171,6 +172,116 @@ class _CellSwitchedCopyWithImpl<$R, $Out> _CellSwitchedCopyWithImpl($value, $cast, t); } +class ColorSchemeChangedMapper extends ClassMapperBase { + ColorSchemeChangedMapper._(); + + static ColorSchemeChangedMapper? _instance; + static ColorSchemeChangedMapper ensureInitialized() { + if (_instance == null) { + MapperContainer.globals.use(_instance = ColorSchemeChangedMapper._()); + BoardEventMapper.ensureInitialized(); + } + return _instance!; + } + + @override + final String id = 'ColorSchemeChanged'; + + static ColorScheme? _$colorScheme(ColorSchemeChanged v) => v.colorScheme; + static const Field _f$colorScheme = + Field('colorScheme', _$colorScheme); + + @override + final MappableFields fields = const { + #colorScheme: _f$colorScheme, + }; + + static ColorSchemeChanged _instantiate(DecodingData data) { + return ColorSchemeChanged(data.dec(_f$colorScheme)); + } + + @override + final Function instantiate = _instantiate; + + static ColorSchemeChanged fromMap(Map map) { + return ensureInitialized().decodeMap(map); + } + + static ColorSchemeChanged fromJson(String json) { + return ensureInitialized().decodeJson(json); + } +} + +mixin ColorSchemeChangedMappable { + String toJson() { + return ColorSchemeChangedMapper.ensureInitialized() + .encodeJson(this as ColorSchemeChanged); + } + + Map toMap() { + return ColorSchemeChangedMapper.ensureInitialized() + .encodeMap(this as ColorSchemeChanged); + } + + ColorSchemeChangedCopyWith + get copyWith => _ColorSchemeChangedCopyWithImpl( + this as ColorSchemeChanged, $identity, $identity); + @override + String toString() { + return ColorSchemeChangedMapper.ensureInitialized() + .stringifyValue(this as ColorSchemeChanged); + } + + @override + bool operator ==(Object other) { + return ColorSchemeChangedMapper.ensureInitialized() + .equalsValue(this as ColorSchemeChanged, other); + } + + @override + int get hashCode { + return ColorSchemeChangedMapper.ensureInitialized() + .hashValue(this as ColorSchemeChanged); + } +} + +extension ColorSchemeChangedValueCopy<$R, $Out> + on ObjectCopyWith<$R, ColorSchemeChanged, $Out> { + ColorSchemeChangedCopyWith<$R, ColorSchemeChanged, $Out> + get $asColorSchemeChanged => + $base.as((v, t, t2) => _ColorSchemeChangedCopyWithImpl(v, t, t2)); +} + +abstract class ColorSchemeChangedCopyWith<$R, $In extends ColorSchemeChanged, + $Out> implements BoardEventCopyWith<$R, $In, $Out> { + @override + $R call({ColorScheme? colorScheme}); + ColorSchemeChangedCopyWith<$R2, $In, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t); +} + +class _ColorSchemeChangedCopyWithImpl<$R, $Out> + extends ClassCopyWithBase<$R, ColorSchemeChanged, $Out> + implements ColorSchemeChangedCopyWith<$R, ColorSchemeChanged, $Out> { + _ColorSchemeChangedCopyWithImpl(super.value, super.then, super.then2); + + @override + late final ClassMapperBase $mapper = + ColorSchemeChangedMapper.ensureInitialized(); + @override + $R call({Object? colorScheme = $none}) => $apply( + FieldCopyWithData({if (colorScheme != $none) #colorScheme: colorScheme})); + @override + ColorSchemeChanged $make(CopyWithData data) => + ColorSchemeChanged(data.get(#colorScheme, or: $value.colorScheme)); + + @override + ColorSchemeChangedCopyWith<$R2, ColorSchemeChanged, $Out2> $chain<$R2, $Out2>( + Then<$Out2, $R2> t) => + _ColorSchemeChangedCopyWithImpl($value, $cast, t); +} + class HandChangedMapper extends ClassMapperBase { HandChangedMapper._(); diff --git a/app/lib/bloc/board_state.dart b/app/lib/bloc/board_state.dart index 2947624..2b7dee7 100644 --- a/app/lib/bloc/board_state.dart +++ b/app/lib/bloc/board_state.dart @@ -1,4 +1,5 @@ import 'package:dart_mappable/dart_mappable.dart'; +import 'package:flutter/material.dart'; import 'package:quokka/models/data.dart'; import 'package:quokka/models/table.dart'; import 'package:quokka/models/vector.dart'; @@ -8,6 +9,7 @@ part 'board_state.mapper.dart'; @MappableClass() class BoardState with BoardStateMappable { + final ColorScheme? colorScheme; final QuokkaFileSystem fileSystem; final GameTable table; final VectorDefinition? selectedCell; @@ -19,6 +21,7 @@ class BoardState with BoardStateMappable { const BoardState({ required this.fileSystem, this.name, + this.colorScheme, this.table = const GameTable(), this.selectedCell, this.selectedDeck, diff --git a/app/lib/bloc/board_state.mapper.dart b/app/lib/bloc/board_state.mapper.dart index 1d8d09c..c2c36b5 100644 --- a/app/lib/bloc/board_state.mapper.dart +++ b/app/lib/bloc/board_state.mapper.dart @@ -29,6 +29,9 @@ class BoardStateMapper extends ClassMapperBase { static String? _$name(BoardState v) => v.name; static const Field _f$name = Field('name', _$name, opt: true); + static ColorScheme? _$colorScheme(BoardState v) => v.colorScheme; + static const Field _f$colorScheme = + Field('colorScheme', _$colorScheme, opt: true); static GameTable _$table(BoardState v) => v.table; static const Field _f$table = Field('table', _$table, opt: true, def: const GameTable()); @@ -48,6 +51,7 @@ class BoardStateMapper extends ClassMapperBase { final MappableFields fields = const { #fileSystem: _f$fileSystem, #name: _f$name, + #colorScheme: _f$colorScheme, #table: _f$table, #selectedCell: _f$selectedCell, #selectedDeck: _f$selectedDeck, @@ -59,6 +63,7 @@ class BoardStateMapper extends ClassMapperBase { return BoardState( fileSystem: data.dec(_f$fileSystem), name: data.dec(_f$name), + colorScheme: data.dec(_f$colorScheme), table: data.dec(_f$table), selectedCell: data.dec(_f$selectedCell), selectedDeck: data.dec(_f$selectedDeck), @@ -124,6 +129,7 @@ abstract class BoardStateCopyWith<$R, $In extends BoardState, $Out> $R call( {QuokkaFileSystem? fileSystem, String? name, + ColorScheme? colorScheme, GameTable? table, VectorDefinition? selectedCell, ItemLocation? selectedDeck, @@ -154,6 +160,7 @@ class _BoardStateCopyWithImpl<$R, $Out> $R call( {QuokkaFileSystem? fileSystem, Object? name = $none, + Object? colorScheme = $none, GameTable? table, Object? selectedCell = $none, Object? selectedDeck = $none, @@ -162,6 +169,7 @@ class _BoardStateCopyWithImpl<$R, $Out> $apply(FieldCopyWithData({ if (fileSystem != null) #fileSystem: fileSystem, if (name != $none) #name: name, + if (colorScheme != $none) #colorScheme: colorScheme, if (table != null) #table: table, if (selectedCell != $none) #selectedCell: selectedCell, if (selectedDeck != $none) #selectedDeck: selectedDeck, @@ -172,6 +180,7 @@ class _BoardStateCopyWithImpl<$R, $Out> BoardState $make(CopyWithData data) => BoardState( fileSystem: data.get(#fileSystem, or: $value.fileSystem), name: data.get(#name, or: $value.name), + colorScheme: data.get(#colorScheme, or: $value.colorScheme), table: data.get(#table, or: $value.table), selectedCell: data.get(#selectedCell, or: $value.selectedCell), selectedDeck: data.get(#selectedDeck, or: $value.selectedDeck), diff --git a/app/lib/board/cell.dart b/app/lib/board/cell.dart index 48fdfe0..0052c9d 100644 --- a/app/lib/board/cell.dart +++ b/app/lib/board/cell.dart @@ -114,9 +114,7 @@ class GameCell extends PositionComponent final controller = EffectController( duration: 0.1, ); - final context = game.buildContext; - final color = - context == null ? Colors.green : Theme.of(context).colorScheme.primary; + final color = state.colorScheme?.primary ?? Colors.green.withOpacity(0.5); if (selected) { _updateEffects([ OpacityEffect.to(1, controller), diff --git a/app/lib/board/game.dart b/app/lib/board/game.dart index d988db8..9834227 100644 --- a/app/lib/board/game.dart +++ b/app/lib/board/game.dart @@ -50,7 +50,7 @@ class BoardGame extends FlameGame with ScrollDetector, KeyboardEvents { } @override - void onMount() { + void onAttach() { _updateLocale(); } @@ -82,6 +82,11 @@ class BoardGame extends FlameGame with ScrollDetector, KeyboardEvents { if (!_currentCameraVelocity.isZero()) { camera.moveBy(_currentCameraVelocity * dt * 60); } + final nextColorScheme = + buildContext != null ? Theme.of(buildContext!).colorScheme : null; + if (nextColorScheme != bloc.state.colorScheme) { + bloc.add(ColorSchemeChanged(nextColorScheme)); + } } @override diff --git a/app/lib/board/hand/item.dart b/app/lib/board/hand/item.dart index cb3a4ca..a268cd6 100644 --- a/app/lib/board/hand/item.dart +++ b/app/lib/board/hand/item.dart @@ -1,6 +1,7 @@ import 'package:flame/components.dart'; import 'package:flame/events.dart'; import 'package:flame_bloc/flame_bloc.dart'; +import 'package:flutter/material.dart' show Colors; import 'package:flutter/painting.dart'; import 'package:quokka/bloc/board.dart'; import 'package:quokka/bloc/board_state.dart'; @@ -16,9 +17,10 @@ abstract class HandItem extends PositionComponent HasGameRef, DragCallbacks, LongDragCallbacks, - FlameBlocReader { + FlameBlocListenable { final T item; late final SpriteComponent _sprite; + late final TextComponent _label; Vector2 _lastPos = Vector2.zero(); HandItem({required this.item}) : super(size: Vector2(100, 0)); @@ -36,15 +38,6 @@ abstract class HandItem extends PositionComponent @override Future onLoad() async { super.onLoad(); - add(TextComponent( - text: label, - size: Vector2(0, labelHeight), - position: Vector2(50, 0), - anchor: Anchor.topCenter, - textRenderer: TextPaint( - style: const TextStyle(fontSize: 14), - ), - )); _sprite = SpriteComponent( position: Vector2(0, labelHeight), size: Vector2(100, 0), @@ -53,6 +46,30 @@ abstract class HandItem extends PositionComponent add(_sprite); } + @override + bool listenWhen(BoardState previousState, BoardState newState) => + previousState.colorScheme != newState.colorScheme; + + @override + void onInitialState(BoardState state) { + add(_label = TextComponent( + text: label, + size: Vector2(0, labelHeight), + position: Vector2(50, 0), + anchor: Anchor.topCenter, + textRenderer: _buildPaint(state))); + } + + _buildPaint([BoardState? state]) => TextPaint( + style: TextStyle( + fontSize: 14, color: state?.colorScheme?.onSurface ?? Colors.white), + ); + + @override + void onNewState(BoardState state) { + _label.textRenderer = _buildPaint(state); + } + @override void onParentResize(Vector2 maxSize) { height = maxSize.y; diff --git a/app/lib/board/hand/view.dart b/app/lib/board/hand/view.dart index fde4c08..de61d69 100644 --- a/app/lib/board/hand/view.dart +++ b/app/lib/board/hand/view.dart @@ -5,7 +5,7 @@ import 'package:flame/components.dart'; import 'package:flame/events.dart'; import 'package:flame_bloc/flame_bloc.dart'; import 'package:flutter/material.dart' - show CustomPainter, Colors, Canvas, Size, Paint, PaintingStyle, Rect; + show Canvas, Color, Colors, CustomPainter, Paint, PaintingStyle, Rect, Size; import 'package:quokka/bloc/board.dart'; import 'package:quokka/bloc/board_state.dart'; import 'package:quokka/board/game.dart'; @@ -22,14 +22,15 @@ import 'package:quokka/models/vector.dart'; class GameHandCustomPainter extends CustomPainter { final bool showHand; + final Color color; - GameHandCustomPainter({this.showHand = false}); + GameHandCustomPainter({this.showHand = false, this.color = Colors.black}); @override void paint(Canvas canvas, Size size) { if (!showHand) return; final paint = Paint() - ..color = Colors.black + ..color = color ..style = PaintingStyle.fill ..strokeWidth = 2; canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint); @@ -37,7 +38,7 @@ class GameHandCustomPainter extends CustomPainter { @override bool shouldRepaint(GameHandCustomPainter oldDelegate) => - showHand != oldDelegate.showHand; + showHand != oldDelegate.showHand || color != oldDelegate.color; } class GameHand extends CustomPainterComponent @@ -50,11 +51,7 @@ class GameHand extends CustomPainterComponent double _nextItemPos = 0; final _itemsChild = PositionComponent(); - GameHand() - : super( - anchor: Anchor.topLeft, - painter: GameHandCustomPainter(), - ); + GameHand() : super(anchor: Anchor.topLeft, painter: GameHandCustomPainter()); @override void onLoad() { @@ -81,13 +78,16 @@ class GameHand extends CustomPainterComponent previousState.selectedDeck != newState.selectedDeck || previousState.selectedCell != newState.selectedCell || previousState.table.cells[previousState.selectedCell] != - newState.table.cells[newState.selectedCell]; + newState.table.cells[newState.selectedCell] || + previousState.colorScheme != newState.colorScheme; void _buildHand(BoardState state) { _itemsChild.children .whereType() .forEach((e) => e.removeFromParent()); - painter = GameHandCustomPainter(showHand: state.showHand); + painter = GameHandCustomPainter( + showHand: state.showHand, + color: state.colorScheme?.surface ?? Colors.black); if (!state.showHand) return; _itemsChild.x = 0; final selected = state.selectedCell; diff --git a/app/lib/models/translation.dart b/app/lib/models/translation.dart index 2c43bd2..9f22370 100644 --- a/app/lib/models/translation.dart +++ b/app/lib/models/translation.dart @@ -13,7 +13,7 @@ class TranslationsStore { PackTranslation getTranslation([String? locale]) => (locale == null ? null : translations[locale]) ?? - translations[this.getLocale()] ?? + translations[getLocale()] ?? PackTranslation(); T findTranslation(T? Function(PackTranslation) finder, T fallback,