NEW: MIH MineSweeper Package pt1

This commit is contained in:
2025-10-16 09:45:17 +02:00
parent 22d8c64994
commit 6ecce1e9ff
8 changed files with 873 additions and 46 deletions

View File

@@ -1,10 +1,10 @@
@font-face {
font-family: 'Mih_Icons';
src: url('fonts/Mih_Icons.eot?blbuxz');
src: url('fonts/Mih_Icons.eot?blbuxz#iefix') format('embedded-opentype'),
url('fonts/Mih_Icons.ttf?blbuxz') format('truetype'),
url('fonts/Mih_Icons.woff?blbuxz') format('woff'),
url('fonts/Mih_Icons.svg?blbuxz#Mih_Icons') format('svg');
font-family: 'icomoon';
src: url('fonts/icomoon.eot?8flwgj');
src: url('fonts/icomoon.eot?8flwgj#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?8flwgj') format('truetype'),
url('fonts/icomoon.woff?8flwgj') format('woff'),
url('fonts/icomoon.svg?8flwgj#icomoon') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
@@ -13,7 +13,7 @@
[class^="icon-"],
[class*=" icon-"] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'Mih_Icons' !important;
font-family: 'icomoon' !important;
/* speak: never; */
font-style: normal;
font-weight: normal;
@@ -26,70 +26,74 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-mzansi_directory:before {
.icon-mine_sweeper:before {
content: "\e900";
}
.icon-personal_profile:before {
.icon-mzansi_directory:before {
content: "\e901";
}
.icon-about_mih:before {
.icon-personal_profile:before {
content: "\e902";
}
.icon-access_control:before {
.icon-about_mih:before {
content: "\e903";
}
.icon-business_profile:before {
.icon-access_control:before {
content: "\e904";
}
.icon-business_setup:before {
.icon-business_profile:before {
content: "\e905";
}
.icon-i_dont_know:before {
.icon-business_setup:before {
content: "\e906";
}
.icon-mih_logo:before {
.icon-calculator:before {
content: "\e907";
}
.icon-mih_ring:before {
.icon-calendar:before {
content: "\e908";
}
.icon-mzansi_ai:before {
.icon-i_dont_know:before {
content: "\e909";
}
.icon-mzansi_wallet:before {
.icon-mih_logo:before {
content: "\e90a";
}
.icon-notifications:before {
.icon-mih_ring:before {
content: "\e90b";
}
.icon-patient_manager:before {
.icon-mzansi_ai:before {
content: "\e90c";
}
.icon-patient_profile:before {
.icon-mzansi_wallet:before {
content: "\e90d";
}
.icon-profile_setup:before {
.icon-notifications:before {
content: "\e90e";
}
.icon-calculator:before {
content: "\e940";
.icon-patient_manager:before {
content: "\e90f";
}
.icon-calendar:before {
content: "\e953";
.icon-patient_profile:before {
content: "\e910";
}
.icon-profile_setup:before {
content: "\e911";
}

View File

@@ -11,54 +11,57 @@ class MihIcons {
// IconData constants based on your style.css file
// Note: We convert the hex code from CSS (\eXXX) to an integer (0xeXXX)
static const IconData mzansiDirectory =
static const IconData mineSweeper =
IconData(0xe900, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData personalProfile =
static const IconData mzansiDirectory =
IconData(0xe901, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData aboutMih =
static const IconData personalProfile =
IconData(0xe902, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData accessControl =
static const IconData aboutMih =
IconData(0xe903, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData businessProfile =
static const IconData accessControl =
IconData(0xe904, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData businessSetup =
static const IconData businessProfile =
IconData(0xe905, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData iDontKnow =
static const IconData businessSetup =
IconData(0xe906, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData mihLogo =
static const IconData calculator =
IconData(0xe907, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData mihRing =
static const IconData calendar =
IconData(0xe908, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData mzansiAi =
static const IconData iDontKnow =
IconData(0xe909, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData mzansiWallet =
static const IconData mihLogo =
IconData(0xe90a, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData notifications =
static const IconData mihRing =
IconData(0xe90b, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData patientManager =
static const IconData mzansiAi =
IconData(0xe90c, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData patientProfile =
static const IconData mzansiWallet =
IconData(0xe90d, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData profileSetup =
static const IconData notifications =
IconData(0xe90e, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData calculator =
IconData(0xe940, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData patientManager =
IconData(0xe90f, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData calendar =
IconData(0xe953, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData patientProfile =
IconData(0xe910, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
static const IconData profileSetup =
IconData(0xe911, fontFamily: _mihFontFam, fontPackage: _mihFontPkg);
}

View File

@@ -0,0 +1,13 @@
class BoardSquare {
bool hasBomb;
int bombsAround;
bool isOpened;
bool isFlagged;
BoardSquare({
this.hasBomb = false,
this.bombsAround = 0,
this.isOpened = false,
this.isFlagged = false,
});
}

View File

@@ -0,0 +1,111 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/components/board_square.dart';
class MineTile extends StatelessWidget {
final BoardSquare square;
final VoidCallback onTap;
final VoidCallback onLongPress;
const MineTile({
super.key,
required this.square,
required this.onTap,
required this.onLongPress,
});
Widget _getTileContent(BuildContext context) {
if (square.isFlagged) {
return Icon(
Icons.flag,
color: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode != "Dark",
),
);
}
if (square.isOpened) {
if (square.hasBomb) {
return const Icon(FontAwesomeIcons.bomb, color: Colors.black);
} else if (square.bombsAround > 0) {
// Display bomb count
return Center(
child: Text(
'${square.bombsAround}',
style: TextStyle(
fontWeight: FontWeight.bold,
color: _getTileColor(square.bombsAround, context),
),
),
);
} else {
// Opened, but no bomb count (empty square)
return const SizedBox.shrink();
}
}
// Default: Unopened tile
return const SizedBox.shrink();
}
Color _getTileColor(int bombsAround, BuildContext context) {
// Choose colors based on standard Minesweeper appearance
switch (bombsAround) {
case 1:
return MihColors.getBluishPurpleColor(
MzansiInnovationHub.of(context)!.theme.mode != "Dark",
);
// return Colors.blue;
case 2:
return MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode != "Dark",
);
// return Colors.green;
case 3:
return MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode != "Dark",
);
// return Colors.red;
case 4:
return MihColors.getPurpleColor(
MzansiInnovationHub.of(context)!.theme.mode != "Dark",
);
// return Colors.purple;
case 5:
return MihColors.getOrangeColor(
MzansiInnovationHub.of(context)!.theme.mode != "Dark",
);
// return Colors.brown;
default:
// return MihColors.getBluishPurpleColor(
// MzansiInnovationHub.of(context)!.theme.mode == "Dark",
// );
return Colors.black;
}
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(1.0),
child: MihButton(
onPressed: onTap,
onLongPressed: onLongPress,
buttonColor: square.isOpened
? MihColors.getGreyColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark",
)
: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark",
),
width: 50,
height: 50,
borderRadius: 3,
child: _getTileContent(context),
),
);
}
}

View File

@@ -1,4 +1,12 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart';
import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart';
import 'package:provider/provider.dart';
class MihMineSweeper extends StatefulWidget {
const MihMineSweeper({super.key});
@@ -10,6 +18,54 @@ class MihMineSweeper extends StatefulWidget {
class _MihMineSweeperState extends State<MihMineSweeper> {
@override
Widget build(BuildContext context) {
return const Placeholder();
return MihPackage(
appActionButton: getAction(),
appTools: getTools(),
appToolTitles: getToolTitle(),
appBody: getToolBody(),
selectedbodyIndex: context.watch<MihMineSweeperProvider>().toolIndex,
onIndexChange: (newIndex) {
context.read<MihMineSweeperProvider>().setToolIndex(newIndex);
},
);
}
MihPackageAction getAction() {
return MihPackageAction(
icon: const Icon(Icons.arrow_back),
iconSize: 35,
onTap: () {
context.goNamed(
'mihHome',
extra: true,
);
FocusScope.of(context).unfocus();
},
);
}
MihPackageTools getTools() {
Map<Widget, void Function()?> temp = {};
temp[const Icon(FontAwesomeIcons.bomb)] = () {
context.read<MihMineSweeperProvider>().setToolIndex(0);
};
return MihPackageTools(
tools: temp,
selcetedIndex: context.watch<MihMineSweeperProvider>().toolIndex,
);
}
List<String> getToolTitle() {
List<String> toolTitles = [
"MineSweeper",
];
return toolTitles;
}
List<Widget> getToolBody() {
List<Widget> toolBodies = [
const MineSweeperGame(),
];
return toolBodies;
}
}

View File

@@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
class MihMineSweeperTile extends StatefulWidget {
final bool personalSelected;
final double packageSize;
const MihMineSweeperTile({
super.key,
required this.personalSelected,
required this.packageSize,
});
@override
State<MihMineSweeperTile> createState() => _MihMineSweeperTileState();
}
class _MihMineSweeperTileState extends State<MihMineSweeperTile> {
@override
Widget build(BuildContext context) {
return MihPackageTile(
onTap: () {
context.goNamed(
"mihMineSweeper",
);
},
appName: "MineSweeper",
appIcon: Icon(
MihIcons.mineSweeper,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
// size: widget.packageSize,
),
iconSize: widget.packageSize,
primaryColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
secondaryColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
}
}

View File

@@ -0,0 +1,596 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:go_router/go_router.dart';
import 'package:mzansi_innovation_hub/main.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart';
import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/components/board_square.dart';
import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/components/mine_tile.dart';
import 'package:provider/provider.dart';
class MineSweeperGame extends StatefulWidget {
const MineSweeperGame({super.key});
@override
State<MineSweeperGame> createState() => _MineSweeperGameState();
}
class _MineSweeperGameState extends State<MineSweeperGame> {
TextEditingController modeController = TextEditingController();
final _formKey = GlobalKey<FormState>();
List<List<BoardSquare>> board = [];
bool isGameOver = false;
bool isGameWon = false;
int squaresLeft = -1;
bool _isFirstLoad = true;
void showStartGameWindow(MihMineSweeperProvider mihMineSweeperProvider) {
showDialog(
context: context,
builder: (context) {
return MihPackageWindow(
fullscreen: false,
windowTitle: "New Game Settings",
onWindowTapClose: () {
context.pop();
},
windowBody: Column(
children: [
MihForm(
formKey: _formKey,
formFields: [
MihDropdownField(
controller: modeController,
hintText: "Difficulty",
dropdownOptions: ["Easy", "Normal", "Hard"],
requiredText: true,
editable: true,
enableSearch: false,
),
const SizedBox(height: 25),
Center(
child: MihButton(
onPressed: () {
setState(
() => initializeBoard(mihMineSweeperProvider));
Navigator.of(context).pop();
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 300,
child: Text(
"Start Game",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
),
],
),
],
),
);
});
}
// --- GAME INITIALIZATION LOGIC ---
void initializeBoard(MihMineSweeperProvider mihMineSweeperProvider) {
// 1. Create a board of empty squares
board = List.generate(
mihMineSweeperProvider.rowCount,
(i) => List.generate(
mihMineSweeperProvider.columnCount,
(j) => BoardSquare(),
),
);
// 2. Place bombs randomly
placeBombs(mihMineSweeperProvider);
// 3. Calculate the number of bombs around each non-mine square
calculateBombsAround(mihMineSweeperProvider);
// Reset state variables
squaresLeft =
mihMineSweeperProvider.rowCount * mihMineSweeperProvider.columnCount;
isGameOver = false;
isGameWon = false;
// You'd typically add a call to setState here, but it's in initState.
}
void placeBombs(MihMineSweeperProvider mihMineSweeperProvider) {
final Random random = Random();
int bombsPlaced = 0;
while (bombsPlaced < mihMineSweeperProvider.totalMines) {
int r = random.nextInt(mihMineSweeperProvider.rowCount);
int c = random.nextInt(mihMineSweeperProvider.columnCount);
if (!board[r][c].hasBomb) {
board[r][c].hasBomb = true;
bombsPlaced++;
}
}
}
void calculateBombsAround(MihMineSweeperProvider mihMineSweeperProvider) {
for (int r = 0; r < mihMineSweeperProvider.rowCount; r++) {
for (int c = 0; c < mihMineSweeperProvider.columnCount; c++) {
if (!board[r][c].hasBomb) {
int count = 0;
// Check the 8 neighbors
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (i == 0 && j == 0) continue; // Skip the current square
int neighborR = r + i;
int neighborC = c + j;
// Check if neighbor is within bounds
if (neighborR >= 0 &&
neighborR < mihMineSweeperProvider.rowCount &&
neighborC >= 0 &&
neighborC < mihMineSweeperProvider.columnCount) {
if (board[neighborR][neighborC].hasBomb) {
count++;
}
}
}
}
board[r][c].bombsAround = count;
}
}
}
}
// Handles recursive opening of zero-squares
void _expandZeros(
MihMineSweeperProvider mihMineSweeperProvider, int r, int c) {
if (r < 0 ||
r >= mihMineSweeperProvider.rowCount ||
c < 0 ||
c >= mihMineSweeperProvider.columnCount ||
board[r][c].isOpened) {
return;
}
BoardSquare square = board[r][c];
// Open the current square
square.isOpened = true;
squaresLeft--;
// If it's a zero square, recursively call for neighbors
if (square.bombsAround == 0) {
// Check all 8 neighbors (not just 4 sides, for standard Minesweeper expansion)
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
_expandZeros(mihMineSweeperProvider, r + i, c + j);
}
}
}
}
void handleTap(MihMineSweeperProvider mihMineSweeperProvider, int r, int c) {
if (isGameOver || board[r][c].isOpened || board[r][c].isFlagged) {
return;
}
// 1. Check for bomb (LOSS)
if (board[r][c].hasBomb) {
setState(() {
board[r][c].isOpened = true;
isGameOver = true;
// lose alert
showDialog(
context: context,
builder: (context) {
return MihPackageAlert(
alertIcon: Icon(
FontAwesomeIcons.bomb,
color: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
size: 100,
),
alertTitle: "Better Luck Next Time",
alertBody: Column(
children: [
Text(
"Your lost this game of MIH MineSweeper!!!",
style: TextStyle(
fontSize: 15,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
const SizedBox(height: 20),
Wrap(
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 10,
runSpacing: 10,
children: [
MihButton(
onPressed: () {
setState(
() => initializeBoard(mihMineSweeperProvider));
Navigator.of(context).pop();
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 300,
child: Text(
"New Game",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
),
],
),
alertColour: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
},
);
});
return;
}
// 2. Open square and handle expansion (RECURSION)
if (board[r][c].bombsAround == 0) {
// Start recursive expansion
_expandZeros(mihMineSweeperProvider, r, c);
} else {
// Just open the single square
board[r][c].isOpened = true;
squaresLeft--;
}
// 3. Check for win
_checkWinCondition(mihMineSweeperProvider);
// Update the UI
setState(() {});
}
void handleLongPress(int r, int c) {
if (isGameOver || board[r][c].isOpened) {
return;
}
setState(() {
// Toggle the flag status
board[r][c].isFlagged = !board[r][c].isFlagged;
});
}
// --- GAME ACTION LOGIC ---
void _checkWinCondition(MihMineSweeperProvider mihMineSweeperProvider) {
// Game is won if all non-mine squares are opened.
if (squaresLeft <= mihMineSweeperProvider.totalMines) {
isGameWon = true;
isGameOver = true;
// win alert
showDialog(
context: context,
builder: (context) {
return MihPackageAlert(
alertIcon: Icon(
Icons.celebration,
color: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
size: 100,
),
alertTitle: "Congradulations",
alertBody: Column(
children: [
Text(
"Your won this game of MIH MineSweeper!!!",
style: TextStyle(
fontSize: 15,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
const SizedBox(height: 20),
Wrap(
runAlignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 10,
runSpacing: 10,
children: [
MihButton(
onPressed: () {
setState(() => initializeBoard(mihMineSweeperProvider));
Navigator.of(context).pop();
},
buttonColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
width: 300,
child: Text(
"New Game",
style: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
],
),
],
),
alertColour: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
);
},
);
}
}
Color? getDifficultyColor() {
String mode = modeController.text;
switch (mode) {
case "Easy":
return MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark",
);
case "Normal":
return MihColors.getOrangeColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark",
);
case "Hard":
return MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark",
);
default:
return null;
}
}
@override
void initState() {
super.initState();
modeController.text = "Easy";
// showStartGameWindow(context.read<MihMineSweeperProvider>());
// initializeBoard();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
// This method is safe for calling showDialog or reading provider values.
if (_isFirstLoad) {
// 1. Get the provider safely.
WidgetsBinding.instance.addPostFrameCallback((_) {
final mihMineSweeperProvider = context.read<MihMineSweeperProvider>();
// board = List.generate(
// mihMineSweeperProvider.rowCount,
// (i) => List.generate(
// mihMineSweeperProvider.columnCount,
// (j) => BoardSquare(),
// ),
// );
// 2. Show the dialog to get initial game settings.
// The user selection in the dialog will call initializeBoard().
showStartGameWindow(mihMineSweeperProvider);
});
// 3. Set flag to prevent showing the dialog on subsequent dependency changes
_isFirstLoad = false;
}
}
@override
Widget build(BuildContext context) {
return Consumer<MihMineSweeperProvider>(
builder: (BuildContext context,
MihMineSweeperProvider mihMineSweeperProvider, Widget? child) {
return Stack(
alignment: Alignment.topCenter,
children: [
MihSingleChildScroll(
child: board.isEmpty && squaresLeft < 0
// Start Up Message before setting up game
? Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 50),
Icon(
MihIcons.mineSweeper,
size: 165,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
const SizedBox(height: 10),
Text(
"Welcom to MIH MineSweeper, the first game of MIH.",
textAlign: TextAlign.center,
overflow: TextOverflow.visible,
style: TextStyle(
fontSize: 25,
fontWeight: FontWeight.bold,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
),
const SizedBox(height: 25),
Center(
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.normal,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
),
children: [
TextSpan(text: "Press "),
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Icon(
Icons.menu,
size: 20,
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!
.theme
.mode ==
"Dark"),
),
),
TextSpan(text: " to start a new game."),
],
),
),
),
],
),
)
// Display Game Board when game started
: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Display game status
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
'Mines: ${mihMineSweeperProvider.totalMines}',
textAlign: TextAlign.left,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold),
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
modeController.text,
textAlign: TextAlign.right,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: getDifficultyColor(),
),
),
),
),
],
),
// const SizedBox(
// height: 30,
// ),
// The Board Grid
SizedBox(
width: mihMineSweeperProvider.columnCount *
40.0, // Control size based on columns
height: mihMineSweeperProvider.rowCount *
40.0, // Control size based on rows
child: GridView.builder(
physics:
const NeverScrollableScrollPhysics(), // Prevent scrolling
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount:
mihMineSweeperProvider.columnCount,
crossAxisSpacing: 0,
mainAxisSpacing: 0,
),
itemCount: mihMineSweeperProvider.rowCount *
mihMineSweeperProvider.columnCount,
itemBuilder: (context, index) {
int r = index ~/
mihMineSweeperProvider
.columnCount; // Integer division for row
int c = index %
mihMineSweeperProvider
.columnCount; // Remainder for column
return MineTile(
square: board[r][c],
onTap: () =>
handleTap(mihMineSweeperProvider, r, c),
onLongPress: () => handleLongPress(r, c),
);
},
),
),
],
),
),
Positioned(
right: 10,
bottom: 10,
child: MihFloatingMenu(
animatedIcon: AnimatedIcons.menu_close,
children: [
SpeedDialChild(
child: Icon(
Icons.add,
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
),
label: board.isEmpty && squaresLeft < 0
? "Start Game"
: "Reset Game",
labelBackgroundColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
labelStyle: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
fontWeight: FontWeight.bold,
),
backgroundColor: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode ==
"Dark"),
onTap: () {
showStartGameWindow(mihMineSweeperProvider);
},
)
]),
)
],
);
},
);
}
}