diff --git a/Frontend/lib/mih_components/mih_package_components/assets/fonts/Mih_Icons.ttf b/Frontend/lib/mih_components/mih_package_components/assets/fonts/Mih_Icons.ttf index 71c04e15..a908997c 100644 Binary files a/Frontend/lib/mih_components/mih_package_components/assets/fonts/Mih_Icons.ttf and b/Frontend/lib/mih_components/mih_package_components/assets/fonts/Mih_Icons.ttf differ diff --git a/Frontend/lib/mih_components/mih_package_components/assets/fonts/style.css b/Frontend/lib/mih_components/mih_package_components/assets/fonts/style.css index 97fe7b5a..9b49c4fc 100644 --- a/Frontend/lib/mih_components/mih_package_components/assets/fonts/style.css +++ b/Frontend/lib/mih_components/mih_package_components/assets/fonts/style.css @@ -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"; } \ No newline at end of file diff --git a/Frontend/lib/mih_components/mih_package_components/mih_icons.dart b/Frontend/lib/mih_components/mih_package_components/mih_icons.dart index bfd4a9ac..6dbb19c8 100644 --- a/Frontend/lib/mih_components/mih_package_components/mih_icons.dart +++ b/Frontend/lib/mih_components/mih_package_components/mih_icons.dart @@ -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); } diff --git a/Frontend/lib/mih_packages/mine_sweeper/components/board_square.dart b/Frontend/lib/mih_packages/mine_sweeper/components/board_square.dart new file mode 100644 index 00000000..0259b064 --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/components/board_square.dart @@ -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, + }); +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/components/mine_tile.dart b/Frontend/lib/mih_packages/mine_sweeper/components/mine_tile.dart new file mode 100644 index 00000000..4e877c4b --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/components/mine_tile.dart @@ -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), + ), + ); + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart b/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart index 98fd163f..b0659619 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart @@ -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 { @override Widget build(BuildContext context) { - return const Placeholder(); + return MihPackage( + appActionButton: getAction(), + appTools: getTools(), + appToolTitles: getToolTitle(), + appBody: getToolBody(), + selectedbodyIndex: context.watch().toolIndex, + onIndexChange: (newIndex) { + context.read().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 temp = {}; + temp[const Icon(FontAwesomeIcons.bomb)] = () { + context.read().setToolIndex(0); + }; + return MihPackageTools( + tools: temp, + selcetedIndex: context.watch().toolIndex, + ); + } + + List getToolTitle() { + List toolTitles = [ + "MineSweeper", + ]; + return toolTitles; + } + + List getToolBody() { + List toolBodies = [ + const MineSweeperGame(), + ]; + return toolBodies; } } diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart new file mode 100644 index 00000000..81cab8fc --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart @@ -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 createState() => _MihMineSweeperTileState(); +} + +class _MihMineSweeperTileState extends State { + @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"), + ); + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart new file mode 100644 index 00000000..be21f407 --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart @@ -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 createState() => _MineSweeperGameState(); +} + +class _MineSweeperGameState extends State { + TextEditingController modeController = TextEditingController(); + final _formKey = GlobalKey(); + List> 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()); + // 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(); + // 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( + 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); + }, + ) + ]), + ) + ], + ); + }, + ); + } +}