import 'package:flutter/material.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:sudoku/cubit/game_cubit.dart'; import 'package:sudoku/models/game/cell.dart'; import 'package:sudoku/models/game/game.dart'; class CellWidget extends StatelessWidget { const CellWidget({super.key, required this.cell}); final Cell cell; @override Widget build(BuildContext context) { return BlocBuilder<GameCubit, GameState>( builder: (BuildContext context, GameState gameState) { final Game game = gameState.currentGame; final String imageAsset = getImageAssetName(game); return Container( decoration: BoxDecoration( color: getBackgroundColor(game), border: getCellBorders(game), ), child: GestureDetector( child: AnimatedSwitcher( duration: const Duration(milliseconds: 100), transitionBuilder: (Widget child, Animation<double> animation) { return ScaleTransition(scale: animation, child: child); }, child: Image( image: AssetImage(imageAsset), fit: BoxFit.fill, key: ValueKey<int>(imageAsset.hashCode), ), ), onTap: () { final GameCubit gameCubit = BlocProvider.of<GameCubit>(context); if (cell.location.col != game.selectedCell?.location.col || cell.location.row != game.selectedCell?.location.row) { gameCubit.selectCell(cell.location); } else { gameCubit.unselectCell(); } }, ), ); }, ); } /* * Compute image asset name, from skin and cell value/state */ String getImageAssetName(Game game) { if ((cell.value) > 0) { final int cellValue = game.getTranslatedValueForDisplay(cell.value); return 'assets/skins/${game.globalSettings.skin}_$cellValue.png'; } return 'assets/ui/cell_empty.png'; } // Compute cell background color, from cell state Color getBackgroundColor(Game game) { final Color editableCellColor = Colors.grey.shade100; final Color editableCellColorConflict = Colors.pink.shade100; final Color fixedCellColor = Colors.grey.shade300; final Color fixedCellColorConflict = Colors.pink.shade200; final Color editableSelectedValueColor = Colors.green.shade100; final Color fixedSelectedValueColor = Colors.green.shade300; final Color editableAnimated = Colors.green.shade200; final Color fixedAnimated = Colors.green.shade300; Color backgroundColor = editableCellColor; if (cell.isFixed == true) { backgroundColor = fixedCellColor; } final int conflictsCount = game.boardConflicts[cell.location.row][cell.location.col]; if (game.showConflicts == true) { if (conflictsCount != 0) { if (cell.isFixed == true) { backgroundColor = fixedCellColorConflict; } else { backgroundColor = editableCellColorConflict; } } if ((cell.value != 0) && (cell.value == game.selectedCell?.value)) { if (cell.isFixed == true) { backgroundColor = fixedSelectedValueColor; } else { backgroundColor = editableSelectedValueColor; } } } final bool isAnimated = game.boardAnimated[cell.location.row][cell.location.col]; if (isAnimated) { if (cell.isFixed == true) { backgroundColor = fixedAnimated; } else { backgroundColor = editableAnimated; } } return backgroundColor; } // Compute cell borders, from board size and cell state Border getCellBorders(Game game) { final Color cellBorderDarkColor = Colors.grey.shade800; final Color cellBorderLightColor = Colors.grey.shade600; const Color cellBorderSelectedColor = Colors.red; Color cellBorderColor = cellBorderSelectedColor; double cellBorderWidth = 4; // Reduce cell border width on big boards if (game.boardSize > 8) { cellBorderWidth = 2; if (game.boardSize > 10) { cellBorderWidth = 1; } } if (!game.isRunning) { cellBorderColor = Colors.green.shade700; } Border borders = Border.all( color: cellBorderColor, width: cellBorderWidth, ); // Update cell borders if not currently selected cell if (cell.location.col != game.selectedCell?.location.col || cell.location.row != game.selectedCell?.location.row) { borders = Border( top: BorderSide( width: cellBorderWidth, color: (((cell.location.row) % game.blockSizeVertical) == 0) ? cellBorderDarkColor : cellBorderLightColor), left: BorderSide( width: cellBorderWidth, color: (((cell.location.col) % game.blockSizeHorizontal) == 0) ? cellBorderDarkColor : cellBorderLightColor), right: BorderSide( width: cellBorderWidth, color: ((((cell.location.col) + 1) % game.blockSizeHorizontal) == 0) ? cellBorderDarkColor : cellBorderLightColor), bottom: BorderSide( width: cellBorderWidth, color: ((((cell.location.row) + 1) % game.blockSizeVertical) == 0) ? cellBorderDarkColor : cellBorderLightColor), ); } return borders; } }