rename container folders
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mzansi_innovation_hub/main.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_circle_avatar.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_icons.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_providers/mih_mine_sweeper_provider.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class BuildMinesweeperLeaderboardList extends StatefulWidget {
|
||||
const BuildMinesweeperLeaderboardList({super.key});
|
||||
|
||||
@override
|
||||
State<BuildMinesweeperLeaderboardList> createState() =>
|
||||
_BuildMinesweeperLeaderboardListState();
|
||||
}
|
||||
|
||||
class _BuildMinesweeperLeaderboardListState
|
||||
extends State<BuildMinesweeperLeaderboardList> {
|
||||
Color getMedalColor(int index) {
|
||||
switch (index) {
|
||||
case (0):
|
||||
return MihColors.getGoldColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
|
||||
case (1):
|
||||
return MihColors.getSilverColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
|
||||
case (2):
|
||||
return MihColors.getBronze(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
|
||||
default:
|
||||
return MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final double width = MediaQuery.sizeOf(context).width;
|
||||
return Consumer2<MzansiProfileProvider, MihMineSweeperProvider>(
|
||||
builder: (BuildContext context, MzansiProfileProvider profileProvider,
|
||||
MihMineSweeperProvider mineSweeperProvider, Widget? child) {
|
||||
return ListView.separated(
|
||||
separatorBuilder: (BuildContext context, index) {
|
||||
return Divider(
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
);
|
||||
},
|
||||
itemCount: mineSweeperProvider.leaderboard!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return FutureBuilder(
|
||||
future: mineSweeperProvider.leaderboardUserPicturesUrl[index],
|
||||
builder: (context, asyncSnapshot) {
|
||||
ImageProvider<Object>? imageFile;
|
||||
bool loading = true;
|
||||
if (asyncSnapshot.connectionState == ConnectionState.done) {
|
||||
loading = false;
|
||||
if (asyncSnapshot.hasData) {
|
||||
imageFile = asyncSnapshot.requireData != ""
|
||||
? CachedNetworkImageProvider(
|
||||
asyncSnapshot.requireData)
|
||||
: null;
|
||||
} else {
|
||||
imageFile = null;
|
||||
}
|
||||
} else {
|
||||
imageFile = null;
|
||||
}
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: width / 20),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
"#${index + 1}",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: getMedalColor(index),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
loading
|
||||
? Icon(
|
||||
MihIcons.mihRing,
|
||||
size: 80,
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!
|
||||
.theme
|
||||
.mode ==
|
||||
"Dark"),
|
||||
)
|
||||
: imageFile == null
|
||||
? Icon(
|
||||
MihIcons.iDontKnow,
|
||||
size: 80,
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!
|
||||
.theme
|
||||
.mode ==
|
||||
"Dark"),
|
||||
)
|
||||
: MihCircleAvatar(
|
||||
key: UniqueKey(),
|
||||
imageFile: imageFile,
|
||||
width: 80,
|
||||
editable: false,
|
||||
fileNameController: null,
|
||||
userSelectedfile: null,
|
||||
frameColor: getMedalColor(index),
|
||||
backgroundColor: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!
|
||||
.theme
|
||||
.mode ==
|
||||
"Dark"),
|
||||
onChange: () {},
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"${mineSweeperProvider.leaderboard![index].username}${profileProvider.user!.username == mineSweeperProvider.leaderboard![index].username ? " (You)" : ""}",
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: getMedalColor(index),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"Score: ${mineSweeperProvider.leaderboard![index].game_score}\nTime: ${mineSweeperProvider.leaderboard![index].game_time}",
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
// fontWeight: FontWeight.bold,
|
||||
color: getMedalColor(index),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mzansi_innovation_hub/main.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_providers/mih_mine_sweeper_provider.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class BuildMyScoreBoardList extends StatefulWidget {
|
||||
const BuildMyScoreBoardList({super.key});
|
||||
|
||||
@override
|
||||
State<BuildMyScoreBoardList> createState() =>
|
||||
_BuildMinesweeperLeaderboardListState();
|
||||
}
|
||||
|
||||
class _BuildMinesweeperLeaderboardListState
|
||||
extends State<BuildMyScoreBoardList> {
|
||||
Color getMedalColor(int index) {
|
||||
switch (index) {
|
||||
case (0):
|
||||
return MihColors.getGoldColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
|
||||
case (1):
|
||||
return MihColors.getSilverColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
|
||||
case (2):
|
||||
return MihColors.getBronze(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
|
||||
default:
|
||||
return MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final double width = MediaQuery.sizeOf(context).width;
|
||||
return Consumer2<MzansiProfileProvider, MihMineSweeperProvider>(
|
||||
builder: (BuildContext context, MzansiProfileProvider profileProvider,
|
||||
MihMineSweeperProvider mineSweeperProvider, Widget? child) {
|
||||
return ListView.separated(
|
||||
separatorBuilder: (BuildContext context, index) {
|
||||
return Divider(
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
);
|
||||
},
|
||||
itemCount: mineSweeperProvider.myScoreboard!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: width / 20),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
"#${index + 1}",
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: getMedalColor(index),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Score: ${mineSweeperProvider.myScoreboard![index].game_score}",
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: getMedalColor(index),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"Time: ${mineSweeperProvider.myScoreboard![index].game_time}",
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
// fontWeight: FontWeight.bold,
|
||||
color: getMedalColor(index),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ken_logger/ken_logger.dart';
|
||||
import 'package:mzansi_innovation_hub/main.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_circle_avatar.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
|
||||
import 'package:redacted/redacted.dart';
|
||||
|
||||
class LeaderboardUserRanking extends StatelessWidget {
|
||||
final int index;
|
||||
final String proPicUrl;
|
||||
final String username;
|
||||
final dynamic gameScore;
|
||||
final String gameTime;
|
||||
final bool isCurrentUser;
|
||||
final Future<ImageProvider<Object>?> Function(String) getUserPicture;
|
||||
|
||||
const LeaderboardUserRanking({
|
||||
super.key,
|
||||
required this.index,
|
||||
required this.proPicUrl,
|
||||
required this.username,
|
||||
required this.gameScore,
|
||||
required this.gameTime,
|
||||
required this.isCurrentUser,
|
||||
required this.getUserPicture,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: getUserPicture(proPicUrl),
|
||||
builder: (context, asyncSnapshot) {
|
||||
bool isLoading =
|
||||
asyncSnapshot.connectionState == ConnectionState.waiting;
|
||||
|
||||
KenLogger.success("URL: ${asyncSnapshot.data.toString()}");
|
||||
return ListTile(
|
||||
leading: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"#${index + 1}",
|
||||
style: const TextStyle(
|
||||
fontSize: 25,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
MihCircleAvatar(
|
||||
key: ValueKey(asyncSnapshot.data
|
||||
.toString()), // Use ValueKey for stable identity
|
||||
imageFile: asyncSnapshot.data,
|
||||
width: 60,
|
||||
editable: false,
|
||||
fileNameController: null,
|
||||
userSelectedfile: null,
|
||||
frameColor: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
backgroundColor: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
onChange: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
title: Text(
|
||||
"$username${isCurrentUser ? " (You)" : ""}",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
),
|
||||
).redacted(context: context, redact: isLoading),
|
||||
subtitle: Text(
|
||||
"Score: $gameScore\nTime: $gameTime",
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
),
|
||||
).redacted(context: context, redact: isLoading),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
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_package_components/mih_button.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_dropdwn_field.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_form.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_window.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_providers/mih_mine_sweeper_provider.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class MihMineSweeperStartGameWindow extends StatefulWidget {
|
||||
final void Function()? onPressed;
|
||||
const MihMineSweeperStartGameWindow({
|
||||
super.key,
|
||||
required this.onPressed,
|
||||
});
|
||||
|
||||
@override
|
||||
State<MihMineSweeperStartGameWindow> createState() =>
|
||||
_MihMineSweeperStartGameWindowState();
|
||||
}
|
||||
|
||||
class _MihMineSweeperStartGameWindowState
|
||||
extends State<MihMineSweeperStartGameWindow> {
|
||||
TextEditingController modeController = TextEditingController();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
void applyGameSettings(MihMineSweeperProvider mihMineSweeperProvider) {
|
||||
mihMineSweeperProvider.setDifficulty(modeController.text);
|
||||
switch (mihMineSweeperProvider.difficulty) {
|
||||
case ("Very Easy"):
|
||||
mihMineSweeperProvider.setRowCount(6);
|
||||
mihMineSweeperProvider.setCoulmnCount(6);
|
||||
mihMineSweeperProvider.setTotalMines(5);
|
||||
// mihMineSweeperProvider.setRowCount(5);
|
||||
// mihMineSweeperProvider.setCoulmnCount(5);
|
||||
// mihMineSweeperProvider.setTotalMines(3);
|
||||
break;
|
||||
case ("Easy"):
|
||||
mihMineSweeperProvider.setRowCount(8);
|
||||
mihMineSweeperProvider.setCoulmnCount(8);
|
||||
mihMineSweeperProvider.setTotalMines(10);
|
||||
// mihMineSweeperProvider.setRowCount(10);
|
||||
// mihMineSweeperProvider.setCoulmnCount(10);
|
||||
// mihMineSweeperProvider.setTotalMines(15);
|
||||
break;
|
||||
case ("Intermediate"):
|
||||
mihMineSweeperProvider.setRowCount(10);
|
||||
mihMineSweeperProvider.setCoulmnCount(10);
|
||||
mihMineSweeperProvider.setTotalMines(18);
|
||||
// mihMineSweeperProvider.setRowCount(15);
|
||||
// mihMineSweeperProvider.setCoulmnCount(10);
|
||||
// mihMineSweeperProvider.setTotalMines(23);
|
||||
break;
|
||||
case ("Hard"):
|
||||
mihMineSweeperProvider.setRowCount(12);
|
||||
mihMineSweeperProvider.setCoulmnCount(10);
|
||||
mihMineSweeperProvider.setTotalMines(30);
|
||||
// mihMineSweeperProvider.setRowCount(20);
|
||||
// mihMineSweeperProvider.setCoulmnCount(10);
|
||||
// mihMineSweeperProvider.setTotalMines(30);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String getModeConfig() {
|
||||
switch (modeController.text) {
|
||||
case ("Very Easy"):
|
||||
return "Columns: 6\nRows: 6\nBombs: 5";
|
||||
case ("Easy"):
|
||||
return "Columns: 8\nRows: 8\nBombs: 10";
|
||||
case ("Intermediate"):
|
||||
return "Columns: 10\nRows: 10\nBombs: 18";
|
||||
case ("Hard"):
|
||||
return "Columns: 10\nRows: 12\nBombs: 30";
|
||||
default:
|
||||
return "Error";
|
||||
}
|
||||
}
|
||||
|
||||
void _onModeChanged() {
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
modeController.removeListener(_onModeChanged);
|
||||
modeController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
modeController.text = context.read<MihMineSweeperProvider>().difficulty;
|
||||
modeController.addListener(_onModeChanged);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MihPackageWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: "New Game Settings",
|
||||
onWindowTapClose: () {
|
||||
context.pop();
|
||||
},
|
||||
windowBody: Consumer<MihMineSweeperProvider>(
|
||||
builder: (BuildContext context,
|
||||
MihMineSweeperProvider mihMineSweeperProvider, Widget? child) {
|
||||
return Column(
|
||||
children: [
|
||||
MihForm(
|
||||
formKey: _formKey,
|
||||
formFields: [
|
||||
MihDropdownField(
|
||||
controller: modeController,
|
||||
hintText: "Difficulty",
|
||||
dropdownOptions: [
|
||||
"Very Easy",
|
||||
"Easy",
|
||||
"Intermediate",
|
||||
"Hard"
|
||||
],
|
||||
requiredText: true,
|
||||
editable: true,
|
||||
enableSearch: false,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
getModeConfig(),
|
||||
style: TextStyle(
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
Center(
|
||||
child: MihButton(
|
||||
onPressed: () {
|
||||
applyGameSettings(mihMineSweeperProvider);
|
||||
context.pop();
|
||||
widget.onPressed?.call();
|
||||
},
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
112
mih_ui/lib/mih_packages/mine_sweeper/components/mine_tile.dart
Normal file
112
mih_ui/lib/mih_packages/mine_sweeper/components/mine_tile.dart
Normal file
@@ -0,0 +1,112 @@
|
||||
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_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(
|
||||
fontSize: 25,
|
||||
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),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
141
mih_ui/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart
Normal file
141
mih_ui/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart
Normal file
@@ -0,0 +1,141 @@
|
||||
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_package_components/mih_package.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_action.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tools.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_loading_circle.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_providers/mih_banner_ad_provider.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_providers/mih_mine_sweeper_provider.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/package_tools/mih_mine_sweeper_leader_board.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/package_tools/my_score_board.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_services/mih_data_helper_services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class MihMineSweeper extends StatefulWidget {
|
||||
const MihMineSweeper({super.key});
|
||||
|
||||
@override
|
||||
State<MihMineSweeper> createState() => _MihMineSweeperState();
|
||||
}
|
||||
|
||||
class _MihMineSweeperState extends State<MihMineSweeper> {
|
||||
bool _isLoadingInitialData = true;
|
||||
late final MineSweeperGame _mineSweeperGame;
|
||||
late final MihMineSweeperLeaderBoard _mineSweeperLeaderBoard;
|
||||
late final MyScoreBoard _myScoreBoard;
|
||||
late final MineSweeperQuickStartGuide _mineSweeperQuickStartGuide;
|
||||
|
||||
Future<void> _loadInitialData() async {
|
||||
setState(() {
|
||||
_isLoadingInitialData = true;
|
||||
});
|
||||
MzansiProfileProvider mzansiProfileProvider =
|
||||
context.read<MzansiProfileProvider>();
|
||||
MihBannerAdProvider bannerAdProvider = context.read<MihBannerAdProvider>();
|
||||
if (mzansiProfileProvider.user == null) {
|
||||
await MihDataHelperServices().loadUserDataOnly(
|
||||
mzansiProfileProvider,
|
||||
);
|
||||
}
|
||||
bannerAdProvider.loadBannerAd();
|
||||
setState(() {
|
||||
_isLoadingInitialData = false;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_mineSweeperGame = MineSweeperGame();
|
||||
_mineSweeperLeaderBoard = MihMineSweeperLeaderBoard();
|
||||
_myScoreBoard = MyScoreBoard();
|
||||
_mineSweeperQuickStartGuide = MineSweeperQuickStartGuide();
|
||||
_loadInitialData();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<MihMineSweeperProvider>(
|
||||
builder:
|
||||
(BuildContext context, MihMineSweeperProvider value, Widget? child) {
|
||||
if (_isLoadingInitialData) {
|
||||
return Scaffold(
|
||||
body: Center(
|
||||
child: Mihloadingcircle(),
|
||||
),
|
||||
);
|
||||
}
|
||||
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: () {
|
||||
MihMineSweeperProvider mineSweeperProvider =
|
||||
context.read<MihMineSweeperProvider>();
|
||||
mineSweeperProvider.setToolIndex(0);
|
||||
mineSweeperProvider.setDifficulty("Easy");
|
||||
context.goNamed(
|
||||
'mihHome',
|
||||
);
|
||||
FocusScope.of(context).unfocus();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
MihPackageTools getTools() {
|
||||
Map<Widget, void Function()?> temp = {};
|
||||
temp[const Icon(FontAwesomeIcons.bomb)] = () {
|
||||
context.read<MihMineSweeperProvider>().setToolIndex(0);
|
||||
};
|
||||
temp[const Icon(Icons.leaderboard_rounded)] = () {
|
||||
context.read<MihMineSweeperProvider>().setToolIndex(1);
|
||||
};
|
||||
temp[const Icon(Icons.perm_identity_rounded)] = () {
|
||||
context.read<MihMineSweeperProvider>().setToolIndex(2);
|
||||
};
|
||||
temp[const Icon(Icons.rule_rounded)] = () {
|
||||
context.read<MihMineSweeperProvider>().setToolIndex(3);
|
||||
};
|
||||
return MihPackageTools(
|
||||
tools: temp,
|
||||
selcetedIndex: context.watch<MihMineSweeperProvider>().toolIndex,
|
||||
);
|
||||
}
|
||||
|
||||
List<String> getToolTitle() {
|
||||
List<String> toolTitles = [
|
||||
"Minesweeper",
|
||||
"Leader Board",
|
||||
"My Scores",
|
||||
"Guide",
|
||||
];
|
||||
return toolTitles;
|
||||
}
|
||||
|
||||
List<Widget> getToolBody() {
|
||||
return [
|
||||
_mineSweeperGame,
|
||||
_mineSweeperLeaderBoard,
|
||||
_myScoreBoard,
|
||||
_mineSweeperQuickStartGuide,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
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_package_components/mih_icons.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tile.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
|
||||
|
||||
class MihMineSweeperTile extends StatefulWidget {
|
||||
final double packageSize;
|
||||
const MihMineSweeperTile({
|
||||
super.key,
|
||||
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,
|
||||
textColor: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:ken_logger/ken_logger.dart';
|
||||
import 'package:mzansi_innovation_hub/main.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_dropdwn_field.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_icons.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tool_body.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_loading_circle.dart';
|
||||
import 'package:mzansi_innovation_hub/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/builders/build_minesweeper_leaderboard_list.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_services/mih_minesweeper_services.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class MihMineSweeperLeaderBoard extends StatefulWidget {
|
||||
const MihMineSweeperLeaderBoard({super.key});
|
||||
|
||||
@override
|
||||
State<MihMineSweeperLeaderBoard> createState() =>
|
||||
_MihMineSweeperLeaderBoardState();
|
||||
}
|
||||
|
||||
class _MihMineSweeperLeaderBoardState extends State<MihMineSweeperLeaderBoard> {
|
||||
TextEditingController filterController = TextEditingController();
|
||||
bool isLoading = true;
|
||||
Future<void> initialiseLeaderboard() async {
|
||||
MihMineSweeperProvider mineSweeperProvider =
|
||||
context.read<MihMineSweeperProvider>();
|
||||
filterController.text = mineSweeperProvider.difficulty;
|
||||
KenLogger.success("getting data");
|
||||
await MihMinesweeperServices().getTop20Leaderboard(mineSweeperProvider);
|
||||
List<Future<String>> userPicturesUrl = [];
|
||||
Future<String> userPicUrl;
|
||||
for (final ranking in mineSweeperProvider.leaderboard!) {
|
||||
userPicUrl = MihFileApi.getMinioFileUrl(ranking.proPicUrl);
|
||||
userPicturesUrl.add(userPicUrl);
|
||||
}
|
||||
mineSweeperProvider.setLeaderboardUserPictures(
|
||||
leaderboardUserPicturesUrl: userPicturesUrl);
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
void refreshLeaderBoard(
|
||||
MihMineSweeperProvider mineSweeperProvider, String difficulty) {
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
mineSweeperProvider.setDifficulty(difficulty);
|
||||
mineSweeperProvider.setLeaderboard(leaderboard: null);
|
||||
mineSweeperProvider.setMyScoreboard(myScoreboard: null);
|
||||
initialiseLeaderboard();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await initialiseLeaderboard();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final double width = MediaQuery.sizeOf(context).width;
|
||||
return Consumer<MihMineSweeperProvider>(
|
||||
builder: (BuildContext context,
|
||||
MihMineSweeperProvider mineSweeperProvider, Widget? child) {
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
refreshLeaderBoard(mineSweeperProvider, filterController.text);
|
||||
},
|
||||
child: MihPackageToolBody(
|
||||
borderOn: false,
|
||||
bodyItem: getBody(width),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget getBody(double width) {
|
||||
return Consumer<MihMineSweeperProvider>(
|
||||
builder: (BuildContext context,
|
||||
MihMineSweeperProvider mineSweeperProvider, Widget? child) {
|
||||
if (isLoading) {
|
||||
return Center(
|
||||
child: Mihloadingcircle(),
|
||||
);
|
||||
} else {
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: width / 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Flexible(
|
||||
child: MihDropdownField(
|
||||
controller: filterController,
|
||||
hintText: "Leaderboards",
|
||||
dropdownOptions: const [
|
||||
"Very Easy",
|
||||
"Easy",
|
||||
"Intermediate",
|
||||
"Hard",
|
||||
],
|
||||
requiredText: true,
|
||||
editable: true,
|
||||
enableSearch: false,
|
||||
validator: (value) {
|
||||
return MihValidationServices().isEmpty(value);
|
||||
},
|
||||
onSelected: (selection) {
|
||||
refreshLeaderBoard(mineSweeperProvider, selection!);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
!isLoading && mineSweeperProvider.leaderboard!.isEmpty
|
||||
? 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(
|
||||
"Be the first on the leaderboard.",
|
||||
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(
|
||||
FontAwesomeIcons.bomb,
|
||||
size: 20,
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!
|
||||
.theme
|
||||
.mode ==
|
||||
"Dark"),
|
||||
),
|
||||
),
|
||||
TextSpan(text: " and start a new game"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: Expanded(
|
||||
child: BuildMinesweeperLeaderboardList(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,860 @@
|
||||
import 'dart:async';
|
||||
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_package_components/mih_banner_ad.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_button.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_floating_menu.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_icons.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tool_body.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_window.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_single_child_scroll.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_loading_circle.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_providers/mih_mine_sweeper_provider.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_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/mih_mine_sweeper_start_game_window.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/components/mine_tile.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_services/mih_minesweeper_services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class MineSweeperGame extends StatefulWidget {
|
||||
const MineSweeperGame({super.key});
|
||||
|
||||
@override
|
||||
State<MineSweeperGame> createState() => _MineSweeperGameState();
|
||||
}
|
||||
|
||||
class _MineSweeperGameState extends State<MineSweeperGame> {
|
||||
List<List<BoardSquare>> board = [];
|
||||
bool isGameOver = false;
|
||||
bool isGameWon = false;
|
||||
int squaresLeft = -1;
|
||||
Timer? _timer;
|
||||
int _milliseconds = 0;
|
||||
bool _isRunning = false;
|
||||
static const int millisecondsPerUpdate = 100;
|
||||
|
||||
double timeStringToTotalSeconds(String timeString) {
|
||||
try {
|
||||
List<String> parts = timeString.split(':');
|
||||
if (parts.length != 4) {
|
||||
return 0.0;
|
||||
}
|
||||
double hours = double.parse(parts[0]);
|
||||
double minutes = double.parse(parts[1]);
|
||||
double seconds = double.parse(parts[2]);
|
||||
double milliseconds = double.parse(parts[3]);
|
||||
double totalSeconds =
|
||||
(hours * 3600) + (minutes * 60) + seconds + (milliseconds / 100);
|
||||
return totalSeconds;
|
||||
} catch (e) {
|
||||
print("Error parsing time string: $e");
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
double calculateGameScore(MihMineSweeperProvider mihMineSweeperProvider) {
|
||||
int scoreConst = 10000;
|
||||
double dificusltyMultiplier;
|
||||
switch (mihMineSweeperProvider.difficulty) {
|
||||
case ("Very Easy"):
|
||||
dificusltyMultiplier = 0.5;
|
||||
break;
|
||||
case ("Easy"):
|
||||
dificusltyMultiplier = 1.0;
|
||||
break;
|
||||
case ("Intermediate"):
|
||||
dificusltyMultiplier = 2.5;
|
||||
break;
|
||||
case ("Hard"):
|
||||
dificusltyMultiplier = 5.0;
|
||||
break;
|
||||
default:
|
||||
dificusltyMultiplier = 0.0;
|
||||
break;
|
||||
}
|
||||
double rawScore = (scoreConst * dificusltyMultiplier) /
|
||||
timeStringToTotalSeconds(_formatTime());
|
||||
|
||||
String scoreString = rawScore.toStringAsFixed(5);
|
||||
return double.parse(scoreString);
|
||||
}
|
||||
|
||||
void startTimer() {
|
||||
if (_isRunning) return;
|
||||
_isRunning = true;
|
||||
_timer = Timer.periodic(const Duration(milliseconds: millisecondsPerUpdate),
|
||||
(timer) {
|
||||
setState(() {
|
||||
_milliseconds += millisecondsPerUpdate; // Increment by the interval
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void stopTimer() {
|
||||
_timer?.cancel();
|
||||
setState(() {
|
||||
_isRunning = false;
|
||||
});
|
||||
}
|
||||
|
||||
void resetTimer() {
|
||||
stopTimer(); // Stop the timer first
|
||||
setState(() {
|
||||
_milliseconds = 0; // Reset the time to zero
|
||||
});
|
||||
}
|
||||
|
||||
String _formatTime() {
|
||||
Duration duration = Duration(milliseconds: _milliseconds);
|
||||
final int hours = duration.inHours;
|
||||
final int minutes = duration.inMinutes.remainder(60);
|
||||
final int seconds = duration.inSeconds.remainder(60);
|
||||
final int centiseconds = (duration.inMilliseconds.remainder(1000)) ~/ 10;
|
||||
String hoursStr = hours.toString().padLeft(2, '0');
|
||||
String minutesStr = minutes.toString().padLeft(2, '0');
|
||||
String secondsStr = seconds.toString().padLeft(2, '0');
|
||||
String centiStr = centiseconds.toString().padLeft(2, '0');
|
||||
return '$hoursStr:$minutesStr:$secondsStr:$centiStr';
|
||||
}
|
||||
|
||||
void showStartGameWindow(
|
||||
MihMineSweeperProvider mihMineSweeperProvider,
|
||||
) {
|
||||
// easy - 10 * 10 & 15 bombs
|
||||
// Intermediate - 10 * 15 & 23 bombs
|
||||
// Hard - 10 * 20 & 30 bombs
|
||||
showDialog(
|
||||
barrierDismissible: false,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return MihMineSweeperStartGameWindow(
|
||||
onPressed: () {
|
||||
resetTimer();
|
||||
mihMineSweeperProvider
|
||||
.setDifficulty(mihMineSweeperProvider.difficulty);
|
||||
setState(() => initializeBoard(mihMineSweeperProvider));
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// --- 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.
|
||||
startTimer();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> handleTap(MzansiProfileProvider profileProvider,
|
||||
MihMineSweeperProvider mihMineSweeperProvider, int r, int c) async {
|
||||
if (isGameOver || board[r][c].isOpened || board[r][c].isFlagged) {
|
||||
return;
|
||||
}
|
||||
// 1. Check for bomb (LOSS)
|
||||
if (board[r][c].hasBomb) {
|
||||
stopTimer();
|
||||
setState(() {
|
||||
board[r][c].isOpened = true;
|
||||
isGameOver = true;
|
||||
// lose alert
|
||||
loseAlert(mihMineSweeperProvider);
|
||||
});
|
||||
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(profileProvider, 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 ---
|
||||
Future<void> _checkWinCondition(
|
||||
MzansiProfileProvider profileProvider,
|
||||
MihMineSweeperProvider mihMineSweeperProvider,
|
||||
) async {
|
||||
// Game is won if all non-mine squares are opened.
|
||||
if (squaresLeft <= mihMineSweeperProvider.totalMines) {
|
||||
stopTimer();
|
||||
isGameWon = true;
|
||||
isGameOver = true;
|
||||
// win alert
|
||||
winAlert(mihMineSweeperProvider);
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Mihloadingcircle(
|
||||
message: "Uploading your score",
|
||||
);
|
||||
});
|
||||
await MihMinesweeperServices().addPlayerScore(
|
||||
profileProvider,
|
||||
mihMineSweeperProvider,
|
||||
_formatTime().replaceAll("00:", ""),
|
||||
calculateGameScore(mihMineSweeperProvider),
|
||||
);
|
||||
context.pop();
|
||||
}
|
||||
}
|
||||
|
||||
Color? getDifficultyColor(MihMineSweeperProvider mihMineSweeperProvider) {
|
||||
String mode = mihMineSweeperProvider.difficulty;
|
||||
switch (mode) {
|
||||
case "Very Easy":
|
||||
return MihColors.getGreenColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark",
|
||||
);
|
||||
case "Easy":
|
||||
return MihColors.getGreenColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode != "Dark",
|
||||
);
|
||||
case "Intermediate":
|
||||
return MihColors.getOrangeColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark",
|
||||
);
|
||||
case "Hard":
|
||||
return MihColors.getRedColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark",
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void loseAlert(MihMineSweeperProvider mihMineSweeperProvider) {
|
||||
showDialog(
|
||||
barrierDismissible: false,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return MihPackageWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: null,
|
||||
onWindowTapClose: null,
|
||||
backgroundColor: MihColors.getRedColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode != "Dark"),
|
||||
windowBody: Column(
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
Icon(
|
||||
FontAwesomeIcons.bomb,
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
size: 125,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
"Better Luck Next Time",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Center(
|
||||
child: Text(
|
||||
"Your lost this game of MIH Minesweeper!!!",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Text(
|
||||
"Please feel free to start a New Game or check out the Leader Board to find out who's the best in Mzansi.",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Wrap(
|
||||
runAlignment: WrapAlignment.center,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
children: [
|
||||
MihButton(
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
showStartGameWindow(mihMineSweeperProvider);
|
||||
},
|
||||
buttonColor: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
width: 300,
|
||||
child: Text(
|
||||
"New Game",
|
||||
style: TextStyle(
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
MihButton(
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
},
|
||||
buttonColor: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
width: 300,
|
||||
child: Text(
|
||||
"View Board",
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
MihButton(
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
mihMineSweeperProvider.setToolIndex(1);
|
||||
},
|
||||
buttonColor: MihColors.getGoldColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
width: 300,
|
||||
child: Text(
|
||||
"Leader Board",
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void winAlert(MihMineSweeperProvider mihMineSweeperProvider) {
|
||||
showDialog(
|
||||
barrierDismissible: false,
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return MihPackageWindow(
|
||||
fullscreen: false,
|
||||
windowTitle: null,
|
||||
onWindowTapClose: null,
|
||||
backgroundColor: MihColors.getGreenColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
windowBody: Column(
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
Icon(
|
||||
Icons.celebration,
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
size: 150,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
"Congratulations",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
fontSize: 25,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Text(
|
||||
"Your won this game of MIH Minesweeper!!!",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
"Time Taken: ${_formatTime().replaceAll("00:", "")}",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
"Score: ${calculateGameScore(mihMineSweeperProvider)}",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Wrap(
|
||||
runAlignment: WrapAlignment.center,
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
alignment: WrapAlignment.center,
|
||||
spacing: 10,
|
||||
runSpacing: 10,
|
||||
children: [
|
||||
MihButton(
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
showStartGameWindow(mihMineSweeperProvider);
|
||||
},
|
||||
buttonColor: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
width: 300,
|
||||
child: Text(
|
||||
"New Game",
|
||||
style: TextStyle(
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
MihButton(
|
||||
onPressed: () {
|
||||
context.pop();
|
||||
},
|
||||
buttonColor: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
width: 300,
|
||||
child: Text(
|
||||
"View Board",
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
MihButton(
|
||||
onPressed: () {
|
||||
mihMineSweeperProvider.setLeaderboard(leaderboard: null);
|
||||
context.pop();
|
||||
mihMineSweeperProvider.setToolIndex(1);
|
||||
},
|
||||
buttonColor: MihColors.getGoldColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
width: 300,
|
||||
child: Text(
|
||||
"Leader Board",
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_timer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
// UBongani was here during the MIH Live
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MihPackageToolBody(
|
||||
borderOn: false,
|
||||
bodyItem: getBody(),
|
||||
);
|
||||
}
|
||||
|
||||
Widget getBody() {
|
||||
return Consumer2<MzansiProfileProvider, MihMineSweeperProvider>(
|
||||
builder: (BuildContext context, MzansiProfileProvider profileProvider,
|
||||
MihMineSweeperProvider mihMineSweeperProvider, Widget? child) {
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: 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 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 or learn how to play the minesweeper."),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
// 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.symmetric(
|
||||
horizontal: 10.0),
|
||||
child: Text(
|
||||
'Mines: ${mihMineSweeperProvider.totalMines}',
|
||||
textAlign: TextAlign.left,
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10.0),
|
||||
child: Text(
|
||||
_formatTime().replaceAll("00:", ""),
|
||||
textAlign: TextAlign.right,
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
mihMineSweeperProvider.difficulty,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: getDifficultyColor(
|
||||
mihMineSweeperProvider),
|
||||
),
|
||||
),
|
||||
|
||||
// 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(profileProvider,
|
||||
mihMineSweeperProvider, r, c),
|
||||
onLongPress: () => handleLongPress(r, c),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
SizedBox(height: 30),
|
||||
// const SizedBox(height: 100),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 10,
|
||||
bottom: 10,
|
||||
child: MihFloatingMenu(
|
||||
animatedIcon: AnimatedIcons.menu_close,
|
||||
children: [
|
||||
SpeedDialChild(
|
||||
child: Icon(
|
||||
Icons.rule_rounded,
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
),
|
||||
label: "Learn how to play",
|
||||
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: () {
|
||||
mihMineSweeperProvider.setToolIndex(3);
|
||||
},
|
||||
),
|
||||
SpeedDialChild(
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
),
|
||||
label: "Start New 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);
|
||||
},
|
||||
),
|
||||
]),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
_timer != null ? MihBannerAd() : SizedBox(),
|
||||
SizedBox(height: 15),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,880 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mzansi_innovation_hub/main.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tool_body.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_single_child_scroll.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
|
||||
|
||||
class MineSweeperQuickStartGuide extends StatefulWidget {
|
||||
const MineSweeperQuickStartGuide({super.key});
|
||||
|
||||
@override
|
||||
State<MineSweeperQuickStartGuide> createState() =>
|
||||
_MineSweeperQuickStartGuideState();
|
||||
}
|
||||
|
||||
class _MineSweeperQuickStartGuideState
|
||||
extends State<MineSweeperQuickStartGuide> {
|
||||
double titleSize = 22.0;
|
||||
double subtitleSize = 20.0;
|
||||
double pointsSize = 18.0;
|
||||
|
||||
Widget sectionOne() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode != "Darl"),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: Column(
|
||||
children: [
|
||||
// Title
|
||||
Text(
|
||||
"1. Two Main Actions\n(Your Controls)",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: titleSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
//Part One
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: 'Quick Tap (or Click): This is the Dig action.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getGreenColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: subtitleSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: '• Goal:',
|
||||
style: TextStyle(
|
||||
color: MihColors.getGreenColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' To uncover a square and see a number clue.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: '• Risk:',
|
||||
style: TextStyle(
|
||||
color: MihColors.getRedColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' If you click a mine, the game ends!',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
//Part Two
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text:
|
||||
'Tap and Hold (or Long Press): This is the Flag action (🚩).',
|
||||
style: TextStyle(
|
||||
color: MihColors.getRedColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: subtitleSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: '• Goal:',
|
||||
style: TextStyle(
|
||||
color: MihColors.getGreenColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' To safely mark a square that you are',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' certain',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' is a mine.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: '• Risk:',
|
||||
style: TextStyle(
|
||||
color: MihColors.getRedColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
' Accidental placement of flags will cause confusion.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: '• Benefit:',
|
||||
style: TextStyle(
|
||||
color: MihColors.getGreenColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
' You cannot accidentally click a square that is flagged.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget sectionTwo() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode != "Darl"),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: Column(
|
||||
children: [
|
||||
// Title
|
||||
Text(
|
||||
"2. The Golden Rule\n(Reading the Numbers)",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: titleSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
//Part One
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text:
|
||||
'The number tells you exactly how many mines are touching that square (including sides and corners).',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: subtitleSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: "• If you see a Blank Space (a '0'):",
|
||||
style: TextStyle(
|
||||
color: MihColors.getOrangeColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: " Zero (0) ",
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
' mines are touching it. All surrounding squares are safe, and the game will open them for you automatically.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: "• If you see a '1':",
|
||||
style: TextStyle(
|
||||
color: MihColors.getOrangeColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' Only ',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'one',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
' mine is touching this square. You must find and flag that single mine.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: "• If you see a '3':",
|
||||
style: TextStyle(
|
||||
color: MihColors.getOrangeColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: " Three ",
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
'mines are touching this square. You must find and flag all three.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget sectionThree() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode != "Darl"),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: Column(
|
||||
children: [
|
||||
// Title
|
||||
Text(
|
||||
"3. The Winning Strategy\n(The Deduction Loop)",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: titleSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
//Part One
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text:
|
||||
'The game is won by uncovering every single safe square and correctly flagging all the mines. Use this two-step loop to clear the board:',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: subtitleSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: 'A. Find the Mines (Where to Flag 🚩)',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPurpleColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: subtitleSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: '• Goal:',
|
||||
style: TextStyle(
|
||||
color: MihColors.getGreenColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
' Look for a number that only has one choice for a mine. e.g. If a \'1\' is touching only one hidden square, that hidden square',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' must ',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'be the mine.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: '• Action:',
|
||||
style: TextStyle(
|
||||
color: MihColors.getRedColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' Tap and Hold to place a',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' Flag ',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: 'on the square you are sure is a mine.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
//Part Two
|
||||
RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: 'B. Find the Safe Squares (Where to Dig)',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPurpleColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: subtitleSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: '• Goal:',
|
||||
style: TextStyle(
|
||||
color: MihColors.getGreenColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
' Look for a number that has been \'satisfied\' by your flags. e.g. You see a \'2\' and you have already placed two 🚩 flags touching it. The \'2\' is satisfied.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: '• Action:',
|
||||
style: TextStyle(
|
||||
color: MihColors.getRedColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode !=
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
' Quick Tap any of the remaining hidden squares touching that \'satisfied\' number. They',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' must be safe ',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
'because the mine requirement has already been met.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget sectionFour() {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode != "Darl"),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(15.0),
|
||||
child: Column(
|
||||
children: [
|
||||
// Title
|
||||
Text(
|
||||
"✨ Key Beginner Tips",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: titleSize,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: "• Start on the Edges and Corners: ",
|
||||
style: TextStyle(
|
||||
color: MihColors.getBronze(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
'Numbers on the edge or corner of the board are easier to solve because they have fewer surrounding squares to check.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
||||
child: Align(
|
||||
alignment: Alignment.topLeft,
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: "• Don't Guess: ",
|
||||
style: TextStyle(
|
||||
color: MihColors.getBronze(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
'If you are down to two squares and either one could be the mine, look somewhere else on the board for a guaranteed, safe move.',
|
||||
style: TextStyle(
|
||||
color: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode ==
|
||||
"Dark"),
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: pointsSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Size size = MediaQuery.sizeOf(context);
|
||||
final double width = size.width;
|
||||
return MihPackageToolBody(
|
||||
borderOn: false,
|
||||
bodyItem: getBody(width),
|
||||
);
|
||||
}
|
||||
|
||||
Widget getBody(double width) {
|
||||
return MihSingleChildScroll(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: width / 20),
|
||||
child: Column(
|
||||
children: [
|
||||
const Text(
|
||||
'Simple Rules and Strategy',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text(
|
||||
'Minesweeper is a puzzle game where you use numbers to figure out where the hidden bombs (mines) are located.',
|
||||
style: TextStyle(fontSize: 18),
|
||||
),
|
||||
// const Divider(height: 30),
|
||||
const SizedBox(height: 15),
|
||||
sectionOne(),
|
||||
const SizedBox(height: 15),
|
||||
sectionTwo(),
|
||||
const SizedBox(height: 15),
|
||||
sectionThree(),
|
||||
const SizedBox(height: 15),
|
||||
sectionFour(),
|
||||
const SizedBox(height: 15),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:ken_logger/ken_logger.dart';
|
||||
import 'package:mzansi_innovation_hub/main.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_circle_avatar.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_dropdwn_field.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_icons.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tool_body.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_package_components/mih_loading_circle.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_providers/mih_mine_sweeper_provider.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/builders/build_my_scoreboard_list.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_services/mih_minesweeper_services.dart';
|
||||
import 'package:mzansi_innovation_hub/mih_services/mih_validation_services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class MyScoreBoard extends StatefulWidget {
|
||||
const MyScoreBoard({super.key});
|
||||
|
||||
@override
|
||||
State<MyScoreBoard> createState() => _MihMineSweeperLeaderBoardState();
|
||||
}
|
||||
|
||||
class _MihMineSweeperLeaderBoardState extends State<MyScoreBoard> {
|
||||
TextEditingController filterController = TextEditingController();
|
||||
|
||||
Future<void> initialiseLeaderboard() async {
|
||||
MzansiProfileProvider profileProvider =
|
||||
context.read<MzansiProfileProvider>();
|
||||
MihMineSweeperProvider mineSweeperProvider =
|
||||
context.read<MihMineSweeperProvider>();
|
||||
filterController.text = mineSweeperProvider.difficulty;
|
||||
KenLogger.success("getting data");
|
||||
await MihMinesweeperServices()
|
||||
.getMyScoreboard(profileProvider, mineSweeperProvider);
|
||||
KenLogger.success("${mineSweeperProvider.myScoreboard}");
|
||||
}
|
||||
|
||||
void refreshLeaderBoard(
|
||||
MihMineSweeperProvider mineSweeperProvider, String difficulty) {
|
||||
mineSweeperProvider.setDifficulty(difficulty);
|
||||
mineSweeperProvider.setLeaderboard(leaderboard: null);
|
||||
mineSweeperProvider.setMyScoreboard(myScoreboard: null);
|
||||
initialiseLeaderboard();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
await initialiseLeaderboard();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final double width = MediaQuery.sizeOf(context).width;
|
||||
return Consumer<MihMineSweeperProvider>(
|
||||
builder: (BuildContext context,
|
||||
MihMineSweeperProvider mineSweeperProvider, Widget? child) {
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
refreshLeaderBoard(mineSweeperProvider, filterController.text);
|
||||
},
|
||||
child: MihPackageToolBody(
|
||||
borderOn: false,
|
||||
bodyItem: getBody(width),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget getBody(double width) {
|
||||
return Consumer2<MzansiProfileProvider, MihMineSweeperProvider>(
|
||||
builder: (BuildContext context, MzansiProfileProvider profileProvider,
|
||||
MihMineSweeperProvider mineSweeperProvider, Widget? child) {
|
||||
if (mineSweeperProvider.myScoreboard == null) {
|
||||
return Center(
|
||||
child: Mihloadingcircle(),
|
||||
);
|
||||
} else {
|
||||
return Column(
|
||||
children: [
|
||||
Center(
|
||||
child: MihCircleAvatar(
|
||||
imageFile: profileProvider.userProfilePicture,
|
||||
width: 150,
|
||||
editable: false,
|
||||
fileNameController: null,
|
||||
userSelectedfile: null,
|
||||
frameColor: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
backgroundColor: MihColors.getPrimaryColor(
|
||||
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
|
||||
onChange: (selectedImage) {},
|
||||
key: ValueKey(profileProvider.userProfilePicUrl),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: width / 20),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
Flexible(
|
||||
child: MihDropdownField(
|
||||
controller: filterController,
|
||||
hintText: "Scoreboards",
|
||||
dropdownOptions: const [
|
||||
"Very Easy",
|
||||
"Easy",
|
||||
"Intermediate",
|
||||
"Hard",
|
||||
],
|
||||
requiredText: true,
|
||||
editable: true,
|
||||
enableSearch: false,
|
||||
validator: (value) {
|
||||
return MihValidationServices().isEmpty(value);
|
||||
},
|
||||
onSelected: (selection) {
|
||||
refreshLeaderBoard(mineSweeperProvider, selection!);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
mineSweeperProvider.myScoreboard!.isEmpty
|
||||
? 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(
|
||||
"You have played and ${mineSweeperProvider.difficulty} yet.",
|
||||
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(
|
||||
FontAwesomeIcons.bomb,
|
||||
size: 20,
|
||||
color: MihColors.getSecondaryColor(
|
||||
MzansiInnovationHub.of(context)!
|
||||
.theme
|
||||
.mode ==
|
||||
"Dark"),
|
||||
),
|
||||
),
|
||||
TextSpan(text: " and start a new game"),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: Expanded(child: BuildMyScoreBoardList()),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user