> allOffsets,
+) {
+ final object = HighScore(
+ highScoreValue: reader.readLong(offsets[0]),
+ );
+ object.id = id;
+ return object;
+}
+
+P _highScoreDeserializeProp(
+ IsarReader reader,
+ int propertyId,
+ int offset,
+ Map> 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> _highScoreGetLinks(HighScore object) {
+ return [];
+}
+
+void _highScoreAttach(IsarCollection col, Id id, HighScore object) {
+ object.id = id;
+}
+
+extension HighScoreQueryWhereSort
+ on QueryBuilder {
+ QueryBuilder anyId() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addWhereClause(const IdWhereClause.any());
+ });
+ }
+}
+
+extension HighScoreQueryWhere
+ on QueryBuilder {
+ QueryBuilder idEqualTo(Id id) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addWhereClause(IdWhereClause.between(
+ lower: id,
+ upper: id,
+ ));
+ });
+ }
+
+ QueryBuilder 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 idGreaterThan(Id id,
+ {bool include = false}) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addWhereClause(
+ IdWhereClause.greaterThan(lower: id, includeLower: include),
+ );
+ });
+ }
+
+ QueryBuilder idLessThan(Id id,
+ {bool include = false}) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addWhereClause(
+ IdWhereClause.lessThan(upper: id, includeUpper: include),
+ );
+ });
+ }
+
+ QueryBuilder 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 {
+ QueryBuilder
+ highScoreValueEqualTo(int value) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.equalTo(
+ property: r'highScoreValue',
+ value: value,
+ ));
+ });
+ }
+
+ QueryBuilder
+ highScoreValueGreaterThan(
+ int value, {
+ bool include = false,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.greaterThan(
+ include: include,
+ property: r'highScoreValue',
+ value: value,
+ ));
+ });
+ }
+
+ QueryBuilder
+ highScoreValueLessThan(
+ int value, {
+ bool include = false,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.lessThan(
+ include: include,
+ property: r'highScoreValue',
+ value: value,
+ ));
+ });
+ }
+
+ QueryBuilder
+ 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 idEqualTo(
+ Id value) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.equalTo(
+ property: r'id',
+ value: value,
+ ));
+ });
+ }
+
+ QueryBuilder idGreaterThan(
+ Id value, {
+ bool include = false,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.greaterThan(
+ include: include,
+ property: r'id',
+ value: value,
+ ));
+ });
+ }
+
+ QueryBuilder idLessThan(
+ Id value, {
+ bool include = false,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.lessThan(
+ include: include,
+ property: r'id',
+ value: value,
+ ));
+ });
+ }
+
+ QueryBuilder 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 {}
+
+extension HighScoreQueryLinks
+ on QueryBuilder {}
+
+extension HighScoreQuerySortBy on QueryBuilder {
+ QueryBuilder sortByHighScoreValue() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'highScoreValue', Sort.asc);
+ });
+ }
+
+ QueryBuilder sortByHighScoreValueDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'highScoreValue', Sort.desc);
+ });
+ }
+}
+
+extension HighScoreQuerySortThenBy
+ on QueryBuilder {
+ QueryBuilder thenByHighScoreValue() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'highScoreValue', Sort.asc);
+ });
+ }
+
+ QueryBuilder thenByHighScoreValueDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'highScoreValue', Sort.desc);
+ });
+ }
+
+ QueryBuilder thenById() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'id', Sort.asc);
+ });
+ }
+
+ QueryBuilder thenByIdDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'id', Sort.desc);
+ });
+ }
+}
+
+extension HighScoreQueryWhereDistinct
+ on QueryBuilder {
+ QueryBuilder distinctByHighScoreValue() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addDistinctBy(r'highScoreValue');
+ });
+ }
+}
+
+extension HighScoreQueryProperty
+ on QueryBuilder {
+ QueryBuilder idProperty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addPropertyName(r'id');
+ });
+ }
+
+ QueryBuilder highScoreValueProperty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addPropertyName(r'highScoreValue');
+ });
+ }
+}
diff --git a/lib/models/isar/settings.dart b/lib/models/isar/settings.dart
new file mode 100644
index 0000000..02739f8
--- /dev/null
+++ b/lib/models/isar/settings.dart
@@ -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;
+}
diff --git a/lib/models/isar/settings.g.dart b/lib/models/isar/settings.g.dart
new file mode 100644
index 0000000..d2777c3
--- /dev/null
+++ b/lib/models/isar/settings.g.dart
@@ -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 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 offsets,
+ Map> allOffsets,
+) {
+ var bytesCount = offsets.last;
+ return bytesCount;
+}
+
+void _settingsSerialize(
+ Settings object,
+ IsarWriter writer,
+ List offsets,
+ Map> allOffsets,
+) {
+ writer.writeBool(offsets[0], object.isMusicEnabled);
+ writer.writeBool(offsets[1], object.isSoundEnabled);
+}
+
+Settings _settingsDeserialize(
+ Id id,
+ IsarReader reader,
+ List offsets,
+ Map> allOffsets,
+) {
+ final object = Settings(
+ isMusicEnabled: reader.readBool(offsets[0]),
+ isSoundEnabled: reader.readBool(offsets[1]),
+ );
+ object.id = id;
+ return object;
+}
+
+P _settingsDeserializeProp(
+ IsarReader reader,
+ int propertyId,
+ int offset,
+ Map> 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> _settingsGetLinks(Settings object) {
+ return [];
+}
+
+void _settingsAttach(IsarCollection col, Id id, Settings object) {
+ object.id = id;
+}
+
+extension SettingsQueryWhereSort on QueryBuilder {
+ QueryBuilder anyId() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addWhereClause(const IdWhereClause.any());
+ });
+ }
+}
+
+extension SettingsQueryWhere on QueryBuilder {
+ QueryBuilder idEqualTo(Id id) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addWhereClause(IdWhereClause.between(
+ lower: id,
+ upper: id,
+ ));
+ });
+ }
+
+ QueryBuilder 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 idGreaterThan(Id id,
+ {bool include = false}) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addWhereClause(
+ IdWhereClause.greaterThan(lower: id, includeLower: include),
+ );
+ });
+ }
+
+ QueryBuilder idLessThan(Id id,
+ {bool include = false}) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addWhereClause(
+ IdWhereClause.lessThan(upper: id, includeUpper: include),
+ );
+ });
+ }
+
+ QueryBuilder 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 {
+ QueryBuilder idEqualTo(Id value) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.equalTo(
+ property: r'id',
+ value: value,
+ ));
+ });
+ }
+
+ QueryBuilder idGreaterThan(
+ Id value, {
+ bool include = false,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.greaterThan(
+ include: include,
+ property: r'id',
+ value: value,
+ ));
+ });
+ }
+
+ QueryBuilder idLessThan(
+ Id value, {
+ bool include = false,
+ }) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.lessThan(
+ include: include,
+ property: r'id',
+ value: value,
+ ));
+ });
+ }
+
+ QueryBuilder 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 isMusicEnabledEqualTo(
+ bool value) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.equalTo(
+ property: r'isMusicEnabled',
+ value: value,
+ ));
+ });
+ }
+
+ QueryBuilder isSoundEnabledEqualTo(
+ bool value) {
+ return QueryBuilder.apply(this, (query) {
+ return query.addFilterCondition(FilterCondition.equalTo(
+ property: r'isSoundEnabled',
+ value: value,
+ ));
+ });
+ }
+}
+
+extension SettingsQueryObject
+ on QueryBuilder {}
+
+extension SettingsQueryLinks
+ on QueryBuilder {}
+
+extension SettingsQuerySortBy on QueryBuilder {
+ QueryBuilder sortByIsMusicEnabled() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'isMusicEnabled', Sort.asc);
+ });
+ }
+
+ QueryBuilder sortByIsMusicEnabledDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'isMusicEnabled', Sort.desc);
+ });
+ }
+
+ QueryBuilder sortByIsSoundEnabled() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'isSoundEnabled', Sort.asc);
+ });
+ }
+
+ QueryBuilder sortByIsSoundEnabledDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'isSoundEnabled', Sort.desc);
+ });
+ }
+}
+
+extension SettingsQuerySortThenBy
+ on QueryBuilder {
+ QueryBuilder thenById() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'id', Sort.asc);
+ });
+ }
+
+ QueryBuilder thenByIdDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'id', Sort.desc);
+ });
+ }
+
+ QueryBuilder thenByIsMusicEnabled() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'isMusicEnabled', Sort.asc);
+ });
+ }
+
+ QueryBuilder thenByIsMusicEnabledDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'isMusicEnabled', Sort.desc);
+ });
+ }
+
+ QueryBuilder thenByIsSoundEnabled() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'isSoundEnabled', Sort.asc);
+ });
+ }
+
+ QueryBuilder thenByIsSoundEnabledDesc() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addSortBy(r'isSoundEnabled', Sort.desc);
+ });
+ }
+}
+
+extension SettingsQueryWhereDistinct
+ on QueryBuilder {
+ QueryBuilder distinctByIsMusicEnabled() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addDistinctBy(r'isMusicEnabled');
+ });
+ }
+
+ QueryBuilder distinctByIsSoundEnabled() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addDistinctBy(r'isSoundEnabled');
+ });
+ }
+}
+
+extension SettingsQueryProperty
+ on QueryBuilder {
+ QueryBuilder idProperty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addPropertyName(r'id');
+ });
+ }
+
+ QueryBuilder isMusicEnabledProperty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addPropertyName(r'isMusicEnabled');
+ });
+ }
+
+ QueryBuilder isSoundEnabledProperty() {
+ return QueryBuilder.apply(this, (query) {
+ return query.addPropertyName(r'isSoundEnabled');
+ });
+ }
+}
diff --git a/lib/screens/game_over_screen.dart b/lib/screens/game_over_screen.dart
new file mode 100644
index 0000000..b4b6543
--- /dev/null
+++ b/lib/screens/game_over_screen.dart
@@ -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(
+ 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'),
+ )
+ ],
+ ),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/screens/game_screen.dart b/lib/screens/game_screen.dart
new file mode 100644
index 0000000..57aa181
--- /dev/null
+++ b/lib/screens/game_screen.dart
@@ -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 {
+ 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!),
+ // ),
+ // ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/screens/main_menu.dart b/lib/screens/main_menu.dart
deleted file mode 100644
index 36bae61..0000000
--- a/lib/screens/main_menu.dart
+++ /dev/null
@@ -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)),
- ),
- ],
- ),
- ),
- );
- }
-}
diff --git a/lib/screens/main_menu_screen.dart b/lib/screens/main_menu_screen.dart
new file mode 100644
index 0000000..c9ef983
--- /dev/null
+++ b/lib/screens/main_menu_screen.dart
@@ -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 createState() => _MainMenuScreenState();
+}
+
+class _MainMenuScreenState extends State {
+ bool islevelProgression = true;
+
+ @override
+ void initState() {
+ super.initState();
+ SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
+ // _loadBackground();
+ // _checkPremiumStatus();
+ _loadMode();
+ }
+
+ Future _loadMode() async {
+ final mode = await AppStateManager.getMode();
+ setState(() {
+ islevelProgression = mode;
+ });
+ }
+
+ // Future _loadBackground() async {
+ // final background = await MainDB.instance.getBackground();
+ // setState(() {
+ // backgroundImage = background;
+ // });
+ // }
+
+ // void _updateBackground(Background newBackground) {
+ // setState(() {
+ // backgroundImage = newBackground;
+ // });
+ // }
+
+ // // Premium check
+ // Future _checkPremiumStatus() async {
+ // bool isPremium = await AppStateManager.isPremium();
+ // setState(() {
+ // _isPremium = isPremium;
+ // });
+ // }
+
+ Future _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),
+ ],
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/screens/options_screen.dart b/lib/screens/options_screen.dart
new file mode 100644
index 0000000..9185126
--- /dev/null
+++ b/lib/screens/options_screen.dart
@@ -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 createState() => _OptionsScreenState();
+}
+
+class _OptionsScreenState extends State {
+ bool isSound = true;
+ bool isMusic = true;
+ // Background? backgroundImage;
+
+ @override
+ void initState() {
+ super.initState();
+ fetchSoundAndMusicState();
+ // _loadBackground();
+ getVersionNumber();
+ // _checkPremiumStatus();
+ }
+
+ Future getVersionNumber() async {
+ PackageInfo packageInfo = await PackageInfo.fromPlatform();
+ return packageInfo.version;
+ }
+
+ // Future _loadBackground() async {
+ // final background = await MainDB.instance.getBackground();
+ // setState(() {
+ // backgroundImage = background;
+ // });
+ // }
+
+ // Future _checkPremiumStatus() async {
+ // bool isPremium = await AppStateManager.isPremium();
+ // setState(() {
+ // _isPremium = isPremium;
+ // });
+ // }
+
+ // Future refreshOptionsScreen() async {
+ // await _checkPremiumStatus();
+
+ // setState(() {});
+ // }
+
+ Future 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(
+ 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(
+ future: getVersionNumber(),
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ return Text('Version: ${snapshot.data}');
+ } else {
+ return Text('Version: loading...');
+ }
+ },
+ )
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/screens/pause_screen.dart b/lib/screens/pause_screen.dart
new file mode 100644
index 0000000..945e40c
--- /dev/null
+++ b/lib/screens/pause_screen.dart
@@ -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 createState() => _PauseMenuState();
+}
+
+class _PauseMenuState extends State {
+ 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'),
+ )),
+ ],
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/styles/styles.dart b/lib/styles/styles.dart
new file mode 100644
index 0000000..855657d
--- /dev/null
+++ b/lib/styles/styles.dart
@@ -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);
+}
diff --git a/lib/utilities/assets.dart b/lib/utilities/assets.dart
new file mode 100644
index 0000000..e053497
--- /dev/null
+++ b/lib/utilities/assets.dart
@@ -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";
+}
diff --git a/lib/widgets/gradient_button.dart b/lib/widgets/gradient_button.dart
new file mode 100644
index 0000000..368f206
--- /dev/null
+++ b/lib/widgets/gradient_button.dart
@@ -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),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/icon_widgets/arrow_left_icon.dart b/lib/widgets/icon_widgets/arrow_left_icon.dart
new file mode 100644
index 0000000..f3bd98c
--- /dev/null
+++ b/lib/widgets/icon_widgets/arrow_left_icon.dart
@@ -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,
+ );
+ }
+}
diff --git a/lib/widgets/icon_widgets/check_circle_icon.dart b/lib/widgets/icon_widgets/check_circle_icon.dart
new file mode 100644
index 0000000..c672cc6
--- /dev/null
+++ b/lib/widgets/icon_widgets/check_circle_icon.dart
@@ -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,
+ );
+ }
+}
diff --git a/lib/widgets/icon_widgets/check_icon.dart b/lib/widgets/icon_widgets/check_icon.dart
new file mode 100644
index 0000000..c484080
--- /dev/null
+++ b/lib/widgets/icon_widgets/check_icon.dart
@@ -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,
+ );
+ }
+}
diff --git a/lib/widgets/icon_widgets/chevron_down_icon.dart b/lib/widgets/icon_widgets/chevron_down_icon.dart
new file mode 100644
index 0000000..51919e2
--- /dev/null
+++ b/lib/widgets/icon_widgets/chevron_down_icon.dart
@@ -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,
+ );
+ }
+}
diff --git a/lib/widgets/icon_widgets/chevron_right_icon.dart b/lib/widgets/icon_widgets/chevron_right_icon.dart
new file mode 100644
index 0000000..3f948f7
--- /dev/null
+++ b/lib/widgets/icon_widgets/chevron_right_icon.dart
@@ -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,
+ );
+ }
+}
diff --git a/lib/widgets/icon_widgets/clipboard_icon.dart b/lib/widgets/icon_widgets/clipboard_icon.dart
new file mode 100644
index 0000000..edec2a5
--- /dev/null
+++ b/lib/widgets/icon_widgets/clipboard_icon.dart
@@ -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,
+ );
+ }
+}
diff --git a/lib/widgets/icon_widgets/music_icon.dart b/lib/widgets/icon_widgets/music_icon.dart
new file mode 100644
index 0000000..46ef162
--- /dev/null
+++ b/lib/widgets/icon_widgets/music_icon.dart
@@ -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,
+ );
+ }
+}
diff --git a/lib/widgets/icon_widgets/pause_circle_icon.dart b/lib/widgets/icon_widgets/pause_circle_icon.dart
new file mode 100644
index 0000000..e14d24a
--- /dev/null
+++ b/lib/widgets/icon_widgets/pause_circle_icon.dart
@@ -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,
+ );
+ }
+}
diff --git a/lib/widgets/icon_widgets/star_icon.dart b/lib/widgets/icon_widgets/star_icon.dart
new file mode 100644
index 0000000..a55c064
--- /dev/null
+++ b/lib/widgets/icon_widgets/star_icon.dart
@@ -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,
+ );
+ }
+}
diff --git a/lib/widgets/icon_widgets/ticket_icon.dart b/lib/widgets/icon_widgets/ticket_icon.dart
new file mode 100644
index 0000000..ecd133f
--- /dev/null
+++ b/lib/widgets/icon_widgets/ticket_icon.dart
@@ -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,
+ );
+ }
+}
diff --git a/lib/widgets/icon_widgets/volume_icon.dart b/lib/widgets/icon_widgets/volume_icon.dart
new file mode 100644
index 0000000..970c70b
--- /dev/null
+++ b/lib/widgets/icon_widgets/volume_icon.dart
@@ -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,
+ );
+ }
+}
diff --git a/lib/widgets/overlays/game_overlay/hint_button.dart b/lib/widgets/overlays/game_overlay/hint_button.dart
new file mode 100644
index 0000000..20da7e4
--- /dev/null
+++ b/lib/widgets/overlays/game_overlay/hint_button.dart
@@ -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),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/overlays/game_overlay/pause_button.dart b/lib/widgets/overlays/game_overlay/pause_button.dart
new file mode 100644
index 0000000..71f5428
--- /dev/null
+++ b/lib/widgets/overlays/game_overlay/pause_button.dart
@@ -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(),
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/overlays/game_overlay/restart_button.dart b/lib/widgets/overlays/game_overlay/restart_button.dart
new file mode 100644
index 0000000..76d9ca2
--- /dev/null
+++ b/lib/widgets/overlays/game_overlay/restart_button.dart
@@ -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),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/radio_button.dart b/lib/widgets/radio_button.dart
new file mode 100644
index 0000000..9b79ee6
--- /dev/null
+++ b/lib/widgets/radio_button.dart
@@ -0,0 +1,32 @@
+import 'package:flutter/material.dart';
+import 'package:match_magic/styles/styles.dart';
+
+class RadioButton extends StatelessWidget {
+ final T value;
+ final T? groupValue;
+ final ValueChanged? onChanged;
+
+ const RadioButton({
+ required this.value,
+ required this.groupValue,
+ required this.onChanged,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ children: [
+ Radio(
+ value: value,
+ groupValue: groupValue,
+ onChanged: onChanged,
+ activeColor: AppStyles.accentColor,
+ visualDensity: const VisualDensity(
+ horizontal: VisualDensity.minimumDensity,
+ vertical: VisualDensity.minimumDensity,
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/toggle_switch.dart b/lib/widgets/toggle_switch.dart
new file mode 100644
index 0000000..17547b2
--- /dev/null
+++ b/lib/widgets/toggle_switch.dart
@@ -0,0 +1,26 @@
+import 'package:flutter/material.dart';
+import 'package:match_magic/styles/styles.dart';
+
+class ToggleSwitch extends StatelessWidget {
+ final ValueChanged? 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)),
+ );
+ }
+}
diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc
index 1830e5c..7faaafd 100644
--- a/linux/flutter/generated_plugin_registrant.cc
+++ b/linux/flutter/generated_plugin_registrant.cc
@@ -7,9 +7,13 @@
#include "generated_plugin_registrant.h"
#include
+#include
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);
}
diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake
index e9abb91..98e76e5 100644
--- a/linux/flutter/generated_plugins.cmake
+++ b/linux/flutter/generated_plugins.cmake
@@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_linux
+ isar_flutter_libs
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift
index a9f2f23..c272181 100644
--- a/macos/Flutter/GeneratedPluginRegistrant.swift
+++ b/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -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"))
}
diff --git a/pubspec.lock b/pubspec.lock
index 284de48..f0f3a3d 100644
--- a/pubspec.lock
+++ b/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"
diff --git a/pubspec.yaml b/pubspec.yaml
index c992ecf..050314a 100644
--- a/pubspec.yaml
+++ b/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
diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc
index 09e8e2c..ba7f138 100644
--- a/windows/flutter/generated_plugin_registrant.cc
+++ b/windows/flutter/generated_plugin_registrant.cc
@@ -7,8 +7,11 @@
#include "generated_plugin_registrant.h"
#include
+#include
void RegisterPlugins(flutter::PluginRegistry* registry) {
AudioplayersWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
+ IsarFlutterLibsPluginRegisterWithRegistrar(
+ registry->GetRegistrarForPlugin("IsarFlutterLibsPlugin"));
}
diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake
index 375535c..f310bcc 100644
--- a/windows/flutter/generated_plugins.cmake
+++ b/windows/flutter/generated_plugins.cmake
@@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_windows
+ isar_flutter_libs
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST