...
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
// packages/feature_game_sudoku/lib/widgets/number_pad.dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:service_api/service_api.dart'; // 👈 SudokuTheme import
|
||||
|
||||
class NumberPad extends StatelessWidget {
|
||||
final int blockSize;
|
||||
final SudokuTheme theme;
|
||||
final Map<int, int> numberCounts;
|
||||
final int? selectedNumber;
|
||||
final Function(int) onNumberTapped;
|
||||
final bool isLandscape;
|
||||
|
||||
const NumberPad({
|
||||
super.key,
|
||||
required this.blockSize,
|
||||
required this.theme,
|
||||
required this.numberCounts,
|
||||
required this.selectedNumber,
|
||||
required this.onNumberTapped,
|
||||
required this.isLandscape,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final int gridSize = blockSize * blockSize;
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
final bool isDark = themeData.brightness == Brightness.dark;
|
||||
|
||||
final Color selectedColor = themeData.primaryColor;
|
||||
final Color onSelectedColor = themeData.colorScheme.onPrimary;
|
||||
|
||||
final Color completedColor = isDark ? Colors.white24 : Colors.black26;
|
||||
final Color completedTextColor = isDark ? Colors.white54 : Colors.black54;
|
||||
|
||||
final Color defaultTextColor = isDark ? Colors.white70 : Colors.black87;
|
||||
|
||||
List<Widget> numberButtons = List.generate(gridSize, (index) {
|
||||
int numberValue = index + 1;
|
||||
String numberSymbol = theme.getSymbol(numberValue);
|
||||
bool isSelected = (numberValue == selectedNumber);
|
||||
bool isCompleted = (numberCounts[numberValue] ?? 0) >= gridSize;
|
||||
|
||||
Widget button = ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: isSelected ? selectedColor : null,
|
||||
foregroundColor: isSelected ? onSelectedColor : defaultTextColor,
|
||||
disabledBackgroundColor: completedColor,
|
||||
disabledForegroundColor: completedTextColor,
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
textStyle: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))
|
||||
),
|
||||
onPressed: isCompleted
|
||||
? null
|
||||
: () => onNumberTapped(numberValue),
|
||||
child: FittedBox(
|
||||
fit: BoxFit.contain,
|
||||
child: Text(numberSymbol),
|
||||
),
|
||||
);
|
||||
|
||||
if (isLandscape) {
|
||||
return Flexible(child: button);
|
||||
} else {
|
||||
return button;
|
||||
}
|
||||
});
|
||||
|
||||
if (isLandscape) {
|
||||
return Wrap(
|
||||
runSpacing: 4.0,
|
||||
spacing: 4.0,
|
||||
children: numberButtons,
|
||||
);
|
||||
} else {
|
||||
return GridView.count(
|
||||
crossAxisCount: blockSize,
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.zero,
|
||||
mainAxisSpacing: 4,
|
||||
crossAxisSpacing: 4,
|
||||
children: numberButtons,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
// packages/feature_game_sudoku/lib/widgets/sudoku_board.dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:service_api/service_api.dart'; // 👈 SudokuTheme import
|
||||
|
||||
class SudokuBoard extends StatelessWidget {
|
||||
final int blockSize;
|
||||
final SudokuTheme theme;
|
||||
final List<int> cells;
|
||||
final List<int> originalCells;
|
||||
final int? selectedIndex;
|
||||
final int? selectedNumberPad;
|
||||
final Set<int> incorrectCells;
|
||||
final Function(int) onCellTapped;
|
||||
|
||||
const SudokuBoard({
|
||||
super.key,
|
||||
required this.blockSize,
|
||||
required this.theme,
|
||||
required this.cells,
|
||||
required this.originalCells,
|
||||
required this.selectedIndex,
|
||||
required this.selectedNumberPad,
|
||||
required this.incorrectCells,
|
||||
required this.onCellTapped,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final int gridSize = blockSize * blockSize;
|
||||
final double fontSize = (gridSize > 9) ? (gridSize > 16 ? 12 : 16) : 24;
|
||||
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
final ColorScheme colorScheme = themeData.colorScheme;
|
||||
final bool isDark = themeData.brightness == Brightness.dark;
|
||||
|
||||
final Color thickBorderColor = colorScheme.onSurface.withOpacity(isDark ? 0.8 : 1.0);
|
||||
final Color thinBorderColor = themeData.dividerColor;
|
||||
|
||||
final Color incorrectBg = colorScheme.error.withOpacity(0.2);
|
||||
final Color highlightedBg = colorScheme.primary.withOpacity(0.2);
|
||||
final Color editableBg = themeData.scaffoldBackgroundColor;
|
||||
final Color fixedBg = isDark ? colorScheme.surfaceVariant : colorScheme.onSurface.withOpacity(0.1);
|
||||
|
||||
final Color selectedTextColor = colorScheme.secondary;
|
||||
final Color incorrectTextColor = colorScheme.error;
|
||||
final Color editableTextColor = colorScheme.primary;
|
||||
final Color fixedTextColor = colorScheme.onSurface;
|
||||
|
||||
return AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: GridView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: gridSize,
|
||||
),
|
||||
itemCount: gridSize * gridSize,
|
||||
itemBuilder: (context, index) {
|
||||
int row = index ~/ gridSize;
|
||||
int col = index % gridSize;
|
||||
|
||||
int cellValue = cells[index];
|
||||
bool isEditable = (originalCells[index] == 0);
|
||||
bool isSelected = (index == selectedIndex);
|
||||
|
||||
bool isHighlighted = (cellValue != 0 &&
|
||||
selectedNumberPad != null &&
|
||||
cellValue == selectedNumberPad);
|
||||
|
||||
bool isIncorrect = incorrectCells.contains(index);
|
||||
|
||||
BorderSide thickBorder = BorderSide(color: thickBorderColor, width: 2.0);
|
||||
BorderSide thinBorder = BorderSide(color: thinBorderColor, width: 0.5);
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => onCellTapped(index),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: isIncorrect
|
||||
? incorrectBg
|
||||
: isHighlighted
|
||||
? highlightedBg
|
||||
: isEditable
|
||||
? editableBg
|
||||
: fixedBg,
|
||||
border: Border(
|
||||
top: (row == 0) ? thickBorder : thinBorder,
|
||||
left: (col == 0) ? thickBorder : thinBorder,
|
||||
right: (col == gridSize - 1) ? thickBorder : (col % blockSize == blockSize - 1) ? thickBorder : thinBorder,
|
||||
bottom: (row == gridSize - 1) ? thickBorder : (row % blockSize == blockSize - 1) ? thickBorder : thinBorder,
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
cellValue == 0 ? '' : theme.getSymbol(cellValue),
|
||||
style: TextStyle(
|
||||
fontSize: fontSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: isSelected
|
||||
? selectedTextColor
|
||||
: isIncorrect
|
||||
? incorrectTextColor
|
||||
: isEditable
|
||||
? editableTextColor
|
||||
: fixedTextColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user