Added screens: pause, game over. Added modes: game by levels, game by time limit. Added sounds. Added database for storing points.
BIN
assets/images/game_over_score.png
Normal file
After Width: | Height: | Size: 75 KiB |
4
assets/svg/arrow-left.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 12H5" stroke="#202020" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12 19L5 12L12 5" stroke="#202020" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 315 B |
4
assets/svg/check-circle.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20 11.2686V12.0046C19.999 13.7297 19.4404 15.4083 18.4075 16.79C17.3745 18.1718 15.9226 19.1826 14.2683 19.6717C12.6139 20.1608 10.8458 20.1021 9.22757 19.5042C7.60934 18.9064 6.22772 17.8015 5.28877 16.3542C4.34981 14.907 3.90383 13.195 4.01734 11.4736C4.13085 9.75223 4.79777 8.11364 5.91862 6.80224C7.03948 5.49083 8.55423 4.57688 10.2369 4.1967C11.9197 3.81651 13.6802 3.99045 15.256 4.69258" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M19 6L12.0769 13L10 10.9021" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 718 B |
3
assets/svg/check.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16 5L7.05799 13.3614C6.6736 13.7208 6.0764 13.7208 5.69201 13.3614L2 9.90909" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 276 B |
3
assets/svg/chevron-down.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 9L12 15L18 9" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 214 B |
3
assets/svg/chevron-right.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 18L15 12L9 6" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 214 B |
4
assets/svg/clipboard.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 3H13.5C13.8978 3 14.2794 3.16389 14.5607 3.45561C14.842 3.74733 15 4.143 15 4.55556V15.4444C15 15.857 14.842 16.2527 14.5607 16.5444C14.2794 16.8361 13.8978 17 13.5 17H4.5C4.10218 17 3.72064 16.8361 3.43934 16.5444C3.15804 16.2527 3 15.857 3 15.4444V4.55556C3 4.143 3.15804 3.74733 3.43934 3.45561C3.72064 3.16389 4.10218 3 4.5 3H6" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M11.25 2H6.75C6.33579 2 6 2.33579 6 2.75V4.25C6 4.66421 6.33579 5 6.75 5H11.25C11.6642 5 12 4.66421 12 4.25V2.75C12 2.33579 11.6642 2 11.25 2Z" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 772 B |
5
assets/svg/music.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.66667 13.6667V4.40268C6.66667 3.91384 7.02008 3.49665 7.50227 3.41629L14.8356 2.19407C15.4451 2.09248 16 2.56252 16 3.18046V12.1111" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M4.33333 16C5.622 16 6.66667 14.9553 6.66667 13.6666C6.66667 12.378 5.622 11.3333 4.33333 11.3333C3.04467 11.3333 2 12.378 2 13.6666C2 14.9553 3.04467 16 4.33333 16Z" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M13.6667 13.6667C14.9553 13.6667 16 12.8832 16 11.9167C16 10.9502 14.9553 10.1667 13.6667 10.1667C12.378 10.1667 11.3333 10.9502 11.3333 11.9167C11.3333 12.8832 12.378 13.6667 13.6667 13.6667Z" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 882 B |
5
assets/svg/pause-circle.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="#202020" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10 15V9" stroke="#202020" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M14 15V9" stroke="#202020" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 514 B |
3
assets/svg/star.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.09177 2.97113C8.44903 2.19577 9.55097 2.19577 9.90823 2.97114L11.3156 6.02547C11.4659 6.35169 11.7796 6.57224 12.1374 6.60326L15.5552 6.89953C16.4483 6.97695 16.7963 8.0998 16.1034 8.66866L13.6245 10.704C13.3282 10.9473 13.1971 11.3386 13.287 11.7113L14.0284 14.7861C14.2326 15.6326 13.3324 16.3174 12.5711 15.8949L9.48525 14.1824C9.18343 14.0149 8.81657 14.0149 8.51475 14.1824L5.42894 15.8949C4.66759 16.3174 3.76743 15.6326 3.97156 14.7861L4.71303 11.7113C4.80291 11.3386 4.67178 10.9473 4.37547 10.704L1.89657 8.66866C1.20374 8.0998 1.55168 6.97695 2.44478 6.89953L5.86258 6.60326C6.22042 6.57224 6.53414 6.35169 6.68445 6.02547L8.09177 2.97113Z" stroke="#202020" stroke-width="1.5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 804 B |
6
assets/svg/ticket.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.88727 3.1875V5.0025" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.88727 13.3198V14.8378" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.88727 10.7429V7.1272" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M14 15C15.3666 15 16 14.3496 16 13V11.113C16 10.8368 15.7711 10.6206 15.5074 10.5388C14.8453 10.3334 14.3675 9.72409 14.3675 9.00077C14.3675 8.27745 14.8453 7.66765 15.5074 7.46203C15.7711 7.38013 16 7.16394 16 6.88779V5C16 3.65044 15.3658 3 14 3H3C1.63423 3 1 3.65044 1 5V6.95114C1 7.22728 1.22831 7.44341 1.4937 7.51969C2.15524 7.70983 2.63251 8.27785 2.63251 9.00077C2.63251 9.72409 2.15473 10.3334 1.49263 10.5388C1.22889 10.6206 1 10.8368 1 11.113V13C1 14.3496 1.63345 15 3 15H14Z" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
4
assets/svg/volume.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.3333 3.21478C11.3333 2.35385 10.3178 1.89533 9.67201 2.46467L6.17233 5.55011C5.98967 5.71115 5.75453 5.8 5.51102 5.8H4C2.89543 5.8 2 6.69543 2 7.8V10.2C2 11.3046 2.89543 12.2 4 12.2H5.51102C5.75453 12.2 5.98967 12.2889 6.17233 12.4499L9.67202 15.5353C10.3178 16.1047 11.3333 15.6461 11.3333 14.7852V3.21478Z" stroke="#202020" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M14.4444 6.22815C15.3744 6.78144 16 7.81559 16 9.00005C16 10.1845 15.3744 11.2186 14.4444 11.7719" stroke="#202020" stroke-width="1.5" stroke-linecap="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 679 B |
103
lib/db/main_db.dart
Normal file
@ -0,0 +1,103 @@
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:match_magic/models/isar/high_score.dart';
|
||||
import 'package:match_magic/models/isar/settings.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
class MainDB {
|
||||
MainDB._();
|
||||
static MainDB? _instance;
|
||||
static MainDB get instance => _instance ??= MainDB._();
|
||||
|
||||
Isar? _isar;
|
||||
|
||||
Isar get isar => _isar!;
|
||||
|
||||
Future<bool> initMainDB({Isar? mock}) async {
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
if (mock != null) {
|
||||
_isar = mock;
|
||||
return true;
|
||||
}
|
||||
if (_isar != null && isar.isOpen) return false;
|
||||
|
||||
_isar = await Isar.open(
|
||||
[SettingsSchema, HighScoreSchema],
|
||||
directory: dir.path,
|
||||
inspector: false,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<void> saveSoundEnabled(bool isEnabled) async {
|
||||
print('saveSoundEnabled $isEnabled');
|
||||
final settings = await isar.settings.where().findFirst();
|
||||
await isar.writeTxn(() async {
|
||||
if (settings != null) {
|
||||
settings.isSoundEnabled = isEnabled;
|
||||
await isar.settings.put(settings);
|
||||
} else {
|
||||
final newSettings = Settings(
|
||||
isSoundEnabled: isEnabled,
|
||||
isMusicEnabled: true,
|
||||
);
|
||||
await isar.settings.put(newSettings);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> saveMusicEnabled(bool isEnabled) async {
|
||||
final settings = await isar.settings.where().findFirst();
|
||||
await isar.writeTxn(() async {
|
||||
if (settings != null) {
|
||||
settings.isMusicEnabled = isEnabled;
|
||||
await isar.settings.put(settings);
|
||||
} else {
|
||||
final newSettings = Settings(
|
||||
isSoundEnabled: true,
|
||||
isMusicEnabled: isEnabled,
|
||||
);
|
||||
await isar.settings.put(newSettings);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<bool> getSoundEnabled() async {
|
||||
final settings = await isar.settings.where().findFirst();
|
||||
return settings?.isSoundEnabled ?? true;
|
||||
}
|
||||
|
||||
Future<bool> getMusicEnabled() async {
|
||||
final settings = await isar.settings.where().findFirst();
|
||||
return settings?.isMusicEnabled ?? true;
|
||||
}
|
||||
|
||||
Future<void> addHighScore(int score, Function()? callback) async {
|
||||
final highScore = HighScore(
|
||||
highScoreValue: score,
|
||||
);
|
||||
|
||||
await isar.writeTxn(() async {
|
||||
final existingHighScore = await isar.highScores.where().findFirst();
|
||||
|
||||
if (existingHighScore != null) {
|
||||
if (score > existingHighScore.highScoreValue) {
|
||||
existingHighScore.highScoreValue = score;
|
||||
await isar.highScores.put(existingHighScore);
|
||||
} else {
|
||||
await isar.highScores.put(existingHighScore);
|
||||
}
|
||||
} else {
|
||||
await isar.highScores.put(highScore);
|
||||
}
|
||||
});
|
||||
if (callback != null) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
Future<int?> getHighScoreValue() async {
|
||||
final highScore = await isar.highScores.where().findFirst();
|
||||
|
||||
return highScore?.highScoreValue;
|
||||
}
|
||||
}
|
@ -3,40 +3,65 @@ import 'package:flame/components.dart';
|
||||
import 'package:flame/effects.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:match_magic/db/main_db.dart';
|
||||
import 'package:match_magic/game/game_mode_manager.dart';
|
||||
import 'package:match_magic/game/sprite_loader.dart';
|
||||
import 'package:match_magic/screens/game_over_screen.dart';
|
||||
import 'package:match_magic/utilities/audio_manager.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/hint_button.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/pause_button.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/restart_button.dart';
|
||||
import 'tile.dart';
|
||||
import 'package:flame/sprite.dart';
|
||||
import 'swap_notifier.dart';
|
||||
|
||||
class Board extends FlameGame {
|
||||
final List<Sprite> sprites;
|
||||
final SwapNotifier swapNotifier;
|
||||
final Sprite magicCubeSprite;
|
||||
BuildContext context;
|
||||
final bool gameMode;
|
||||
late GameModeManager gameModeManager;
|
||||
|
||||
static const int rows = 8;
|
||||
static const int cols = 8;
|
||||
late double tileSize;
|
||||
Tile? selectedTile;
|
||||
List<List<Tile?>> tiles = [];
|
||||
int? selectedRow;
|
||||
int? selectedCol;
|
||||
bool animating = false;
|
||||
bool isGridInitialized = false;
|
||||
Tile? lastMovedTile;
|
||||
Tile? lastMovedByGravity;
|
||||
|
||||
static int score = 0;
|
||||
late TextComponent _playerScore;
|
||||
late TextComponent _playerMoves;
|
||||
late TextComponent _remainingTime;
|
||||
bool isFirstLaunch = true;
|
||||
|
||||
Board({
|
||||
required this.sprites,
|
||||
required this.swapNotifier,
|
||||
required this.magicCubeSprite,
|
||||
});
|
||||
bool isGameOver = false;
|
||||
static bool isSoundPlaying = true;
|
||||
|
||||
Board(
|
||||
this.context, {
|
||||
required this.gameMode,
|
||||
}) {
|
||||
gameModeManager = GameModeManager(
|
||||
currentMode: gameMode,
|
||||
onGameOver: _onGameOver,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onLoad() async {
|
||||
super.onLoad();
|
||||
_resetGame();
|
||||
await loadImages();
|
||||
gameModeManager.initializeMode();
|
||||
|
||||
newGame();
|
||||
}
|
||||
|
||||
void _resetGame() {
|
||||
void newGame() {
|
||||
isFirstLaunch = true;
|
||||
resetGame();
|
||||
gameModeManager.initializeMode();
|
||||
tiles.clear();
|
||||
selectedRow = null;
|
||||
selectedCol = null;
|
||||
@ -44,16 +69,82 @@ class Board extends FlameGame {
|
||||
tileSize = size.x / cols;
|
||||
_initializeGrid(isFirstLaunch);
|
||||
_removeInitialMatches();
|
||||
|
||||
isFirstLaunch = false;
|
||||
_playerScore = TextComponent(
|
||||
text: 'Score: ',
|
||||
position: Vector2(60, 70),
|
||||
anchor: Anchor.centerLeft,
|
||||
);
|
||||
add(_playerScore);
|
||||
if (gameModeManager.currentMode) {
|
||||
_playerMoves = TextComponent(
|
||||
text: 'Moves: ',
|
||||
position: Vector2(200, 70),
|
||||
anchor: Anchor.centerLeft,
|
||||
);
|
||||
add(_playerMoves);
|
||||
} else {
|
||||
_remainingTime = TextComponent(
|
||||
text: 'Time: ',
|
||||
position: Vector2(200, 70),
|
||||
anchor: Anchor.centerLeft,
|
||||
);
|
||||
add(_remainingTime);
|
||||
}
|
||||
}
|
||||
|
||||
void restartGame() {
|
||||
isFirstLaunch = true;
|
||||
swapNotifier.resetScore();
|
||||
_resetGame();
|
||||
void resetGame() {
|
||||
isGameOver = false;
|
||||
this.overlays.remove(GameOverMenu.id);
|
||||
|
||||
score = 0;
|
||||
gameModeManager.resetMode();
|
||||
selectedTile = null;
|
||||
final List<Component> tilesToRemove = [];
|
||||
for (final component in children) {
|
||||
if (component is Tile) {
|
||||
tilesToRemove.add(component);
|
||||
}
|
||||
}
|
||||
for (final tile in tilesToRemove) {
|
||||
remove(tile);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void render(Canvas canvas) {
|
||||
super.render(canvas);
|
||||
|
||||
// Progress bar renderer in level mode
|
||||
if (gameModeManager.currentMode == GameMode.levelProgression) {
|
||||
final progressBarWidth = size.x * (score / gameModeManager.targetScore);
|
||||
final progressBarHeight = 20.0;
|
||||
final rect = Rect.fromLTWH(10, size.y - progressBarHeight - 10,
|
||||
progressBarWidth, progressBarHeight);
|
||||
final paint = Paint()..color = Colors.green;
|
||||
canvas.drawRect(rect, paint);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void update(double dt) {
|
||||
_playerScore.text = 'Score: $score';
|
||||
if (gameModeManager.currentMode) {
|
||||
_playerMoves.text = 'Moves: ${GameModeManager.movesLeft}';
|
||||
} else {
|
||||
_remainingTime.text = 'Time: ${gameModeManager.remainingTime}';
|
||||
}
|
||||
if (!isGameOver && gameModeManager.isGameOverCondition()) {
|
||||
_onGameOver();
|
||||
}
|
||||
|
||||
super.update(dt);
|
||||
}
|
||||
|
||||
void _initializeGrid(bool animate) {
|
||||
int totalTiles = rows * cols;
|
||||
int completedTiles = 0;
|
||||
for (int row = 0; row < rows; row++) {
|
||||
List<Tile?> rowTiles = [];
|
||||
for (int col = 0; col < cols; col++) {
|
||||
@ -64,7 +155,7 @@ class Board extends FlameGame {
|
||||
: Vector2(col * tileSize, row * tileSize);
|
||||
|
||||
var tile = Tile(
|
||||
sprite: sprites[spriteIndex],
|
||||
sprite: Tile.crystals[spriteIndex],
|
||||
spriteIndex: spriteIndex,
|
||||
size: Vector2.all(tileSize),
|
||||
position: initialPosition,
|
||||
@ -80,22 +171,31 @@ class Board extends FlameGame {
|
||||
|
||||
tile.add(
|
||||
MoveEffect.to(
|
||||
Vector2(col * tileSize, row * tileSize),
|
||||
Vector2(col * tileSize, row * tileSize + 200),
|
||||
EffectController(
|
||||
duration: 0.5,
|
||||
startDelay: delay,
|
||||
curve: Curves.bounceOut,
|
||||
),
|
||||
onComplete: () {
|
||||
completedTiles++;
|
||||
if (completedTiles == totalTiles) {
|
||||
isGridInitialized = true;
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
tiles.add(rowTiles);
|
||||
}
|
||||
if (!animate) {
|
||||
isGridInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
int _randomElement() {
|
||||
return Random().nextInt(sprites.length);
|
||||
return Random().nextInt(Tile.crystals.length);
|
||||
}
|
||||
|
||||
void _removeInitialMatches() {
|
||||
@ -106,7 +206,7 @@ class Board extends FlameGame {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
if (_hasMatch(row, col)) {
|
||||
int spriteIndex = _randomElement();
|
||||
tiles[row][col]!.sprite = sprites[spriteIndex];
|
||||
tiles[row][col]!.sprite = Tile.crystals[spriteIndex];
|
||||
tiles[row][col]!.spriteIndex = spriteIndex;
|
||||
hasMatches = true;
|
||||
}
|
||||
@ -115,53 +215,53 @@ class Board extends FlameGame {
|
||||
} while (hasMatches);
|
||||
}
|
||||
|
||||
// Future<void> handleTileSwipe(Tile tile, Vector2 delta) async {
|
||||
// if (animating) return;
|
||||
int _calculateScore(int matchLength) {
|
||||
if (matchLength == 3) {
|
||||
return 50;
|
||||
} else if (matchLength == 4) {
|
||||
return 400;
|
||||
} else if (matchLength == 5) {
|
||||
return 200;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// int row = tile.row;
|
||||
// int col = tile.col;
|
||||
// Tile? targetTile;
|
||||
// Moving elements
|
||||
|
||||
// if (delta.x.abs() > delta.y.abs()) {
|
||||
// if (delta.x > 0 && col < cols - 1) {
|
||||
// targetTile = tiles[row][col + 1];
|
||||
// } else if (delta.x < 0 && col > 0) {
|
||||
// targetTile = tiles[row][col - 1];
|
||||
// }
|
||||
// } else {
|
||||
// if (delta.y > 0 && row < rows - 1) {
|
||||
// targetTile = tiles[row + 1][col];
|
||||
// } else if (delta.y < 0 && row > 0) {
|
||||
// targetTile = tiles[row - 1][col];
|
||||
// }
|
||||
// }
|
||||
void selectTile(Tile tile) {
|
||||
if (selectedTile == null) {
|
||||
selectedTile = tile;
|
||||
tile.select();
|
||||
} else {
|
||||
if (_isNeighbor(selectedTile!, tile) || selectedTile!.isMagicCube) {
|
||||
} else {
|
||||
selectedTile?.deselect();
|
||||
selectedTile = tile;
|
||||
tile.select();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (targetTile != null) {
|
||||
// animating = true;
|
||||
// lastMovedTile = tile;
|
||||
// swapTiles(tile, targetTile, true);
|
||||
|
||||
// await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
// if (!checkMatches()) {
|
||||
// swapTiles(tile, targetTile, true);
|
||||
// } else {
|
||||
// swapNotifier.incrementMoveCount();
|
||||
// }
|
||||
// selectedRow = null;
|
||||
// selectedCol = null;
|
||||
// animating = false;
|
||||
// }
|
||||
// }
|
||||
bool _isNeighbor(Tile tile1, Tile tile2) {
|
||||
return (tile1.row == tile2.row && (tile1.col - tile2.col).abs() == 1) ||
|
||||
(tile1.col == tile2.col && (tile1.row - tile2.row).abs() == 1);
|
||||
}
|
||||
|
||||
Future<void> handleTileSwipe(Tile tile, Vector2 delta) async {
|
||||
if (animating) return;
|
||||
if (!isGridInitialized || animating) return;
|
||||
Tile? targetTile;
|
||||
|
||||
if (tile.isMagicCube) {
|
||||
targetTile = _getTileBySwipeDirection(tile, delta);
|
||||
if (targetTile != null) {
|
||||
_removeAllOfType(targetTile.spriteIndex);
|
||||
_animateRemoveTile(tile);
|
||||
isSoundPlaying = await MainDB.instance.getSoundEnabled();
|
||||
if (isSoundPlaying) {
|
||||
AudioManager.playExplosionSound();
|
||||
}
|
||||
|
||||
tiles[tile.row][tile.col] = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -174,11 +274,11 @@ class Board extends FlameGame {
|
||||
swapTiles(tile, targetTile, true);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
if (!checkMatches()) {
|
||||
bool matchesFound = await checkMatches();
|
||||
if (!matchesFound) {
|
||||
swapTiles(tile, targetTile, true);
|
||||
} else {
|
||||
swapNotifier.incrementMoveCount();
|
||||
GameModeManager.movesLeft--;
|
||||
}
|
||||
selectedRow = null;
|
||||
selectedCol = null;
|
||||
@ -207,28 +307,7 @@ class Board extends FlameGame {
|
||||
return targetTile;
|
||||
}
|
||||
|
||||
void _removeAllOfType(int spriteIndex) {
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
if (tiles[row][col]?.spriteIndex == spriteIndex) {
|
||||
_animateRemoveTile(tiles[row][col]!);
|
||||
tiles[row][col] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_applyGravity();
|
||||
_fillEmptySpaces();
|
||||
}
|
||||
|
||||
bool _isAdjacent(int row1, int col1, int row2, int col2) {
|
||||
return (row1 == row2 && (col1 - col2).abs() == 1) ||
|
||||
(col1 == col2 && (row1 - row2).abs() == 1);
|
||||
}
|
||||
|
||||
void swapTiles(Tile tile1, Tile tile2, bool animate) {
|
||||
// final tempPosition1 = tile1.position.clone();
|
||||
// final tempPosition2 = tile2.position.clone();
|
||||
final tempRow1 = tile1.row;
|
||||
final tempCol1 = tile1.col;
|
||||
final tempRow2 = tile2.row;
|
||||
@ -252,7 +331,49 @@ class Board extends FlameGame {
|
||||
tile1.deselect();
|
||||
}
|
||||
|
||||
bool checkMatches({bool simulate = false}) {
|
||||
// Hint button
|
||||
|
||||
Future<Tile?> findHint() async {
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
Tile? tile = tiles[row][col];
|
||||
|
||||
if (col < cols - 1 && await _canSwap(row, col, row, col + 1)) {
|
||||
return tile;
|
||||
}
|
||||
if (row < rows - 1 && await _canSwap(row, col, row + 1, col)) {
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<bool> _canSwap(int row1, int col1, int row2, int col2) async {
|
||||
Tile tempTile1 = tiles[row1][col1]!;
|
||||
Tile tempTile2 = tiles[row2][col2]!;
|
||||
|
||||
tiles[row1][col1] = tempTile2;
|
||||
tiles[row2][col2] = tempTile1;
|
||||
|
||||
bool matchFound = await checkMatches(simulate: true);
|
||||
|
||||
tiles[row1][col1] = tempTile1;
|
||||
tiles[row2][col2] = tempTile2;
|
||||
|
||||
return matchFound;
|
||||
}
|
||||
|
||||
void showHint() async {
|
||||
Tile? hintTile = await findHint();
|
||||
if (hintTile != null) {
|
||||
hintTile.select();
|
||||
}
|
||||
}
|
||||
|
||||
// Match checks
|
||||
|
||||
Future<bool> checkMatches({bool simulate = false}) async {
|
||||
if (simulate) {
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
@ -279,7 +400,10 @@ class Board extends FlameGame {
|
||||
for (final match in matches) {
|
||||
points += _removeMatchedElements(match[0], match[1]);
|
||||
}
|
||||
isSoundPlaying = await MainDB.instance.getSoundEnabled();
|
||||
if (isSoundPlaying) {
|
||||
AudioManager.playSelectSound();
|
||||
}
|
||||
Future.delayed(const Duration(milliseconds: 300), () {
|
||||
_applyGravity();
|
||||
Future.delayed(const Duration(milliseconds: 300), () {
|
||||
@ -290,7 +414,7 @@ class Board extends FlameGame {
|
||||
});
|
||||
});
|
||||
});
|
||||
swapNotifier.incrementScore(points);
|
||||
score += points;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -302,46 +426,81 @@ class Board extends FlameGame {
|
||||
final value = tiles[row][col]?.spriteIndex;
|
||||
|
||||
int count = 1;
|
||||
for (int i = col + 1; i < cols && tiles[row][i]?.spriteIndex == value; i++)
|
||||
for (int i = col + 1;
|
||||
i < cols && tiles[row][i]?.spriteIndex == value;
|
||||
i++) {
|
||||
count++;
|
||||
for (int i = col - 1; i >= 0 && tiles[row][i]?.spriteIndex == value; i--)
|
||||
}
|
||||
for (int i = col - 1; i >= 0 && tiles[row][i]?.spriteIndex == value; i--) {
|
||||
count++;
|
||||
}
|
||||
if (count >= 3) return true;
|
||||
|
||||
count = 1;
|
||||
for (int i = row + 1; i < rows && tiles[i][col]?.spriteIndex == value; i++)
|
||||
for (int i = row + 1;
|
||||
i < rows && tiles[i][col]?.spriteIndex == value;
|
||||
i++) {
|
||||
count++;
|
||||
for (int i = row - 1; i >= 0 && tiles[i][col]?.spriteIndex == value; i--)
|
||||
}
|
||||
for (int i = row - 1; i >= 0 && tiles[i][col]?.spriteIndex == value; i--) {
|
||||
count++;
|
||||
}
|
||||
return count >= 3;
|
||||
}
|
||||
|
||||
// Removing items
|
||||
|
||||
void _removeAllOfType(int spriteIndex) {
|
||||
int removedCount = 0;
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
if (tiles[row][col]?.spriteIndex == spriteIndex) {
|
||||
_animateRemoveTile(tiles[row][col]!);
|
||||
tiles[row][col] = null;
|
||||
removedCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
score += removedCount * 100;
|
||||
Future.delayed(const Duration(milliseconds: 300), () {
|
||||
_applyGravity();
|
||||
Future.delayed(const Duration(milliseconds: 300), () {
|
||||
_fillEmptySpaces();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
int _removeMatchedElements(int row, int col) {
|
||||
int score = 0;
|
||||
final int? value = tiles[row][col]?.spriteIndex;
|
||||
bool bombTriggered = false;
|
||||
Tile? tileToTransformIntoBomb = null;
|
||||
bool specialTriggered = false;
|
||||
Tile? tileToTransformIntoSpecial;
|
||||
|
||||
int left = col;
|
||||
while (left > 0 && tiles[row][left - 1]?.spriteIndex == value) left--;
|
||||
while (left > 0 && tiles[row][left - 1]?.spriteIndex == value) {
|
||||
left--;
|
||||
}
|
||||
int right = col;
|
||||
while (right < cols - 1 && tiles[row][right + 1]?.spriteIndex == value)
|
||||
while (right < cols - 1 && tiles[row][right + 1]?.spriteIndex == value) {
|
||||
right++;
|
||||
}
|
||||
|
||||
if (right - left + 1 >= 3) {
|
||||
score += _calculateScore(right - left + 1);
|
||||
|
||||
if (right - left + 1 >= 4) {
|
||||
tileToTransformIntoBomb = lastMovedTile ?? lastMovedByGravity;
|
||||
if (right - left + 1 == 4) {
|
||||
tileToTransformIntoSpecial = lastMovedTile ?? lastMovedByGravity;
|
||||
} else if (right - left + 1 >= 5) {
|
||||
tileToTransformIntoSpecial = lastMovedTile ?? lastMovedByGravity;
|
||||
}
|
||||
|
||||
for (int i = left; i <= right; i++) {
|
||||
if (tiles[row][i] != null) {
|
||||
if (tiles[row][i]!.isBomb) {
|
||||
bombTriggered = true;
|
||||
specialTriggered = true;
|
||||
_triggerBomb(row, i);
|
||||
}
|
||||
if (tiles[row][i] != tileToTransformIntoBomb) {
|
||||
if (tiles[row][i] != tileToTransformIntoSpecial) {
|
||||
_animateRemoveTile(tiles[row][i]!);
|
||||
tiles[row][i] = null;
|
||||
}
|
||||
@ -350,25 +509,30 @@ class Board extends FlameGame {
|
||||
}
|
||||
|
||||
int top = row;
|
||||
while (top > 0 && tiles[top - 1][col]?.spriteIndex == value) top--;
|
||||
while (top > 0 && tiles[top - 1][col]?.spriteIndex == value) {
|
||||
top--;
|
||||
}
|
||||
int bottom = row;
|
||||
while (bottom < rows - 1 && tiles[bottom + 1][col]?.spriteIndex == value)
|
||||
while (bottom < rows - 1 && tiles[bottom + 1][col]?.spriteIndex == value) {
|
||||
bottom++;
|
||||
}
|
||||
|
||||
if (bottom - top + 1 >= 3) {
|
||||
score += _calculateScore(bottom - top + 1);
|
||||
|
||||
if (bottom - top + 1 >= 4) {
|
||||
tileToTransformIntoBomb = lastMovedTile ?? lastMovedByGravity;
|
||||
if (bottom - top + 1 == 4) {
|
||||
tileToTransformIntoSpecial = lastMovedTile ?? lastMovedByGravity;
|
||||
} else if (bottom - top + 1 >= 5) {
|
||||
tileToTransformIntoSpecial = lastMovedTile ?? lastMovedByGravity;
|
||||
}
|
||||
|
||||
for (int i = top; i <= bottom; i++) {
|
||||
if (tiles[i][col] != null) {
|
||||
if (tiles[i][col]!.isBomb) {
|
||||
bombTriggered = true;
|
||||
specialTriggered = true;
|
||||
_triggerBomb(i, col);
|
||||
}
|
||||
if (tiles[i][col] != tileToTransformIntoBomb) {
|
||||
if (tiles[i][col] != tileToTransformIntoSpecial) {
|
||||
_animateRemoveTile(tiles[i][col]!);
|
||||
tiles[i][col] = null;
|
||||
}
|
||||
@ -376,19 +540,82 @@ class Board extends FlameGame {
|
||||
}
|
||||
}
|
||||
|
||||
if (bombTriggered) {
|
||||
_triggerBomb(row, col);
|
||||
if (tileToTransformIntoSpecial != null) {
|
||||
if ((right - left + 1 >= 5) || (bottom - top + 1 >= 5)) {
|
||||
_createMagicCube(
|
||||
tileToTransformIntoSpecial.row, tileToTransformIntoSpecial.col);
|
||||
} else {
|
||||
_createBomb(
|
||||
tileToTransformIntoSpecial.row, tileToTransformIntoSpecial.col);
|
||||
}
|
||||
}
|
||||
|
||||
if (tileToTransformIntoBomb != null) {
|
||||
_createBomb(tileToTransformIntoBomb.row, tileToTransformIntoBomb.col);
|
||||
AudioManager.playFourElementsSound();
|
||||
if (specialTriggered) {
|
||||
_triggerBomb(row, col);
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
void _triggerBomb(int row, int col) {
|
||||
void _animateRemoveTile(Tile tile) {
|
||||
tile.add(ScaleEffect.to(
|
||||
Vector2.zero(),
|
||||
EffectController(
|
||||
duration: 0.2,
|
||||
curve: Curves.easeInBack,
|
||||
),
|
||||
onComplete: () => tile.removeFromParent(),
|
||||
));
|
||||
}
|
||||
|
||||
// The emergence of new elements
|
||||
|
||||
void _applyGravity() {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
for (int row = rows - 1; row >= 0; row--) {
|
||||
if (tiles[row][col] == null) {
|
||||
for (int k = row - 1; k >= 0; k--) {
|
||||
if (tiles[k][col] != null) {
|
||||
tiles[row][col] = tiles[k][col]!;
|
||||
tiles[k][col] = null;
|
||||
tiles[row][col]!.row = row;
|
||||
tiles[row][col]!.animateMoveTo(
|
||||
Vector2(col * tileSize, row * tileSize + 200), () {});
|
||||
lastMovedByGravity = tiles[row][col];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _fillEmptySpaces() {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
for (int row = rows - 1; row >= 0; row--) {
|
||||
if (tiles[row][col] == null) {
|
||||
int spriteIndex = _randomElement();
|
||||
var tile = Tile(
|
||||
sprite: Tile.crystals[spriteIndex],
|
||||
spriteIndex: spriteIndex,
|
||||
size: Vector2.all(tileSize),
|
||||
position: Vector2(col * tileSize, -tileSize),
|
||||
row: row,
|
||||
col: col,
|
||||
onSwipe: handleTileSwipe,
|
||||
);
|
||||
tiles[row][col] = tile;
|
||||
add(tile);
|
||||
tile.animateMoveTo(
|
||||
Vector2(col * tileSize, row * tileSize + 200), () {});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bomb
|
||||
|
||||
void _triggerBomb(int row, int col) async {
|
||||
final tile = tiles[row][col];
|
||||
if (tile == null || !tile.isBomb) return;
|
||||
|
||||
@ -412,8 +639,11 @@ class Board extends FlameGame {
|
||||
|
||||
_animateRemoveTile(tile);
|
||||
tiles[row][col] = null;
|
||||
isSoundPlaying = await MainDB.instance.getSoundEnabled();
|
||||
if (isSoundPlaying) {
|
||||
AudioManager.playExplosionSound();
|
||||
}
|
||||
}
|
||||
|
||||
void _animateBombExplosion(Vector2 position) {
|
||||
final explosion = CircleComponent(
|
||||
@ -433,36 +663,11 @@ class Board extends FlameGame {
|
||||
);
|
||||
}
|
||||
|
||||
int _calculateScore(int matchLength) {
|
||||
if (matchLength == 3) {
|
||||
return 50;
|
||||
} else if (matchLength == 4) {
|
||||
return 100;
|
||||
} else if (matchLength == 5) {
|
||||
return 200;
|
||||
void _createBomb(int row, int col) async {
|
||||
isSoundPlaying = await MainDB.instance.getSoundEnabled();
|
||||
if (isSoundPlaying) {
|
||||
AudioManager.playFourElementsSound();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// void _animateRemoveTile(Tile tile) {
|
||||
// tile.add(RemoveEffect(
|
||||
// delay: 0.5,
|
||||
// onComplete: () => remove(tile),
|
||||
// ));
|
||||
// }
|
||||
|
||||
void _animateRemoveTile(Tile tile) {
|
||||
tile.add(ScaleEffect.to(
|
||||
Vector2.zero(),
|
||||
EffectController(
|
||||
duration: 0.2,
|
||||
curve: Curves.easeInBack,
|
||||
),
|
||||
onComplete: () => tile.removeFromParent(),
|
||||
));
|
||||
}
|
||||
|
||||
void _createBomb(int row, int col) {
|
||||
final tile = tiles[row][col];
|
||||
if (tile != null) {
|
||||
tile.isBomb = true;
|
||||
@ -493,12 +698,6 @@ class Board extends FlameGame {
|
||||
}
|
||||
}
|
||||
|
||||
void _createMagicCube(int row, int col) {
|
||||
var tile = tiles[row][col];
|
||||
tile?.sprite = magicCubeSprite;
|
||||
tile?.isMagicCube = true;
|
||||
}
|
||||
|
||||
void explodeBomb(Tile bombTile) {
|
||||
final bombPosition = bombTile.position.clone();
|
||||
final bombRow = bombTile.row;
|
||||
@ -521,259 +720,39 @@ class Board extends FlameGame {
|
||||
tiles[bombRow][bombCol] = null;
|
||||
}
|
||||
|
||||
void _applyGravity() {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
for (int row = rows - 1; row >= 0; row--) {
|
||||
if (tiles[row][col] == null) {
|
||||
for (int k = row - 1; k >= 0; k--) {
|
||||
if (tiles[k][col] != null) {
|
||||
tiles[row][col] = tiles[k][col]!;
|
||||
tiles[k][col] = null;
|
||||
tiles[row][col]!.row = row;
|
||||
tiles[row][col]!.animateMoveTo(
|
||||
Vector2(col * tileSize, row * tileSize), () {});
|
||||
lastMovedByGravity = tiles[row][col];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Magic cube
|
||||
|
||||
void _createMagicCube(int row, int col) async {
|
||||
isSoundPlaying = await MainDB.instance.getSoundEnabled();
|
||||
if (isSoundPlaying) {
|
||||
AudioManager.playFourElementsSound();
|
||||
}
|
||||
var tile = tiles[row][col];
|
||||
tile?.sprite = Tile.magicCubeSprite;
|
||||
tile?.isMagicCube = true;
|
||||
}
|
||||
|
||||
void _fillEmptySpaces() {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
for (int row = rows - 1; row >= 0; row--) {
|
||||
if (tiles[row][col] == null) {
|
||||
int spriteIndex = _randomElement();
|
||||
var tile = Tile(
|
||||
sprite: sprites[spriteIndex],
|
||||
spriteIndex: spriteIndex,
|
||||
size: Vector2.all(tileSize),
|
||||
position: Vector2(col * tileSize, -tileSize),
|
||||
row: row,
|
||||
col: col,
|
||||
// onTileTap: handleTileTap,
|
||||
onSwipe: handleTileSwipe,
|
||||
);
|
||||
tiles[row][col] = tile;
|
||||
add(tile);
|
||||
tile.animateMoveTo(Vector2(col * tileSize, row * tileSize), () {});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Game over
|
||||
|
||||
void _onGameOver() {
|
||||
print("Game Over! Score: ${score}");
|
||||
showGameOverScreen();
|
||||
}
|
||||
|
||||
Tile? findHint() {
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
Tile? tile = tiles[row][col];
|
||||
|
||||
if (col < cols - 1 && _canSwap(row, col, row, col + 1)) {
|
||||
return tile;
|
||||
}
|
||||
if (row < rows - 1 && _canSwap(row, col, row + 1, col)) {
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
void showGameOverScreen() {
|
||||
isGameOver = true;
|
||||
remove(_playerScore);
|
||||
if (gameModeManager.currentMode) {
|
||||
remove(_playerMoves);
|
||||
} else {
|
||||
remove(_remainingTime);
|
||||
}
|
||||
|
||||
bool _canSwap(int row1, int col1, int row2, int col2) {
|
||||
Tile tempTile1 = tiles[row1][col1]!;
|
||||
Tile tempTile2 = tiles[row2][col2]!;
|
||||
|
||||
tiles[row1][col1] = tempTile2;
|
||||
tiles[row2][col2] = tempTile1;
|
||||
|
||||
bool matchFound = checkMatches(simulate: true);
|
||||
|
||||
tiles[row1][col1] = tempTile1;
|
||||
tiles[row2][col2] = tempTile2;
|
||||
|
||||
return matchFound;
|
||||
}
|
||||
|
||||
void showHint() {
|
||||
Tile? hintTile = findHint();
|
||||
if (hintTile != null) {
|
||||
hintTile.select();
|
||||
this.overlays.remove(PauseButton.id);
|
||||
this.overlays.remove(RestartButton.id);
|
||||
this.overlays.remove(HintButton.id);
|
||||
MainDB.instance.addHighScore(score, () {
|
||||
this.overlays.add(GameOverMenu.id);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// void handleTileTap(Tile tappedTile) {
|
||||
// if (animating) return;
|
||||
|
||||
// int row = tappedTile.row;
|
||||
// int col = tappedTile.col;
|
||||
|
||||
// if (selectedRow == null || selectedCol == null) {
|
||||
// tappedTile.select();
|
||||
// selectedRow = row;
|
||||
// selectedCol = col;
|
||||
// } else {
|
||||
// tiles[selectedRow!][selectedCol!]?.deselect();
|
||||
// if (_isAdjacent(selectedRow!, selectedCol!, row, col)) {
|
||||
// lastMovedTile = tiles[selectedRow!][selectedCol!];
|
||||
// swapTiles(tiles[selectedRow!][selectedCol!]!, tiles[row][col]!, true);
|
||||
// Future.delayed(const Duration(milliseconds: 300), () {
|
||||
// if (!checkMatches()) {
|
||||
// swapTiles(
|
||||
// tiles[row][col]!, tiles[selectedRow!][selectedCol!]!, true);
|
||||
// }
|
||||
// selectedRow = null;
|
||||
// selectedCol = null;
|
||||
// });
|
||||
// } else {
|
||||
// tiles[selectedRow!][selectedCol!]?.deselect();
|
||||
// tappedTile.select();
|
||||
// selectedRow = row;
|
||||
// selectedCol = col;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// int _removeMatchedElements(int row, int col) {
|
||||
// int score = 0;
|
||||
// final int? value = tiles[row][col]?.spriteIndex;
|
||||
// bool bombTriggered = false;
|
||||
// Tile? tileToTransformIntoBomb = null;
|
||||
|
||||
// int left = col;
|
||||
// while (left > 0 && tiles[row][left - 1]?.spriteIndex == value) left--;
|
||||
// int right = col;
|
||||
// while (right < cols - 1 && tiles[row][right + 1]?.spriteIndex == value)
|
||||
// right++;
|
||||
|
||||
// if (right - left + 1 >= 3) {
|
||||
// score += _calculateScore(right - left + 1);
|
||||
|
||||
// if (right - left + 1 >= 4 &&
|
||||
// lastMovedTile != null &&
|
||||
// lastMovedTile!.row == row &&
|
||||
// lastMovedTile!.col >= left &&
|
||||
// lastMovedTile!.col <= right) {
|
||||
// tileToTransformIntoBomb = lastMovedTile;
|
||||
// }
|
||||
|
||||
// for (int i = left; i <= right; i++) {
|
||||
// if (tiles[row][i] != null) {
|
||||
// if (tiles[row][i]!.isBomb) {
|
||||
// bombTriggered = true;
|
||||
// _triggerBomb(row, i);
|
||||
// }
|
||||
// if (tiles[row][i] != tileToTransformIntoBomb) {
|
||||
// _animateRemoveTile(tiles[row][i]!);
|
||||
// tiles[row][i] = null;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// int top = row;
|
||||
// while (top > 0 && tiles[top - 1][col]?.spriteIndex == value) top--;
|
||||
// int bottom = row;
|
||||
// while (bottom < rows - 1 && tiles[bottom + 1][col]?.spriteIndex == value)
|
||||
// bottom++;
|
||||
|
||||
// if (bottom - top + 1 >= 3) {
|
||||
// score += _calculateScore(bottom - top + 1);
|
||||
|
||||
// if (bottom - top + 1 >= 4 &&
|
||||
// lastMovedTile != null &&
|
||||
// lastMovedTile!.col == col &&
|
||||
// lastMovedTile!.row >= top &&
|
||||
// lastMovedTile!.row <= bottom) {
|
||||
// tileToTransformIntoBomb = lastMovedTile;
|
||||
// }
|
||||
|
||||
// for (int i = top; i <= bottom; i++) {
|
||||
// if (tiles[i][col] != null) {
|
||||
// if (tiles[i][col]!.isBomb) {
|
||||
// bombTriggered = true;
|
||||
// _triggerBomb(i, col);
|
||||
// }
|
||||
// if (tiles[i][col] != tileToTransformIntoBomb) {
|
||||
// _animateRemoveTile(tiles[i][col]!);
|
||||
// tiles[i][col] = null;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (bombTriggered) {
|
||||
// _triggerBomb(row, col);
|
||||
// }
|
||||
|
||||
// if (tileToTransformIntoBomb != null) {
|
||||
// _createBomb(tileToTransformIntoBomb.row, tileToTransformIntoBomb.col);
|
||||
// }
|
||||
|
||||
// return score;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// void explodeBomb(Tile bombTile) {
|
||||
// final bombPosition = bombTile.position;
|
||||
// final bombRow = bombTile.row;
|
||||
// final bombCol = bombTile.col;
|
||||
|
||||
// for (int rowOffset = -1; rowOffset <= 1; rowOffset++) {
|
||||
// for (int colOffset = -1; colOffset <= 1; colOffset++) {
|
||||
// final row = bombRow + rowOffset;
|
||||
// final col = bombCol + colOffset;
|
||||
|
||||
// if (row >= 0 && row < rows && col >= 0 && col < cols) {
|
||||
// final tile = tiles[row][col];
|
||||
// if (tile != null && tile != bombTile) {
|
||||
// _animateRemoveTile(tile);
|
||||
// tiles[row][col] = null;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// bombTile.add(RemoveEffect(
|
||||
// delay: 0.5,
|
||||
// onComplete: () => remove(bombTile),
|
||||
// ));
|
||||
|
||||
// final explosion = CircleComponent(
|
||||
// radius: tileSize / 2,
|
||||
// paint: Paint()..color = Colors.orange.withOpacity(0.7),
|
||||
// position: bombPosition,
|
||||
// );
|
||||
// add(explosion);
|
||||
|
||||
// explosion.add(ScaleEffect.to(
|
||||
// Vector2.all(2),
|
||||
// EffectController(duration: 0.5),
|
||||
// onComplete: () => explosion.removeFromParent(),
|
||||
// ));
|
||||
// }
|
||||
|
||||
|
||||
// void _applyGravity() {
|
||||
// for (int col = 0; col < cols; col++) {
|
||||
// for (int row = rows - 1; row >= 0; row--) {
|
||||
// if (tiles[row][col] == null) {
|
||||
// for (int k = row - 1; k >= 0; k--) {
|
||||
// if (tiles[k][col] != null) {
|
||||
// tiles[row][col] = tiles[k][col]!;
|
||||
// tiles[k][col] = null;
|
||||
// tiles[row][col]!.row = row;
|
||||
// tiles[row][col]!.animateMoveTo(
|
||||
// Vector2(col * tileSize, row * tileSize), () {});
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
89
lib/game/game_mode_manager.dart
Normal file
@ -0,0 +1,89 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:match_magic/game/board.dart';
|
||||
|
||||
enum GameMode {
|
||||
timeAttack,
|
||||
levelProgression,
|
||||
}
|
||||
|
||||
class GameModeManager {
|
||||
final bool currentMode;
|
||||
final VoidCallback onGameOver;
|
||||
|
||||
int remainingTime = 20;
|
||||
int targetScore = 5000;
|
||||
int currentLevel = 1;
|
||||
static int movesLeft = 20;
|
||||
|
||||
Timer? _timer;
|
||||
|
||||
GameModeManager({
|
||||
required this.currentMode,
|
||||
required this.onGameOver,
|
||||
});
|
||||
|
||||
void initializeMode() {
|
||||
if (currentMode) {
|
||||
_startLevelProgressionMode();
|
||||
} else if (!currentMode) {
|
||||
_startTimeAttackMode();
|
||||
}
|
||||
}
|
||||
|
||||
// Reset modes
|
||||
void resetMode() {
|
||||
_timer?.cancel();
|
||||
remainingTime = 20;
|
||||
currentLevel = 1;
|
||||
movesLeft = 20;
|
||||
}
|
||||
|
||||
// Time mode
|
||||
void _startTimeAttackMode() {
|
||||
_timer = Timer.periodic(Duration(seconds: 1), (timer) {
|
||||
if (remainingTime > 0) {
|
||||
remainingTime--;
|
||||
} else {
|
||||
onGameOver();
|
||||
_timer?.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Levels mode
|
||||
void _startLevelProgressionMode() {
|
||||
movesLeft = 20; // Number of moves per level
|
||||
}
|
||||
|
||||
// Time update
|
||||
void updateTime(double dt) {}
|
||||
|
||||
// Game Completion Logic
|
||||
bool isGameOverCondition() {
|
||||
if (!currentMode) {
|
||||
return remainingTime <= 0;
|
||||
} else if (currentMode) {
|
||||
return movesLeft <= 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Moving to the next level
|
||||
void nextLevel() {
|
||||
if (Board.score >= targetScore) {
|
||||
currentLevel++;
|
||||
targetScore += 100;
|
||||
movesLeft = 20;
|
||||
}
|
||||
}
|
||||
|
||||
// Updating the number of remaining moves
|
||||
void updateMoves(int movesUsed) {
|
||||
movesLeft -= movesUsed;
|
||||
if (movesLeft <= 0 && Board.score < targetScore) {
|
||||
onGameOver();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,245 +0,0 @@
|
||||
import 'package:flame/components.dart';
|
||||
import 'package:flame/game.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:match_magic/game/sprite_loader.dart';
|
||||
import 'package:match_magic/utilities/audio_manager.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'board.dart';
|
||||
import 'swap_notifier.dart';
|
||||
|
||||
class MatchMagicGameScreen extends StatefulWidget {
|
||||
const MatchMagicGameScreen({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_MatchMagicGameScreenState createState() => _MatchMagicGameScreenState();
|
||||
}
|
||||
|
||||
class _MatchMagicGameScreenState extends State<MatchMagicGameScreen> {
|
||||
late Future<List<Sprite>> _crystalsFuture;
|
||||
late Future<Sprite> _magicCubeFuture;
|
||||
Board? board;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_crystalsFuture = SpriteLoader.loadCrystalSprites();
|
||||
_magicCubeFuture = SpriteLoader.loadMagicCubeSprite();
|
||||
AudioManager.load();
|
||||
}
|
||||
|
||||
void _restartGame() {
|
||||
context.read<SwapNotifier>().resetScore();
|
||||
setState(() {
|
||||
board = null;
|
||||
_crystalsFuture = SpriteLoader.loadCrystalSprites();
|
||||
_magicCubeFuture = SpriteLoader.loadMagicCubeSprite();
|
||||
});
|
||||
}
|
||||
|
||||
void _showSettingsDialog() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Settings'),
|
||||
content: const Text('The settings have not yet been implemented.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
_showExitConfirmationDialog();
|
||||
},
|
||||
child: const Text('Exit to Main Menu'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Close'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _showExitConfirmationDialog() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Warning'),
|
||||
content: const Text(
|
||||
'You will lose all game progress. Are you sure you want to exit?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
context.read<SwapNotifier>().resetScore();
|
||||
},
|
||||
child: const Text('Yes'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('No'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
body: FutureBuilder<List<Sprite>>(
|
||||
future: _crystalsFuture,
|
||||
builder: (context, crystalSnapshot) {
|
||||
if (crystalSnapshot.connectionState == ConnectionState.done) {
|
||||
if (crystalSnapshot.hasError) {
|
||||
return Center(child: Text('Error: ${crystalSnapshot.error}'));
|
||||
} else if (!crystalSnapshot.hasData ||
|
||||
crystalSnapshot.data == null) {
|
||||
return const Center(child: Text('No crystal sprites found'));
|
||||
} else {
|
||||
final crystals = crystalSnapshot.data!;
|
||||
|
||||
return FutureBuilder<Sprite>(
|
||||
future: _magicCubeFuture,
|
||||
builder: (context, cubeSnapshot) {
|
||||
if (cubeSnapshot.connectionState == ConnectionState.done) {
|
||||
if (cubeSnapshot.hasError) {
|
||||
return Center(
|
||||
child: Text('Error: ${cubeSnapshot.error}'));
|
||||
} else if (!cubeSnapshot.hasData ||
|
||||
cubeSnapshot.data == null) {
|
||||
return const Center(
|
||||
child: Text('No magic cube sprite found'));
|
||||
} else {
|
||||
final magicCube = cubeSnapshot.data!;
|
||||
|
||||
board ??= Board(
|
||||
sprites: crystals,
|
||||
magicCubeSprite: magicCube,
|
||||
swapNotifier: context.read<SwapNotifier>(),
|
||||
);
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
const SizedBox(height: 50),
|
||||
const ScoreDisplay(),
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: GameWidget(game: board!),
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: _restartGame,
|
||||
child: const Text(
|
||||
'Restart',
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
board?.showHint();
|
||||
},
|
||||
child: const Text(
|
||||
'Hint',
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 50),
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
top: 16,
|
||||
left: 16,
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.settings,
|
||||
color: Colors.white),
|
||||
onPressed: _showSettingsDialog,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ScoreDisplay extends StatelessWidget {
|
||||
const ScoreDisplay({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Consumer<SwapNotifier>(
|
||||
builder: (context, notifier, child) {
|
||||
return Card(
|
||||
color: Colors.blueGrey[900],
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'Score: ${notifier.score}',
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
Consumer<SwapNotifier>(
|
||||
builder: (context, notifier, child) {
|
||||
return Card(
|
||||
color: Colors.blueGrey[900],
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'Moves: ${notifier.moveCount}',
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,15 +1,13 @@
|
||||
import 'package:flame/components.dart';
|
||||
// import 'package:flame/components.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
|
||||
class SpriteLoader {
|
||||
static Future<List<Sprite>> loadCrystalSprites() async {
|
||||
List<Sprite> sprites = [];
|
||||
for (int i = 1; i <= 7; i++) {
|
||||
sprites.add(await Sprite.load('crystal$i.png'));
|
||||
}
|
||||
return sprites;
|
||||
}
|
||||
|
||||
static Future<Sprite> loadMagicCubeSprite() async {
|
||||
return Sprite.load('magic_cube.png');
|
||||
}
|
||||
Future<void> loadImages() async {
|
||||
await Flame.images.load('crystal1.png');
|
||||
await Flame.images.load('crystal2.png');
|
||||
await Flame.images.load('crystal3.png');
|
||||
await Flame.images.load('crystal4.png');
|
||||
await Flame.images.load('crystal5.png');
|
||||
await Flame.images.load('crystal6.png');
|
||||
await Flame.images.load('crystal7.png');
|
||||
await Flame.images.load('magic_cube.png');
|
||||
}
|
||||
|
@ -1,54 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'tile.dart';
|
||||
|
||||
class SwapNotifier extends ChangeNotifier {
|
||||
Tile? selectedTile;
|
||||
int _score = 0;
|
||||
int _moveCount = 0;
|
||||
|
||||
int get score => _score;
|
||||
int get moveCount => _moveCount;
|
||||
|
||||
void resetScore() {
|
||||
_score = 0;
|
||||
_moveCount = 0;
|
||||
selectedTile = null;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void incrementScore(int value) {
|
||||
_score += value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void incrementMoveCount() {
|
||||
_moveCount += 1;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
void selectTile(Tile tile) {
|
||||
if (selectedTile == null) {
|
||||
selectedTile = tile;
|
||||
tile.select();
|
||||
} else {
|
||||
if (_isNeighbor(selectedTile!, tile) || selectedTile!.isMagicCube) {
|
||||
notifyListeners();
|
||||
} else {
|
||||
selectedTile?.deselect();
|
||||
selectedTile = tile;
|
||||
tile.select();
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool _isNeighbor(Tile tile1, Tile tile2) {
|
||||
return (tile1.row == tile2.row && (tile1.col - tile2.col).abs() == 1) ||
|
||||
(tile1.col == tile2.col && (tile1.row - tile2.row).abs() == 1);
|
||||
}
|
||||
|
||||
void clearSelectedTile() {
|
||||
selectedTile = null;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
@ -1,6 +1,9 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flame/components.dart';
|
||||
import 'package:flame/effects.dart';
|
||||
import 'package:flame/events.dart';
|
||||
import 'package:flame/flame.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'board.dart';
|
||||
|
||||
@ -26,8 +29,17 @@ class Tile extends SpriteComponent with TapCallbacks, DragCallbacks {
|
||||
required this.col,
|
||||
// required this.onTileTap,
|
||||
required this.onSwipe,
|
||||
}) : super(sprite: sprite, size: size, position: position);
|
||||
}) : super(
|
||||
sprite: sprite,
|
||||
size: size,
|
||||
position: position,
|
||||
) {
|
||||
// final randomSpriteIndex = _random.nextInt(crystals.length);
|
||||
// tile = isMagicCube ? crystals[randomSpriteIndex] : magicCube();
|
||||
}
|
||||
|
||||
// static final Random _random = Random();
|
||||
late Sprite tile;
|
||||
// @override
|
||||
// bool onTapDown(TapDownEvent event) {
|
||||
// if (isAnimating || (parent is Board && (parent as Board).animating)) {
|
||||
@ -37,6 +49,18 @@ class Tile extends SpriteComponent with TapCallbacks, DragCallbacks {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
static List<Sprite> crystals = [
|
||||
crystal1(),
|
||||
crystal2(),
|
||||
crystal3(),
|
||||
crystal4(),
|
||||
crystal5(),
|
||||
crystal6(),
|
||||
crystal7(),
|
||||
];
|
||||
|
||||
static Sprite magicCubeSprite = magicCube();
|
||||
|
||||
@override
|
||||
bool onDragStart(DragStartEvent event) {
|
||||
if (isAnimating || (parent as Board).animating) {
|
||||
@ -123,3 +147,35 @@ class Tile extends SpriteComponent with TapCallbacks, DragCallbacks {
|
||||
// ));
|
||||
// }
|
||||
}
|
||||
|
||||
Sprite crystal1() {
|
||||
return Sprite(Flame.images.fromCache('crystal1.png'));
|
||||
}
|
||||
|
||||
Sprite crystal2() {
|
||||
return Sprite(Flame.images.fromCache('crystal2.png'));
|
||||
}
|
||||
|
||||
Sprite crystal3() {
|
||||
return Sprite(Flame.images.fromCache('crystal3.png'));
|
||||
}
|
||||
|
||||
Sprite crystal4() {
|
||||
return Sprite(Flame.images.fromCache('crystal4.png'));
|
||||
}
|
||||
|
||||
Sprite crystal5() {
|
||||
return Sprite(Flame.images.fromCache('crystal5.png'));
|
||||
}
|
||||
|
||||
Sprite crystal6() {
|
||||
return Sprite(Flame.images.fromCache('crystal6.png'));
|
||||
}
|
||||
|
||||
Sprite crystal7() {
|
||||
return Sprite(Flame.images.fromCache('crystal7.png'));
|
||||
}
|
||||
|
||||
Sprite magicCube() {
|
||||
return Sprite(Flame.images.fromCache('magic_cube.png'));
|
||||
}
|
||||
|
@ -1,20 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:match_magic/screens/main_menu.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'game/match_magic_game.dart';
|
||||
import 'game/swap_notifier.dart';
|
||||
import 'package:match_magic/db/main_db.dart';
|
||||
import 'package:match_magic/screens/main_menu_screen.dart';
|
||||
|
||||
void main() {
|
||||
runApp(
|
||||
MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => SwapNotifier()),
|
||||
],
|
||||
child: const MyApp(),
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await MainDB.instance.initMainDB();
|
||||
SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
DeviceOrientation.portraitDown,
|
||||
]).then(
|
||||
(value) => runApp(
|
||||
// MultiProvider(
|
||||
// providers: [
|
||||
// ChangeNotifierProvider(create: (_) => SwapNotifier()),
|
||||
// ],
|
||||
// child: const
|
||||
MyApp(),
|
||||
),
|
||||
// )
|
||||
);
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
@ -22,8 +27,8 @@ class MyApp extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const MaterialApp(
|
||||
home: MainMenu(),
|
||||
return MaterialApp(
|
||||
home: MainMenuScreen(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
16
lib/models/app_state_manager.dart
Normal file
@ -0,0 +1,16 @@
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class AppStateManager {
|
||||
static const String _modeKey = 'mode';
|
||||
|
||||
// Installing the bubbles or balloons mod
|
||||
static Future<bool> getMode() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getBool(_modeKey) ?? true;
|
||||
}
|
||||
|
||||
static Future<void> setMode(bool mode) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool(_modeKey, mode);
|
||||
}
|
||||
}
|
13
lib/models/isar/high_score.dart
Normal file
@ -0,0 +1,13 @@
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
part 'high_score.g.dart';
|
||||
|
||||
@Collection()
|
||||
class HighScore {
|
||||
Id id = Isar.autoIncrement;
|
||||
|
||||
@enumerated
|
||||
late int highScoreValue;
|
||||
|
||||
HighScore({required this.highScoreValue});
|
||||
}
|
355
lib/models/isar/high_score.g.dart
Normal file
@ -0,0 +1,355 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'high_score.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// IsarCollectionGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetHighScoreCollection on Isar {
|
||||
IsarCollection<HighScore> get highScores => this.collection();
|
||||
}
|
||||
|
||||
const HighScoreSchema = CollectionSchema(
|
||||
name: r'HighScore',
|
||||
id: 6847972554114346288,
|
||||
properties: {
|
||||
r'highScoreValue': PropertySchema(
|
||||
id: 0,
|
||||
name: r'highScoreValue',
|
||||
type: IsarType.long,
|
||||
)
|
||||
},
|
||||
estimateSize: _highScoreEstimateSize,
|
||||
serialize: _highScoreSerialize,
|
||||
deserialize: _highScoreDeserialize,
|
||||
deserializeProp: _highScoreDeserializeProp,
|
||||
idName: r'id',
|
||||
indexes: {},
|
||||
links: {},
|
||||
embeddedSchemas: {},
|
||||
getId: _highScoreGetId,
|
||||
getLinks: _highScoreGetLinks,
|
||||
attach: _highScoreAttach,
|
||||
version: '3.1.0+1',
|
||||
);
|
||||
|
||||
int _highScoreEstimateSize(
|
||||
HighScore object,
|
||||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
var bytesCount = offsets.last;
|
||||
return bytesCount;
|
||||
}
|
||||
|
||||
void _highScoreSerialize(
|
||||
HighScore object,
|
||||
IsarWriter writer,
|
||||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
writer.writeLong(offsets[0], object.highScoreValue);
|
||||
}
|
||||
|
||||
HighScore _highScoreDeserialize(
|
||||
Id id,
|
||||
IsarReader reader,
|
||||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
final object = HighScore(
|
||||
highScoreValue: reader.readLong(offsets[0]),
|
||||
);
|
||||
object.id = id;
|
||||
return object;
|
||||
}
|
||||
|
||||
P _highScoreDeserializeProp<P>(
|
||||
IsarReader reader,
|
||||
int propertyId,
|
||||
int offset,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
switch (propertyId) {
|
||||
case 0:
|
||||
return (reader.readLong(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
}
|
||||
}
|
||||
|
||||
Id _highScoreGetId(HighScore object) {
|
||||
return object.id;
|
||||
}
|
||||
|
||||
List<IsarLinkBase<dynamic>> _highScoreGetLinks(HighScore object) {
|
||||
return [];
|
||||
}
|
||||
|
||||
void _highScoreAttach(IsarCollection<dynamic> col, Id id, HighScore object) {
|
||||
object.id = id;
|
||||
}
|
||||
|
||||
extension HighScoreQueryWhereSort
|
||||
on QueryBuilder<HighScore, HighScore, QWhere> {
|
||||
QueryBuilder<HighScore, HighScore, QAfterWhere> anyId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(const IdWhereClause.any());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension HighScoreQueryWhere
|
||||
on QueryBuilder<HighScore, HighScore, QWhereClause> {
|
||||
QueryBuilder<HighScore, HighScore, QAfterWhereClause> idEqualTo(Id id) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(IdWhereClause.between(
|
||||
lower: id,
|
||||
upper: id,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterWhereClause> idNotEqualTo(Id id) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
if (query.whereSort == Sort.asc) {
|
||||
return query
|
||||
.addWhereClause(
|
||||
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||
)
|
||||
.addWhereClause(
|
||||
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||
);
|
||||
} else {
|
||||
return query
|
||||
.addWhereClause(
|
||||
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||
)
|
||||
.addWhereClause(
|
||||
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterWhereClause> idGreaterThan(Id id,
|
||||
{bool include = false}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(
|
||||
IdWhereClause.greaterThan(lower: id, includeLower: include),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterWhereClause> idLessThan(Id id,
|
||||
{bool include = false}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(
|
||||
IdWhereClause.lessThan(upper: id, includeUpper: include),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterWhereClause> idBetween(
|
||||
Id lowerId,
|
||||
Id upperId, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(IdWhereClause.between(
|
||||
lower: lowerId,
|
||||
includeLower: includeLower,
|
||||
upper: upperId,
|
||||
includeUpper: includeUpper,
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension HighScoreQueryFilter
|
||||
on QueryBuilder<HighScore, HighScore, QFilterCondition> {
|
||||
QueryBuilder<HighScore, HighScore, QAfterFilterCondition>
|
||||
highScoreValueEqualTo(int value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'highScoreValue',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterFilterCondition>
|
||||
highScoreValueGreaterThan(
|
||||
int value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||
include: include,
|
||||
property: r'highScoreValue',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterFilterCondition>
|
||||
highScoreValueLessThan(
|
||||
int value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.lessThan(
|
||||
include: include,
|
||||
property: r'highScoreValue',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterFilterCondition>
|
||||
highScoreValueBetween(
|
||||
int lower,
|
||||
int upper, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.between(
|
||||
property: r'highScoreValue',
|
||||
lower: lower,
|
||||
includeLower: includeLower,
|
||||
upper: upper,
|
||||
includeUpper: includeUpper,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterFilterCondition> idEqualTo(
|
||||
Id value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'id',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterFilterCondition> idGreaterThan(
|
||||
Id value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||
include: include,
|
||||
property: r'id',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterFilterCondition> idLessThan(
|
||||
Id value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.lessThan(
|
||||
include: include,
|
||||
property: r'id',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterFilterCondition> idBetween(
|
||||
Id lower,
|
||||
Id upper, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.between(
|
||||
property: r'id',
|
||||
lower: lower,
|
||||
includeLower: includeLower,
|
||||
upper: upper,
|
||||
includeUpper: includeUpper,
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension HighScoreQueryObject
|
||||
on QueryBuilder<HighScore, HighScore, QFilterCondition> {}
|
||||
|
||||
extension HighScoreQueryLinks
|
||||
on QueryBuilder<HighScore, HighScore, QFilterCondition> {}
|
||||
|
||||
extension HighScoreQuerySortBy on QueryBuilder<HighScore, HighScore, QSortBy> {
|
||||
QueryBuilder<HighScore, HighScore, QAfterSortBy> sortByHighScoreValue() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'highScoreValue', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterSortBy> sortByHighScoreValueDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'highScoreValue', Sort.desc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension HighScoreQuerySortThenBy
|
||||
on QueryBuilder<HighScore, HighScore, QSortThenBy> {
|
||||
QueryBuilder<HighScore, HighScore, QAfterSortBy> thenByHighScoreValue() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'highScoreValue', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterSortBy> thenByHighScoreValueDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'highScoreValue', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterSortBy> thenById() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'id', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, HighScore, QAfterSortBy> thenByIdDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'id', Sort.desc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension HighScoreQueryWhereDistinct
|
||||
on QueryBuilder<HighScore, HighScore, QDistinct> {
|
||||
QueryBuilder<HighScore, HighScore, QDistinct> distinctByHighScoreValue() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'highScoreValue');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension HighScoreQueryProperty
|
||||
on QueryBuilder<HighScore, HighScore, QQueryProperty> {
|
||||
QueryBuilder<HighScore, int, QQueryOperations> idProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'id');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<HighScore, int, QQueryOperations> highScoreValueProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'highScoreValue');
|
||||
});
|
||||
}
|
||||
}
|
14
lib/models/isar/settings.dart
Normal file
@ -0,0 +1,14 @@
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
part 'settings.g.dart';
|
||||
|
||||
@Collection()
|
||||
class Settings {
|
||||
Settings({
|
||||
required this.isSoundEnabled,
|
||||
required this.isMusicEnabled,
|
||||
});
|
||||
Id id = 1;
|
||||
late bool isSoundEnabled;
|
||||
late bool isMusicEnabled;
|
||||
}
|
361
lib/models/isar/settings.g.dart
Normal file
@ -0,0 +1,361 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'settings.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// IsarCollectionGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, unnecessary_null_checks, join_return_with_assignment, prefer_final_locals, avoid_js_rounded_ints, avoid_positional_boolean_parameters, always_specify_types
|
||||
|
||||
extension GetSettingsCollection on Isar {
|
||||
IsarCollection<Settings> get settings => this.collection();
|
||||
}
|
||||
|
||||
const SettingsSchema = CollectionSchema(
|
||||
name: r'Settings',
|
||||
id: -8656046621518759136,
|
||||
properties: {
|
||||
r'isMusicEnabled': PropertySchema(
|
||||
id: 0,
|
||||
name: r'isMusicEnabled',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'isSoundEnabled': PropertySchema(
|
||||
id: 1,
|
||||
name: r'isSoundEnabled',
|
||||
type: IsarType.bool,
|
||||
)
|
||||
},
|
||||
estimateSize: _settingsEstimateSize,
|
||||
serialize: _settingsSerialize,
|
||||
deserialize: _settingsDeserialize,
|
||||
deserializeProp: _settingsDeserializeProp,
|
||||
idName: r'id',
|
||||
indexes: {},
|
||||
links: {},
|
||||
embeddedSchemas: {},
|
||||
getId: _settingsGetId,
|
||||
getLinks: _settingsGetLinks,
|
||||
attach: _settingsAttach,
|
||||
version: '3.1.0+1',
|
||||
);
|
||||
|
||||
int _settingsEstimateSize(
|
||||
Settings object,
|
||||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
var bytesCount = offsets.last;
|
||||
return bytesCount;
|
||||
}
|
||||
|
||||
void _settingsSerialize(
|
||||
Settings object,
|
||||
IsarWriter writer,
|
||||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
writer.writeBool(offsets[0], object.isMusicEnabled);
|
||||
writer.writeBool(offsets[1], object.isSoundEnabled);
|
||||
}
|
||||
|
||||
Settings _settingsDeserialize(
|
||||
Id id,
|
||||
IsarReader reader,
|
||||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
final object = Settings(
|
||||
isMusicEnabled: reader.readBool(offsets[0]),
|
||||
isSoundEnabled: reader.readBool(offsets[1]),
|
||||
);
|
||||
object.id = id;
|
||||
return object;
|
||||
}
|
||||
|
||||
P _settingsDeserializeProp<P>(
|
||||
IsarReader reader,
|
||||
int propertyId,
|
||||
int offset,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
switch (propertyId) {
|
||||
case 0:
|
||||
return (reader.readBool(offset)) as P;
|
||||
case 1:
|
||||
return (reader.readBool(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
}
|
||||
}
|
||||
|
||||
Id _settingsGetId(Settings object) {
|
||||
return object.id;
|
||||
}
|
||||
|
||||
List<IsarLinkBase<dynamic>> _settingsGetLinks(Settings object) {
|
||||
return [];
|
||||
}
|
||||
|
||||
void _settingsAttach(IsarCollection<dynamic> col, Id id, Settings object) {
|
||||
object.id = id;
|
||||
}
|
||||
|
||||
extension SettingsQueryWhereSort on QueryBuilder<Settings, Settings, QWhere> {
|
||||
QueryBuilder<Settings, Settings, QAfterWhere> anyId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(const IdWhereClause.any());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension SettingsQueryWhere on QueryBuilder<Settings, Settings, QWhereClause> {
|
||||
QueryBuilder<Settings, Settings, QAfterWhereClause> idEqualTo(Id id) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(IdWhereClause.between(
|
||||
lower: id,
|
||||
upper: id,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterWhereClause> idNotEqualTo(Id id) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
if (query.whereSort == Sort.asc) {
|
||||
return query
|
||||
.addWhereClause(
|
||||
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||
)
|
||||
.addWhereClause(
|
||||
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||
);
|
||||
} else {
|
||||
return query
|
||||
.addWhereClause(
|
||||
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||
)
|
||||
.addWhereClause(
|
||||
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterWhereClause> idGreaterThan(Id id,
|
||||
{bool include = false}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(
|
||||
IdWhereClause.greaterThan(lower: id, includeLower: include),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterWhereClause> idLessThan(Id id,
|
||||
{bool include = false}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(
|
||||
IdWhereClause.lessThan(upper: id, includeUpper: include),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterWhereClause> idBetween(
|
||||
Id lowerId,
|
||||
Id upperId, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(IdWhereClause.between(
|
||||
lower: lowerId,
|
||||
includeLower: includeLower,
|
||||
upper: upperId,
|
||||
includeUpper: includeUpper,
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension SettingsQueryFilter
|
||||
on QueryBuilder<Settings, Settings, QFilterCondition> {
|
||||
QueryBuilder<Settings, Settings, QAfterFilterCondition> idEqualTo(Id value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'id',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterFilterCondition> idGreaterThan(
|
||||
Id value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||
include: include,
|
||||
property: r'id',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterFilterCondition> idLessThan(
|
||||
Id value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.lessThan(
|
||||
include: include,
|
||||
property: r'id',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterFilterCondition> idBetween(
|
||||
Id lower,
|
||||
Id upper, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.between(
|
||||
property: r'id',
|
||||
lower: lower,
|
||||
includeLower: includeLower,
|
||||
upper: upper,
|
||||
includeUpper: includeUpper,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterFilterCondition> isMusicEnabledEqualTo(
|
||||
bool value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'isMusicEnabled',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterFilterCondition> isSoundEnabledEqualTo(
|
||||
bool value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'isSoundEnabled',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension SettingsQueryObject
|
||||
on QueryBuilder<Settings, Settings, QFilterCondition> {}
|
||||
|
||||
extension SettingsQueryLinks
|
||||
on QueryBuilder<Settings, Settings, QFilterCondition> {}
|
||||
|
||||
extension SettingsQuerySortBy on QueryBuilder<Settings, Settings, QSortBy> {
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> sortByIsMusicEnabled() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isMusicEnabled', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> sortByIsMusicEnabledDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isMusicEnabled', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> sortByIsSoundEnabled() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isSoundEnabled', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> sortByIsSoundEnabledDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isSoundEnabled', Sort.desc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension SettingsQuerySortThenBy
|
||||
on QueryBuilder<Settings, Settings, QSortThenBy> {
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> thenById() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'id', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> thenByIdDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'id', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> thenByIsMusicEnabled() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isMusicEnabled', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> thenByIsMusicEnabledDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isMusicEnabled', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> thenByIsSoundEnabled() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isSoundEnabled', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> thenByIsSoundEnabledDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'isSoundEnabled', Sort.desc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension SettingsQueryWhereDistinct
|
||||
on QueryBuilder<Settings, Settings, QDistinct> {
|
||||
QueryBuilder<Settings, Settings, QDistinct> distinctByIsMusicEnabled() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'isMusicEnabled');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QDistinct> distinctByIsSoundEnabled() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'isSoundEnabled');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension SettingsQueryProperty
|
||||
on QueryBuilder<Settings, Settings, QQueryProperty> {
|
||||
QueryBuilder<Settings, int, QQueryOperations> idProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'id');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, bool, QQueryOperations> isMusicEnabledProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'isMusicEnabled');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, bool, QQueryOperations> isSoundEnabledProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'isSoundEnabled');
|
||||
});
|
||||
}
|
||||
}
|
153
lib/screens/game_over_screen.dart
Normal file
@ -0,0 +1,153 @@
|
||||
import 'package:flame_audio/flame_audio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:match_magic/db/main_db.dart';
|
||||
import 'package:match_magic/game/board.dart';
|
||||
import 'package:match_magic/screens/main_menu_screen.dart';
|
||||
import 'package:match_magic/widgets/gradient_button.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/hint_button.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/pause_button.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/restart_button.dart';
|
||||
|
||||
class GameOverMenu extends StatelessWidget {
|
||||
static const String id = 'GameOverMenu';
|
||||
final Board gameRef;
|
||||
|
||||
GameOverMenu({
|
||||
super.key,
|
||||
required this.gameRef,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Color(0xFFEBEBEB).withOpacity(0.6),
|
||||
Color(0xFFBFBEC0).withOpacity(0.6),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 70, horizontal: 16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Game over title.
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 50.0),
|
||||
child: Text(
|
||||
'Game Over',
|
||||
style: TextStyle(
|
||||
fontSize: 32.0,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Colors.black,
|
||||
shadows: [
|
||||
Shadow(
|
||||
blurRadius: 20.0,
|
||||
color: Colors.white,
|
||||
offset: Offset(0, 0),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Stack(
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.symmetric(horizontal: 64),
|
||||
child: Image.asset('assets/images/game_over_score.png')),
|
||||
Positioned.fill(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(height: 20),
|
||||
Text(
|
||||
'Score: ${Board.score}',
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
FutureBuilder<int?>(
|
||||
future: MainDB.instance.getHighScoreValue(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.waiting) {
|
||||
return CircularProgressIndicator(); //
|
||||
} else if (snapshot.hasError) {
|
||||
return Text('Error: ${snapshot.error}');
|
||||
} else if (snapshot.hasData) {
|
||||
return Text(
|
||||
'High score: ${snapshot.data}',
|
||||
style: TextStyle(
|
||||
fontSize: 16, color: Colors.white),
|
||||
);
|
||||
} else {
|
||||
return Text('No data');
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(child: SizedBox()),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: GradientButton(
|
||||
onPressed: () async {
|
||||
// AdManager.showInterstitialAd(context, () {});
|
||||
// Pause
|
||||
gameRef.overlays.remove(GameOverMenu.id);
|
||||
gameRef.overlays.add(PauseButton.id);
|
||||
gameRef.overlays.add(RestartButton.id);
|
||||
gameRef.overlays.add(HintButton.id);
|
||||
|
||||
gameRef.newGame();
|
||||
gameRef.resumeEngine();
|
||||
},
|
||||
buttonText: 'Play again'),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
// Exit button.
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: GradientButton(
|
||||
onPressed: () {
|
||||
FlameAudio.bgm.stop();
|
||||
gameRef.overlays.remove(GameOverMenu.id);
|
||||
gameRef.removed;
|
||||
gameRef.resumeEngine();
|
||||
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => MainMenuScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
buttonText: 'Exit'),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
88
lib/screens/game_screen.dart
Normal file
@ -0,0 +1,88 @@
|
||||
import 'package:flame/game.dart';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:match_magic/game/board.dart';
|
||||
|
||||
import 'package:match_magic/screens/game_over_screen.dart';
|
||||
import 'package:match_magic/screens/pause_screen.dart';
|
||||
import 'package:match_magic/utilities/audio_manager.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/hint_button.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/pause_button.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/restart_button.dart';
|
||||
|
||||
class GameScreen extends StatefulWidget {
|
||||
GameScreen(this.gameMode);
|
||||
|
||||
final bool gameMode;
|
||||
|
||||
@override
|
||||
_GameScreenState createState() => _GameScreenState();
|
||||
}
|
||||
|
||||
class _GameScreenState extends State<GameScreen> {
|
||||
Board? board;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
AudioManager.load();
|
||||
// AdManager.loadBannerAd();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
GameWidget(
|
||||
initialActiveOverlays: [
|
||||
PauseButton.id,
|
||||
HintButton.id,
|
||||
RestartButton.id
|
||||
],
|
||||
overlayBuilderMap: {
|
||||
PauseButton.id: (BuildContext context, Board gameRef) =>
|
||||
PauseButton(
|
||||
gameRef: gameRef,
|
||||
),
|
||||
HintButton.id: (BuildContext context, Board gameRef) =>
|
||||
HintButton(
|
||||
gameRef: gameRef,
|
||||
),
|
||||
RestartButton.id: (BuildContext context, Board gameRef) =>
|
||||
RestartButton(
|
||||
gameRef: gameRef,
|
||||
),
|
||||
PauseMenu.id: (BuildContext context, Board gameRef) =>
|
||||
PauseMenu(
|
||||
gameRef: gameRef,
|
||||
),
|
||||
GameOverMenu.id: (BuildContext context, Board gameRef) =>
|
||||
GameOverMenu(
|
||||
gameRef: gameRef,
|
||||
)
|
||||
},
|
||||
game: Board(
|
||||
context,
|
||||
gameMode: widget.gameMode,
|
||||
)),
|
||||
// Display Ads
|
||||
// if (AdManager.bannerAd != null)
|
||||
// Align(
|
||||
// alignment: Alignment.bottomCenter,
|
||||
// child: Container(
|
||||
// width: AdManager.bannerAd!.size.width.toDouble(),
|
||||
// height: AdManager.bannerAd!.size.height.toDouble(),
|
||||
// child: AdWidget(ad: AdManager.bannerAd!),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:match_magic/game/match_magic_game.dart';
|
||||
|
||||
class MainMenu extends StatelessWidget {
|
||||
const MainMenu({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
icon: const Icon(Icons.settings, color: Colors.white),
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('Settings'),
|
||||
content:
|
||||
const Text('The settings have not yet been implemented.'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text('Ok'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
backgroundColor: Colors.black,
|
||||
),
|
||||
backgroundColor: Colors.black,
|
||||
body: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 100,
|
||||
),
|
||||
const Text(
|
||||
'Match Magic',
|
||||
style: TextStyle(
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 300,
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const MatchMagicGameScreen()),
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 60.0, vertical: 16.0),
|
||||
),
|
||||
child: const Text('Play', style: TextStyle(fontSize: 16)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
301
lib/screens/main_menu_screen.dart
Normal file
@ -0,0 +1,301 @@
|
||||
// import 'package:flutter/material.dart';
|
||||
// import 'package:match_magic/game/match_magic_game.dart';
|
||||
|
||||
// class MainMenu extends StatelessWidget {
|
||||
// const MainMenu({Key? key}) : super(key: key);
|
||||
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// return Scaffold(
|
||||
// appBar: AppBar(
|
||||
// leading: IconButton(
|
||||
// icon: const Icon(Icons.settings, color: Colors.white),
|
||||
// onPressed: () {
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (context) => AlertDialog(
|
||||
// title: const Text('Settings'),
|
||||
// content:
|
||||
// const Text('The settings have not yet been implemented.'),
|
||||
// actions: [
|
||||
// TextButton(
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).pop();
|
||||
// },
|
||||
// child: const Text('Ok'),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// backgroundColor: Colors.black,
|
||||
// ),
|
||||
// backgroundColor: Colors.black,
|
||||
// body: Center(
|
||||
// child: Column(
|
||||
// children: [
|
||||
// const SizedBox(
|
||||
// height: 100,
|
||||
// ),
|
||||
// const Text(
|
||||
// 'Match Magic',
|
||||
// style: TextStyle(
|
||||
// fontSize: 28,
|
||||
// fontWeight: FontWeight.bold,
|
||||
// color: Colors.white),
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// height: 300,
|
||||
// ),
|
||||
// ElevatedButton(
|
||||
// onPressed: () {
|
||||
// Navigator.push(
|
||||
// context,
|
||||
// MaterialPageRoute(
|
||||
// builder: (context) => const MatchMagicGameScreen()),
|
||||
// );
|
||||
// },
|
||||
// style: ElevatedButton.styleFrom(
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// horizontal: 60.0, vertical: 16.0),
|
||||
// ),
|
||||
// child: const Text('Play', style: TextStyle(fontSize: 16)),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:match_magic/models/app_state_manager.dart';
|
||||
import 'package:match_magic/screens/game_screen.dart';
|
||||
import 'package:match_magic/screens/options_screen.dart';
|
||||
import 'package:match_magic/styles/styles.dart';
|
||||
import 'package:match_magic/utilities/assets.dart';
|
||||
|
||||
class MainMenuScreen extends StatefulWidget {
|
||||
@override
|
||||
State<MainMenuScreen> createState() => _MainMenuScreenState();
|
||||
}
|
||||
|
||||
class _MainMenuScreenState extends State<MainMenuScreen> {
|
||||
bool islevelProgression = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
|
||||
// _loadBackground();
|
||||
// _checkPremiumStatus();
|
||||
_loadMode();
|
||||
}
|
||||
|
||||
Future<void> _loadMode() async {
|
||||
final mode = await AppStateManager.getMode();
|
||||
setState(() {
|
||||
islevelProgression = mode;
|
||||
});
|
||||
}
|
||||
|
||||
// Future<void> _loadBackground() async {
|
||||
// final background = await MainDB.instance.getBackground();
|
||||
// setState(() {
|
||||
// backgroundImage = background;
|
||||
// });
|
||||
// }
|
||||
|
||||
// void _updateBackground(Background newBackground) {
|
||||
// setState(() {
|
||||
// backgroundImage = newBackground;
|
||||
// });
|
||||
// }
|
||||
|
||||
// // Premium check
|
||||
// Future<void> _checkPremiumStatus() async {
|
||||
// bool isPremium = await AppStateManager.isPremium();
|
||||
// setState(() {
|
||||
// _isPremium = isPremium;
|
||||
// });
|
||||
// }
|
||||
|
||||
Future<void> _refreshMainScreen() async {
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
// Container(
|
||||
// decoration: BoxDecoration(
|
||||
// image: DecorationImage(
|
||||
// image: BackgroundImageProvider.getBackgroundImage(
|
||||
// backgroundImage ?? Background.sky),
|
||||
// fit: BoxFit.cover,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 16, top: 32, right: 16, bottom: 70),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
bool? refreshScreen = await showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) => OptionsScreen(
|
||||
// onUpdateBackground: (background) {
|
||||
// setState(() {
|
||||
// backgroundImage = background;
|
||||
// });
|
||||
// },
|
||||
),
|
||||
);
|
||||
if (refreshScreen != null && refreshScreen == true) {
|
||||
await _refreshMainScreen();
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
'Options',
|
||||
style: AppStyles.subtitleTextStyle
|
||||
.copyWith(color: AppStyles.accentColorTopBar),
|
||||
)),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Container(),
|
||||
),
|
||||
Container(
|
||||
height: 150,
|
||||
child: Text(
|
||||
'Match Magic',
|
||||
style: TextStyle(
|
||||
color: AppStyles.accentColorTopBar, fontSize: 30),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 50),
|
||||
Container(
|
||||
height: 200,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// Levels mode
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
islevelProgression = true;
|
||||
});
|
||||
await AppStateManager.setMode(true);
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue,
|
||||
borderRadius:
|
||||
const BorderRadius.all(Radius.circular(20)),
|
||||
border: islevelProgression
|
||||
? Border.all(
|
||||
color: AppStyles.accentColor,
|
||||
width: 2,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
child: const Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Text(
|
||||
'Levels',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
// Limited time mode
|
||||
Expanded(
|
||||
child: GestureDetector(
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
islevelProgression = false;
|
||||
});
|
||||
await AppStateManager.setMode(false);
|
||||
},
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.blue,
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(20)),
|
||||
border: islevelProgression
|
||||
? null
|
||||
: Border.all(
|
||||
color: AppStyles.accentColor,
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
child: const Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Text(
|
||||
'Limited time',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 50),
|
||||
|
||||
// Play game
|
||||
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pushAndRemoveUntil(
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
GameScreen(islevelProgression)),
|
||||
(route) => false);
|
||||
},
|
||||
child: Text('Play game'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
266
lib/screens/options_screen.dart
Normal file
@ -0,0 +1,266 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:match_magic/db/main_db.dart';
|
||||
import 'package:match_magic/game/board.dart';
|
||||
import 'package:match_magic/styles/styles.dart';
|
||||
import 'package:match_magic/widgets/icon_widgets/arrow_left_icon.dart';
|
||||
import 'package:match_magic/widgets/icon_widgets/music_icon.dart';
|
||||
import 'package:match_magic/widgets/icon_widgets/star_icon.dart';
|
||||
import 'package:match_magic/widgets/icon_widgets/volume_icon.dart';
|
||||
import 'package:match_magic/widgets/toggle_switch.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
|
||||
class OptionsScreen extends StatefulWidget {
|
||||
// final Function(Background) onUpdateBackground;
|
||||
|
||||
OptionsScreen();
|
||||
@override
|
||||
State<OptionsScreen> createState() => _OptionsScreenState();
|
||||
}
|
||||
|
||||
class _OptionsScreenState extends State<OptionsScreen> {
|
||||
bool isSound = true;
|
||||
bool isMusic = true;
|
||||
// Background? backgroundImage;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
fetchSoundAndMusicState();
|
||||
// _loadBackground();
|
||||
getVersionNumber();
|
||||
// _checkPremiumStatus();
|
||||
}
|
||||
|
||||
Future<String> getVersionNumber() async {
|
||||
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
return packageInfo.version;
|
||||
}
|
||||
|
||||
// Future<void> _loadBackground() async {
|
||||
// final background = await MainDB.instance.getBackground();
|
||||
// setState(() {
|
||||
// backgroundImage = background;
|
||||
// });
|
||||
// }
|
||||
|
||||
// Future<void> _checkPremiumStatus() async {
|
||||
// bool isPremium = await AppStateManager.isPremium();
|
||||
// setState(() {
|
||||
// _isPremium = isPremium;
|
||||
// });
|
||||
// }
|
||||
|
||||
// Future<void> refreshOptionsScreen() async {
|
||||
// await _checkPremiumStatus();
|
||||
|
||||
// setState(() {});
|
||||
// }
|
||||
|
||||
Future<void> fetchSoundAndMusicState() async {
|
||||
bool soundEnabled = await MainDB.instance.getSoundEnabled();
|
||||
bool musicEnabled = await MainDB.instance.getMusicEnabled();
|
||||
|
||||
setState(() {
|
||||
isSound = soundEnabled;
|
||||
isMusic = musicEnabled;
|
||||
});
|
||||
}
|
||||
|
||||
// void updateBackground(Background newBackground) {
|
||||
// setState(() {
|
||||
// backgroundImage = newBackground;
|
||||
// });
|
||||
// widget.onUpdateBackground(newBackground);
|
||||
// }
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Stack(
|
||||
children: [
|
||||
// Container(
|
||||
// decoration: BoxDecoration(
|
||||
// image: DecorationImage(
|
||||
// image: BackgroundImageProvider.getBackgroundImage(
|
||||
// backgroundImage ?? Background.sky),
|
||||
// fit: BoxFit.cover,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
Container(
|
||||
padding:
|
||||
const EdgeInsets.only(top: 38, left: 16, right: 16, bottom: 16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context, true);
|
||||
},
|
||||
icon: ArrowLeftIcon()),
|
||||
Text(
|
||||
'Options',
|
||||
style: AppStyles.subtitleTextStyle
|
||||
.copyWith(color: AppStyles.accentColorTopBar),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 28,
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
// Sound settings
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: AppStyles.mainBackground,
|
||||
),
|
||||
padding: EdgeInsets.only(
|
||||
top: 12, bottom: 12, right: 12, left: 18),
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const Row(
|
||||
children: [
|
||||
Text(
|
||||
'Sound settings',
|
||||
style: AppStyles.subtitleTextStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
VolumeIcon(),
|
||||
const SizedBox(
|
||||
width: 6,
|
||||
),
|
||||
const Text(
|
||||
'Sound Effects',
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
const Expanded(child: SizedBox()),
|
||||
ToggleSwitch(
|
||||
value: isSound,
|
||||
onChanged: (value) async {
|
||||
setState(() {
|
||||
isSound = value;
|
||||
});
|
||||
|
||||
await MainDB.instance
|
||||
.saveSoundEnabled(value);
|
||||
})
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
MusicIcon(),
|
||||
const SizedBox(
|
||||
width: 6,
|
||||
),
|
||||
const Text(
|
||||
'Music',
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
const Expanded(child: SizedBox()),
|
||||
ToggleSwitch(
|
||||
value: isMusic,
|
||||
onChanged: (value) async {
|
||||
setState(() {
|
||||
isMusic = value;
|
||||
});
|
||||
await MainDB.instance
|
||||
.saveMusicEnabled(value);
|
||||
})
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
|
||||
// High score
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
color: AppStyles.mainBackground,
|
||||
),
|
||||
child: ExpansionTile(
|
||||
backgroundColor: AppStyles.mainBackground,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
title: Row(
|
||||
children: [
|
||||
StarIcon(),
|
||||
SizedBox(
|
||||
width: 6,
|
||||
),
|
||||
Text('High score'),
|
||||
],
|
||||
),
|
||||
children: [
|
||||
ListTile(
|
||||
title: FutureBuilder<int?>(
|
||||
future: MainDB.instance.getHighScoreValue(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Text(
|
||||
'${snapshot.data}',
|
||||
style: TextStyle(fontSize: 16),
|
||||
);
|
||||
} else {
|
||||
return Text('HighScore: 0');
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// About
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 16),
|
||||
child: Column(
|
||||
children: [
|
||||
Text('MatchMagic. Copyright 2024 Cypher Stack, LLC'),
|
||||
FutureBuilder<String>(
|
||||
future: getVersionNumber(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Text('Version: ${snapshot.data}');
|
||||
} else {
|
||||
return Text('Version: loading...');
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
206
lib/screens/pause_screen.dart
Normal file
@ -0,0 +1,206 @@
|
||||
import 'package:flame_audio/flame_audio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:match_magic/db/main_db.dart';
|
||||
import 'package:match_magic/game/board.dart';
|
||||
import 'package:match_magic/screens/main_menu_screen.dart';
|
||||
import 'package:match_magic/styles/styles.dart';
|
||||
|
||||
import 'package:match_magic/widgets/icon_widgets/volume_icon.dart';
|
||||
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/hint_button.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/pause_button.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/restart_button.dart';
|
||||
import 'package:match_magic/widgets/toggle_switch.dart';
|
||||
|
||||
class PauseMenu extends StatefulWidget {
|
||||
static const String id = 'PauseMenu';
|
||||
final Board gameRef;
|
||||
|
||||
const PauseMenu({super.key, required this.gameRef});
|
||||
|
||||
@override
|
||||
State<PauseMenu> createState() => _PauseMenuState();
|
||||
}
|
||||
|
||||
class _PauseMenuState extends State<PauseMenu> {
|
||||
bool isMusic = true;
|
||||
bool isSound = Board.isSoundPlaying;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 70, horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Color(0xFFEBEBEB).withOpacity(0.6),
|
||||
Color(0xFFBFBEC0).withOpacity(0.6),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 122,
|
||||
),
|
||||
// Pause menu title.
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 50.0),
|
||||
child: Text('Game Paused',
|
||||
style: AppStyles.titleTextStyle.copyWith(
|
||||
fontSize: 32, color: AppStyles.accentColorTopBar)),
|
||||
),
|
||||
// Sound settings
|
||||
Card(
|
||||
child: Container(
|
||||
height: 56,
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
children: [
|
||||
const VolumeIcon(),
|
||||
const SizedBox(
|
||||
width: 6,
|
||||
),
|
||||
const Text(
|
||||
'Sound settings',
|
||||
style: TextStyle(),
|
||||
),
|
||||
const Expanded(child: SizedBox()),
|
||||
ToggleSwitch(
|
||||
value: isSound,
|
||||
onChanged: (value) async {
|
||||
setState(() {
|
||||
isSound = value;
|
||||
Board.isSoundPlaying = !Board.isSoundPlaying;
|
||||
});
|
||||
await MainDB.instance.saveSoundEnabled(value);
|
||||
})
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
// Music
|
||||
// Card(
|
||||
// child: Container(
|
||||
// height: 56,
|
||||
// padding: const EdgeInsets.all(12),
|
||||
// child: Row(
|
||||
// children: [
|
||||
// const MusicIcon(),
|
||||
// const SizedBox(
|
||||
// width: 6,
|
||||
// ),
|
||||
// const Text(
|
||||
// 'Music',
|
||||
// style: TextStyle(),
|
||||
// ),
|
||||
// const Expanded(child: SizedBox()),
|
||||
// ToggleSwitch(
|
||||
// value: isMusic,
|
||||
// onChanged: (value) async {
|
||||
// setState(() {
|
||||
// isMusic = value;
|
||||
// if (Board.isMusicPlaying) {
|
||||
// FlameAudio.bgm.stop();
|
||||
// } else {
|
||||
// FlameAudio.bgm.play('.ogg');
|
||||
// }
|
||||
// Board.isMusicPlaying = !Board.isMusicPlaying;
|
||||
// });
|
||||
// await MainDB.instance.saveMusicEnabled(value);
|
||||
// })
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
const Expanded(child: SizedBox()),
|
||||
Row(
|
||||
children: [
|
||||
// Exit button
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AlertDialog(
|
||||
backgroundColor: AppStyles.mainBackground,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
title: const Text(
|
||||
'Quit',
|
||||
style: AppStyles.titleTextStyle,
|
||||
),
|
||||
content: const Text(
|
||||
'Are you sure you want to leave the game? You progress will be lost.',
|
||||
style: AppStyles.subtitleTextStyle,
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(
|
||||
'CANCEL',
|
||||
style: AppStyles.subtitleTextStyle.copyWith(
|
||||
fontSize: 14, color: AppStyles.accentColor),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
FlameAudio.bgm.stop();
|
||||
widget.gameRef.overlays.remove(PauseMenu.id);
|
||||
widget.gameRef.removed;
|
||||
widget.gameRef.resumeEngine();
|
||||
|
||||
Navigator.of(context).pushReplacement(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => MainMenuScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
'EXIT',
|
||||
style: AppStyles.subtitleTextStyle.copyWith(
|
||||
fontSize: 14, color: AppStyles.accentColor),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('Exit'),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
// Continue button
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () async {
|
||||
widget.gameRef.overlays.remove(PauseMenu.id);
|
||||
|
||||
widget.gameRef.overlays.add(PauseButton.id);
|
||||
widget.gameRef.overlays.add(RestartButton.id);
|
||||
widget.gameRef.overlays.add(HintButton.id);
|
||||
widget.gameRef.resumeEngine();
|
||||
print('${Board.isSoundPlaying}');
|
||||
},
|
||||
child: const Text('Continue'),
|
||||
)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
43
lib/styles/styles.dart
Normal file
@ -0,0 +1,43 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppStyles {
|
||||
// Fonts
|
||||
static const TextStyle titleTextStyle = TextStyle(
|
||||
fontFamily: 'MPLUSRounded1c-ExtraBold',
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: AppStyles.textColor,
|
||||
);
|
||||
|
||||
static const TextStyle subtitleTextStyle = TextStyle(
|
||||
fontFamily: 'MPLUSRounded1c-Medium',
|
||||
fontSize: 16,
|
||||
color: AppStyles.textColor,
|
||||
);
|
||||
|
||||
// AppColor
|
||||
static const Color primaryColor = Color(0xFF4124DF);
|
||||
static const Color accentColor = Color(0xFFFF4FA3);
|
||||
static const Color accentColorTopBar = Color(0xFF6014DC);
|
||||
static const Color textColor = Colors.black;
|
||||
static const Color linkColor = Color(0xFF3753E8);
|
||||
|
||||
static const Color mainBackground = Color(0xFFFFFFFF);
|
||||
|
||||
// Button
|
||||
static const buttonGradient = LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [Color(0xBFFF4FA3), Color(0xBF3E24E0)],
|
||||
);
|
||||
static const buttonPrimaryDefaultText = Color(0xFFFBF8FF);
|
||||
|
||||
// ToggleSwitch
|
||||
static const toggleSwitchBg = Color(0xFFFFC9ED);
|
||||
static const toggleSwitchTextInactive = Color(0xFFFFFFFF);
|
||||
static const toggleSwitchActiveBg = Color(0xFFFF4FA3);
|
||||
static const toggleSwitchTextActive = Color(0xFFFFDCF3);
|
||||
|
||||
// TextField
|
||||
static const textField = Color(0xFFFEF1FF);
|
||||
}
|
28
lib/utilities/assets.dart
Normal file
@ -0,0 +1,28 @@
|
||||
abstract class Assets {
|
||||
static const svg = _SVG();
|
||||
static const png = _PNG();
|
||||
}
|
||||
|
||||
class _SVG {
|
||||
const _SVG();
|
||||
String get arrowLeft => "assets/svg/arrow-left.svg";
|
||||
String get check => "assets/svg/check.svg";
|
||||
String get checkCircle => "assets/svg/check-circle.svg";
|
||||
String get chevronDown => "assets/svg/chevron-down.svg";
|
||||
String get chevronRight => "assets/svg/chevron-right.svg";
|
||||
String get clipboard => "assets/svg/clipboard.svg";
|
||||
String get music => "assets/svg/music.svg";
|
||||
String get pauseCircle => "assets/svg/pause-circle.svg";
|
||||
String get star => "assets/svg/star.svg";
|
||||
String get ticket => "assets/svg/ticket.svg";
|
||||
String get volume => "assets/svg/volume.svg";
|
||||
}
|
||||
|
||||
class _PNG {
|
||||
const _PNG();
|
||||
|
||||
// String get logo => "assets/images/teeny_pop_logo.png";
|
||||
|
||||
// Background
|
||||
// String get backgroundSky => "assets/images/background_sky.png";
|
||||
}
|
39
lib/widgets/gradient_button.dart
Normal file
@ -0,0 +1,39 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:match_magic/styles/styles.dart';
|
||||
|
||||
class GradientButton extends StatelessWidget {
|
||||
final VoidCallback onPressed;
|
||||
final String buttonText;
|
||||
|
||||
const GradientButton({
|
||||
Key? key,
|
||||
required this.onPressed,
|
||||
required this.buttonText,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: 40,
|
||||
decoration: const BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(100)),
|
||||
gradient: AppStyles.buttonGradient),
|
||||
child: ElevatedButton(
|
||||
onPressed: onPressed,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent,
|
||||
shadowColor: Colors.transparent,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
buttonText.toUpperCase(),
|
||||
style: const TextStyle(
|
||||
color: AppStyles.buttonPrimaryDefaultText,
|
||||
fontWeight: FontWeight.w700),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
27
lib/widgets/icon_widgets/arrow_left_icon.dart
Normal file
@ -0,0 +1,27 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:match_magic/styles/styles.dart';
|
||||
import 'package:match_magic/utilities/assets.dart';
|
||||
|
||||
class ArrowLeftIcon extends StatelessWidget {
|
||||
const ArrowLeftIcon({
|
||||
Key? key,
|
||||
this.width = 24,
|
||||
this.height = 24,
|
||||
this.color,
|
||||
}) : super(key: key);
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SvgPicture.asset(
|
||||
Assets.svg.arrowLeft,
|
||||
width: width,
|
||||
height: height,
|
||||
color: AppStyles.accentColorTopBar,
|
||||
);
|
||||
}
|
||||
}
|
25
lib/widgets/icon_widgets/check_circle_icon.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:match_magic/utilities/assets.dart';
|
||||
|
||||
class CheckCircleIcon extends StatelessWidget {
|
||||
const CheckCircleIcon({
|
||||
Key? key,
|
||||
this.width = 24,
|
||||
this.height = 24,
|
||||
this.color,
|
||||
}) : super(key: key);
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SvgPicture.asset(
|
||||
Assets.svg.checkCircle,
|
||||
width: width,
|
||||
height: height,
|
||||
);
|
||||
}
|
||||
}
|
25
lib/widgets/icon_widgets/check_icon.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:match_magic/utilities/assets.dart';
|
||||
|
||||
class CheckIcon extends StatelessWidget {
|
||||
const CheckIcon({
|
||||
Key? key,
|
||||
this.width = 18,
|
||||
this.height = 18,
|
||||
this.color,
|
||||
}) : super(key: key);
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SvgPicture.asset(
|
||||
Assets.svg.check,
|
||||
width: width,
|
||||
height: height,
|
||||
);
|
||||
}
|
||||
}
|
25
lib/widgets/icon_widgets/chevron_down_icon.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:match_magic/utilities/assets.dart';
|
||||
|
||||
class ChevronDownIcon extends StatelessWidget {
|
||||
const ChevronDownIcon({
|
||||
Key? key,
|
||||
this.width = 24,
|
||||
this.height = 24,
|
||||
this.color,
|
||||
}) : super(key: key);
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SvgPicture.asset(
|
||||
Assets.svg.chevronDown,
|
||||
width: width,
|
||||
height: height,
|
||||
);
|
||||
}
|
||||
}
|
25
lib/widgets/icon_widgets/chevron_right_icon.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:match_magic/utilities/assets.dart';
|
||||
|
||||
class ChevronRightIcon extends StatelessWidget {
|
||||
const ChevronRightIcon({
|
||||
Key? key,
|
||||
this.width = 24,
|
||||
this.height = 24,
|
||||
this.color,
|
||||
}) : super(key: key);
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SvgPicture.asset(
|
||||
Assets.svg.chevronRight,
|
||||
width: width,
|
||||
height: height,
|
||||
);
|
||||
}
|
||||
}
|
27
lib/widgets/icon_widgets/clipboard_icon.dart
Normal file
@ -0,0 +1,27 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:match_magic/styles/styles.dart';
|
||||
import 'package:match_magic/utilities/assets.dart';
|
||||
|
||||
class ClipboardIcon extends StatelessWidget {
|
||||
const ClipboardIcon({
|
||||
Key? key,
|
||||
this.width = 18,
|
||||
this.height = 18,
|
||||
this.color,
|
||||
}) : super(key: key);
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SvgPicture.asset(
|
||||
Assets.svg.clipboard,
|
||||
width: width,
|
||||
height: height,
|
||||
color: AppStyles.accentColor,
|
||||
);
|
||||
}
|
||||
}
|
25
lib/widgets/icon_widgets/music_icon.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:match_magic/utilities/assets.dart';
|
||||
|
||||
class MusicIcon extends StatelessWidget {
|
||||
const MusicIcon({
|
||||
Key? key,
|
||||
this.width = 18,
|
||||
this.height = 18,
|
||||
this.color,
|
||||
}) : super(key: key);
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SvgPicture.asset(
|
||||
Assets.svg.music,
|
||||
width: width,
|
||||
height: height,
|
||||
);
|
||||
}
|
||||
}
|
27
lib/widgets/icon_widgets/pause_circle_icon.dart
Normal file
@ -0,0 +1,27 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:match_magic/styles/styles.dart';
|
||||
import 'package:match_magic/utilities/assets.dart';
|
||||
|
||||
class PauseCircleIcon extends StatelessWidget {
|
||||
const PauseCircleIcon({
|
||||
Key? key,
|
||||
this.width = 34,
|
||||
this.height = 34,
|
||||
this.color,
|
||||
}) : super(key: key);
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SvgPicture.asset(
|
||||
Assets.svg.pauseCircle,
|
||||
width: width,
|
||||
height: height,
|
||||
color: AppStyles.accentColorTopBar,
|
||||
);
|
||||
}
|
||||
}
|
25
lib/widgets/icon_widgets/star_icon.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:match_magic/utilities/assets.dart';
|
||||
|
||||
class StarIcon extends StatelessWidget {
|
||||
const StarIcon({
|
||||
Key? key,
|
||||
this.width = 18,
|
||||
this.height = 18,
|
||||
this.color,
|
||||
}) : super(key: key);
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SvgPicture.asset(
|
||||
Assets.svg.star,
|
||||
width: width,
|
||||
height: height,
|
||||
);
|
||||
}
|
||||
}
|
25
lib/widgets/icon_widgets/ticket_icon.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:match_magic/utilities/assets.dart';
|
||||
|
||||
class TicketIcon extends StatelessWidget {
|
||||
const TicketIcon({
|
||||
Key? key,
|
||||
this.width = 18,
|
||||
this.height = 18,
|
||||
this.color,
|
||||
}) : super(key: key);
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SvgPicture.asset(
|
||||
Assets.svg.ticket,
|
||||
width: width,
|
||||
height: height,
|
||||
);
|
||||
}
|
||||
}
|
25
lib/widgets/icon_widgets/volume_icon.dart
Normal file
@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:match_magic/utilities/assets.dart';
|
||||
|
||||
class VolumeIcon extends StatelessWidget {
|
||||
const VolumeIcon({
|
||||
Key? key,
|
||||
this.width = 18,
|
||||
this.height = 18,
|
||||
this.color,
|
||||
}) : super(key: key);
|
||||
|
||||
final double width;
|
||||
final double height;
|
||||
final Color? color;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SvgPicture.asset(
|
||||
Assets.svg.volume,
|
||||
width: width,
|
||||
height: height,
|
||||
);
|
||||
}
|
||||
}
|
26
lib/widgets/overlays/game_overlay/hint_button.dart
Normal file
@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:match_magic/game/board.dart';
|
||||
|
||||
class HintButton extends StatelessWidget {
|
||||
final Board gameRef;
|
||||
static const String id = 'HintButton';
|
||||
const HintButton({Key? key, required this.gameRef}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Positioned(
|
||||
bottom: 46,
|
||||
left: 220,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
gameRef.showHint();
|
||||
},
|
||||
child: const Text(
|
||||
'Hint',
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
32
lib/widgets/overlays/game_overlay/pause_button.dart
Normal file
@ -0,0 +1,32 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:match_magic/game/board.dart';
|
||||
import 'package:match_magic/screens/pause_screen.dart';
|
||||
import 'package:match_magic/widgets/icon_widgets/pause_circle_icon.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/hint_button.dart';
|
||||
import 'package:match_magic/widgets/overlays/game_overlay/restart_button.dart';
|
||||
|
||||
class PauseButton extends StatelessWidget {
|
||||
final Board gameRef;
|
||||
static const String id = 'PauseButton';
|
||||
const PauseButton({Key? key, required this.gameRef}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Positioned(
|
||||
top: 46,
|
||||
left: 10,
|
||||
child: IconButton(
|
||||
onPressed: () {
|
||||
// AdManager.loadInterstitialAd();
|
||||
gameRef.pauseEngine();
|
||||
gameRef.overlays.add(PauseMenu.id);
|
||||
gameRef.overlays.remove(PauseButton.id);
|
||||
gameRef.overlays.remove(RestartButton.id);
|
||||
gameRef.overlays.remove(HintButton.id);
|
||||
},
|
||||
icon: PauseCircleIcon(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
26
lib/widgets/overlays/game_overlay/restart_button.dart
Normal file
@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:match_magic/game/board.dart';
|
||||
|
||||
class RestartButton extends StatelessWidget {
|
||||
final Board gameRef;
|
||||
static const String id = 'RestartButton';
|
||||
const RestartButton({Key? key, required this.gameRef}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Positioned(
|
||||
bottom: 46,
|
||||
left: 80,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
gameRef.newGame();
|
||||
},
|
||||
child: const Text(
|
||||
'Restart',
|
||||
style: TextStyle(color: Colors.black),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
32
lib/widgets/radio_button.dart
Normal file
@ -0,0 +1,32 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:match_magic/styles/styles.dart';
|
||||
|
||||
class RadioButton<T> extends StatelessWidget {
|
||||
final T value;
|
||||
final T? groupValue;
|
||||
final ValueChanged<T?>? onChanged;
|
||||
|
||||
const RadioButton({
|
||||
required this.value,
|
||||
required this.groupValue,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
Radio<T>(
|
||||
value: value,
|
||||
groupValue: groupValue,
|
||||
onChanged: onChanged,
|
||||
activeColor: AppStyles.accentColor,
|
||||
visualDensity: const VisualDensity(
|
||||
horizontal: VisualDensity.minimumDensity,
|
||||
vertical: VisualDensity.minimumDensity,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
26
lib/widgets/toggle_switch.dart
Normal file
@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:match_magic/styles/styles.dart';
|
||||
|
||||
class ToggleSwitch extends StatelessWidget {
|
||||
final ValueChanged<bool>? onChanged;
|
||||
final bool value;
|
||||
|
||||
const ToggleSwitch({
|
||||
Key? key,
|
||||
required this.onChanged,
|
||||
required this.value,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Switch(
|
||||
value: value,
|
||||
onChanged: onChanged,
|
||||
activeColor: AppStyles.toggleSwitchTextActive,
|
||||
activeTrackColor: AppStyles.toggleSwitchActiveBg,
|
||||
inactiveThumbColor: AppStyles.toggleSwitchTextInactive,
|
||||
inactiveTrackColor: AppStyles.toggleSwitchBg,
|
||||
trackOutlineColor: MaterialStateProperty.all(Colors.white.withOpacity(0)),
|
||||
);
|
||||
}
|
||||
}
|
@ -7,9 +7,13 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <audioplayers_linux/audioplayers_linux_plugin.h>
|
||||
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin");
|
||||
audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) isar_flutter_libs_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "IsarFlutterLibsPlugin");
|
||||
isar_flutter_libs_plugin_register_with_registrar(isar_flutter_libs_registrar);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
audioplayers_linux
|
||||
isar_flutter_libs
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
@ -6,9 +6,15 @@ import FlutterMacOS
|
||||
import Foundation
|
||||
|
||||
import audioplayers_darwin
|
||||
import isar_flutter_libs
|
||||
import package_info_plus
|
||||
import path_provider_foundation
|
||||
import shared_preferences_foundation
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
|
||||
IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin"))
|
||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
}
|
||||
|
482
pubspec.lock
@ -1,6 +1,30 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "61.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.13.0"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -73,6 +97,70 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
build:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
build_resolvers:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "644dc98a0f179b872f612d3eb627924b578897c629788e858157fa5e704ca0c7"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.11"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: e3c79f69a64bdfcd8a776a3c28db4eb6e3fb5356d013ae5eb2e52007706d5dbe
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.3.1"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_collection
|
||||
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
built_value:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.9.2"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -81,6 +169,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: checked_yaml
|
||||
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -89,6 +185,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: code_builder
|
||||
sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.10.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -97,6 +201,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -113,6 +225,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.8"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
dartx:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dartx
|
||||
sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -174,6 +302,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
flutter_svg:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_svg
|
||||
sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.10+1"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
@ -184,6 +320,30 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: frontend_server_client
|
||||
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: graphs
|
||||
sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
http:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -192,6 +352,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_multi_server
|
||||
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -200,6 +368,54 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: io
|
||||
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
isar:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: isar
|
||||
sha256: "99165dadb2cf2329d3140198363a7e7bff9bbd441871898a87e26914d25cf1ea"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0+1"
|
||||
isar_flutter_libs:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: isar_flutter_libs
|
||||
sha256: bc6768cc4b9c61aabff77152e7f33b4b17d2fc93134f7af1c3dd51500fe8d5e8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0+1"
|
||||
isar_generator:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: isar_generator
|
||||
sha256: "76c121e1295a30423604f2f819bc255bc79f852f3bc8743a24017df6068ad133"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0+1"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: json_annotation
|
||||
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.9.0"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -232,6 +448,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -256,6 +480,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.12.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -272,6 +504,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.1"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
package_info_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: package_info_plus
|
||||
sha256: a75164ade98cb7d24cfd0a13c6408927c6b217fa60dee5a7ff5c116a58f28918
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.0.2"
|
||||
package_info_plus_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_info_plus_platform_interface
|
||||
sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -280,8 +536,16 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
path_provider:
|
||||
path_parsing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_parsing
|
||||
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
path_provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
|
||||
@ -328,6 +592,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.2"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -344,6 +616,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pool
|
||||
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@ -352,11 +632,107 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.2"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "480ba4345773f56acda9abf5f50bd966f581dac5d514e5fc4a18c62976bbba7e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: c4b35f6cb8f63c147312c054ce7c2254c8066745125264f0c88739c417fc9d9f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.2"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -389,6 +765,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_transform
|
||||
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -421,6 +805,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.0"
|
||||
time:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: time
|
||||
sha256: ad8e018a6c9db36cb917a031853a1aae49467a93e0d464683e029537d848c221
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
timing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: timing
|
||||
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -437,6 +837,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.5.0"
|
||||
vector_graphics:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics
|
||||
sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.11+1"
|
||||
vector_graphics_codec:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_codec
|
||||
sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.11+1"
|
||||
vector_graphics_compiler:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_graphics_compiler
|
||||
sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.11+1"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -453,6 +877,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.1"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -461,6 +893,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.6"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.5.4"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -469,6 +925,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
xml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xml
|
||||
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.5.0"
|
||||
xxh3:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xxh3
|
||||
sha256: a92b30944a9aeb4e3d4f3c3d4ddb3c7816ca73475cd603682c4f8149690f56d7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
sdks:
|
||||
dart: ">=3.4.3 <4.0.0"
|
||||
flutter: ">=3.22.0"
|
||||
|
22
pubspec.yaml
@ -38,7 +38,13 @@ dependencies:
|
||||
cupertino_icons: ^1.0.6
|
||||
flame: ^1.18.0
|
||||
audioplayers: ^6.1.0
|
||||
flutter_svg: ^2.0.9
|
||||
flame_audio: ^2.10.3
|
||||
isar: ^3.1.0+1
|
||||
isar_flutter_libs: ^3.1.0+1
|
||||
package_info_plus: ^8.0.2
|
||||
path_provider: ^2.1.4
|
||||
shared_preferences: ^2.3.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@ -50,6 +56,8 @@ dev_dependencies:
|
||||
# package. See that file for information about deactivating specific lint
|
||||
# rules and activating additional ones.
|
||||
flutter_lints: ^3.0.0
|
||||
isar_generator: ^3.1.0+1
|
||||
build_runner: ^2.4.11
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
@ -64,17 +72,9 @@ flutter:
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
assets:
|
||||
- assets/images/crystal1.png
|
||||
- assets/images/crystal2.png
|
||||
- assets/images/crystal3.png
|
||||
- assets/images/crystal4.png
|
||||
- assets/images/crystal5.png
|
||||
- assets/images/crystal6.png
|
||||
- assets/images/crystal7.png
|
||||
- assets/images/magic_cube.png
|
||||
- assets/audio/explosion.ogg
|
||||
- assets/audio/four_elements.ogg
|
||||
- assets/audio/select.ogg
|
||||
- assets/images/
|
||||
- assets/svg/
|
||||
- assets/audio/
|
||||
|
||||
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
|
@ -7,8 +7,11 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <audioplayers_windows/audioplayers_windows_plugin.h>
|
||||
#include <isar_flutter_libs/isar_flutter_libs_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
AudioplayersWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
|
||||
IsarFlutterLibsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin"));
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
audioplayers_windows
|
||||
isar_flutter_libs
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|