Skip to content
Snippets Groups Projects
Commit 5ebf63f4 authored by Benoît Harrault's avatar Benoît Harrault
Browse files

Improve game architecture

parent e9d89ace
No related branches found
No related tags found
1 merge request!18Resolve "Improve game architecture"
Pipeline #5492 passed
Showing
with 884 additions and 39 deletions
import 'package:flutter/material.dart';
import 'package:solitaire/provider/data.dart';
class Tileset extends StatelessWidget {
const Tileset({super.key, required this.myProvider});
final Data myProvider;
@override
Widget build(BuildContext context) {
final Board board = myProvider.board;
Widget boardTileWithoutHole = Image(
image: AssetImage('assets/skins/${myProvider.parameterSkin}_board.png'),
width: myProvider.tileSize,
height: myProvider.tileSize,
fit: BoxFit.fill,
);
return Column(
children: [
Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
for (int row = 0; row < board.length; row++)
TableRow(
children: [
for (int col = 0; col < board[row].length; col++)
TableCell(
child: board[row][col] != null
? (board[row][col]?.render(myProvider) ?? Container())
: boardTileWithoutHole,
),
],
),
],
),
],
);
}
}
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:solitaire/ui/widgets/header_app.dart';
class AboutPage extends StatelessWidget {
const AboutPage({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
const SizedBox(height: 8),
const AppHeader(text: 'about_title'),
const Text('about_content').tr(),
FutureBuilder<PackageInfo>(
future: PackageInfo.fromPlatform(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
return const Text('about_version').tr(
namedArgs: {
'version': snapshot.data!.version,
},
);
default:
return const SizedBox();
}
},
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:overlay_support/overlay_support.dart';
import 'package:solitaire_game/layout/game.dart';
import 'package:solitaire_game/layout/parameters.dart';
import 'package:solitaire_game/provider/data.dart';
import 'package:solitaire_game/utils/game_utils.dart';
class Home extends StatefulWidget {
const Home({super.key});
import 'package:solitaire/provider/data.dart';
import 'package:solitaire/ui/layout/game.dart';
import 'package:solitaire/ui/layout/parameters.dart';
static const String id = 'home';
class GamePage extends StatefulWidget {
const GamePage({super.key});
@override
HomeState createState() => HomeState();
GamePageState createState() => GamePageState();
}
class HomeState extends State<Home> {
class GamePageState extends State<GamePage> {
@override
void initState() {
super.initState();
Data myProvider = Provider.of<Data>(context, listen: false);
final Data myProvider = Provider.of<Data>(context, listen: false);
myProvider.initParametersValues();
myProvider.loadCurrentSavedState();
}
......@@ -65,10 +62,10 @@ class HomeState extends State<Home> {
@override
Widget build(BuildContext context) {
Data myProvider = Provider.of<Data>(context);
final Data myProvider = Provider.of<Data>(context);
if (!myProvider.assetsPreloaded) {
List<String> assets = getImagesAssets(myProvider);
final List<String> assets = getImagesAssets(myProvider);
for (String asset in assets) {
precacheImage(AssetImage(asset), context);
}
......@@ -77,40 +74,11 @@ class HomeState extends State<Home> {
myProvider.updateTileSize((MediaQuery.of(context).size.width - 40) / myProvider.boardSize);
List<Widget> menuActions = [];
if (myProvider.gameIsRunning) {
menuActions = [
TextButton(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: Colors.blue,
width: 4,
),
),
child: const Image(
image: AssetImage('assets/icons/button_back.png'),
fit: BoxFit.fill,
),
),
onPressed: () => toast('Long press to quit game...'),
onLongPress: () => GameUtils.quitGame(myProvider),
),
];
}
return Scaffold(
appBar: AppBar(
actions: menuActions,
),
body: SafeArea(
child: Center(
child: myProvider.gameIsRunning
? Game.buildGameWidget(myProvider)
: Parameters.buildParametersSelector(myProvider),
),
return SafeArea(
child: Center(
child: myProvider.gameIsRunning
? Game(myProvider: myProvider)
: Parameters(myProvider: myProvider),
),
);
}
......
import 'package:flutter/material.dart';
import 'package:solitaire/ui/widgets/header_app.dart';
import 'package:solitaire/ui/widgets/settings/settings_form.dart';
class SettingsPage extends StatelessWidget {
const SettingsPage({super.key});
@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
SizedBox(height: 8),
AppHeader(text: 'settings_title'),
SizedBox(height: 8),
SettingsForm(),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
import 'package:solitaire/config/menu.dart';
import 'package:solitaire/cubit/bottom_nav_cubit.dart';
import 'package:solitaire/provider/data.dart';
import 'package:solitaire/ui/widgets/app_bar.dart';
import 'package:solitaire/ui/widgets/bottom_nav_bar.dart';
class SkeletonScreen extends StatefulWidget {
const SkeletonScreen({super.key});
@override
State<SkeletonScreen> createState() => _SkeletonScreenState();
}
class _SkeletonScreenState extends State<SkeletonScreen> {
@override
Widget build(BuildContext context) {
final Data myProvider = Provider.of<Data>(context);
return Scaffold(
extendBodyBehindAppBar: false,
appBar: StandardAppBar(myProvider: myProvider),
bottomNavigationBar: const BottomNavBar(),
body: BlocBuilder<BottomNavCubit, int>(builder: (BuildContext context, int state) {
return Menu.getPageWidget(state);
}),
backgroundColor: Theme.of(context).colorScheme.background,
);
}
}
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:overlay_support/overlay_support.dart';
import 'package:solitaire/provider/data.dart';
import 'package:solitaire/ui/widgets/header_app.dart';
import 'package:solitaire/utils/game_utils.dart';
class StandardAppBar extends StatelessWidget implements PreferredSizeWidget {
const StandardAppBar({super.key, required this.myProvider});
final Data myProvider;
@override
Widget build(BuildContext context) {
final List<Widget> menuActions = [];
if (myProvider.gameIsRunning) {
menuActions.add(TextButton(
child: const Image(
image: AssetImage('assets/icons/button_back.png'),
fit: BoxFit.fill,
),
onPressed: () => toast(tr('long_press_to_quit')),
onLongPress: () => GameUtils.quitGame(myProvider),
));
}
return AppBar(
title: const AppHeader(text: 'app_name'),
actions: menuActions,
);
}
@override
Size get preferredSize => const Size.fromHeight(50);
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:solitaire/config/menu.dart';
import 'package:solitaire/cubit/bottom_nav_cubit.dart';
class BottomNavBar extends StatelessWidget {
const BottomNavBar({super.key});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.all(0),
elevation: 4,
shadowColor: Theme.of(context).colorScheme.shadow,
color: Theme.of(context).colorScheme.surfaceVariant,
shape: const ContinuousRectangleBorder(),
child: BlocBuilder<BottomNavCubit, int>(
builder: (BuildContext context, int state) {
return BottomNavigationBar(
currentIndex: state,
onTap: (int index) {
context.read<BottomNavCubit>().updateIndex(index);
},
type: BottomNavigationBarType.fixed,
elevation: 0,
backgroundColor: Colors.transparent,
selectedItemColor: Theme.of(context).colorScheme.primary,
unselectedItemColor: Theme.of(context).textTheme.bodySmall!.color,
items: Menu.getMenuItems(),
);
},
),
);
}
}
import 'package:flutter/material.dart';
import 'package:solitaire_game/layout/board.dart';
import 'package:solitaire_game/provider/data.dart';
import 'package:solitaire_game/utils/game_utils.dart';
class Game {
static Widget buildGameWidget(Data myProvider) {
final bool gameIsFinished = myProvider.gameIsFinished;
import 'package:solitaire/provider/data.dart';
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const SizedBox(height: 8),
Game.buildTopIndicatorWidget(myProvider),
const SizedBox(height: 2),
Expanded(
child: Board.buildGameBoard(myProvider),
),
const SizedBox(height: 2),
Container(
child: gameIsFinished
? Game.buildEndGameMessage(myProvider)
: const SizedBox(height: 2),
),
],
);
}
class TopIndicator extends StatelessWidget {
const TopIndicator({super.key, required this.myProvider});
static Widget buildTopIndicatorWidget(Data myProvider) {
final Data myProvider;
@override
Widget build(BuildContext context) {
final int allowedMovesCount = myProvider.allowedMovesCount;
return Table(
......@@ -63,51 +44,4 @@ class Game {
],
);
}
static TextButton buildQuitGameButton(Data myProvider) {
return TextButton(
child: const Image(
image: AssetImage('assets/icons/button_back.png'),
fit: BoxFit.fill,
),
onPressed: () => GameUtils.quitAndDeleteCurrentGame(myProvider),
);
}
static Container buildEndGameMessage(Data myProvider) {
String decorationImageAssetName = '';
if (myProvider.gameWon()) {
decorationImageAssetName = 'assets/icons/game_win.png';
} else {
decorationImageAssetName = 'assets/icons/placeholder.png';
}
final Image decorationImage = Image(
image: AssetImage(decorationImageAssetName),
fit: BoxFit.fill,
);
return Container(
margin: const EdgeInsets.all(2),
padding: const EdgeInsets.all(2),
child: Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
Column(
children: [decorationImage],
),
Column(
children: [buildQuitGameButton(myProvider)],
),
Column(
children: [decorationImage],
),
],
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:solitaire/provider/data.dart';
import 'package:solitaire/ui/widgets/home/button_game_restart.dart';
class EndGameMessage extends StatelessWidget {
const EndGameMessage({super.key, required this.myProvider});
final Data myProvider;
@override
Widget build(BuildContext context) {
String decorationImageAssetName = '';
if (myProvider.gameWon()) {
decorationImageAssetName = 'assets/icons/game_win.png';
} else {
decorationImageAssetName = 'assets/icons/placeholder.png';
}
final Image decorationImage = Image(
image: AssetImage(decorationImageAssetName),
fit: BoxFit.fill,
);
return Container(
margin: const EdgeInsets.all(2),
padding: const EdgeInsets.all(2),
child: Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
Column(children: [decorationImage]),
Column(children: [RestartGameButton(myProvider: myProvider)]),
Column(children: [decorationImage]),
],
),
],
),
);
}
}
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
class AppHeader extends StatelessWidget {
const AppHeader({super.key, required this.text});
final String text;
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tr(text),
textAlign: TextAlign.start,
style: Theme.of(context).textTheme.headlineMedium!.apply(fontWeightDelta: 2),
),
],
);
}
}
import 'package:flutter/material.dart';
import 'package:solitaire/provider/data.dart';
import 'package:solitaire/utils/game_utils.dart';
class RestartGameButton extends StatelessWidget {
const RestartGameButton({super.key, required this.myProvider});
final Data myProvider;
@override
Widget build(BuildContext context) {
return TextButton(
child: const Image(
image: AssetImage('assets/icons/button_back.png'),
fit: BoxFit.fill,
),
onPressed: () => GameUtils.quitAndDeleteCurrentGame(myProvider),
);
}
}
import 'package:flutter/material.dart';
import 'package:solitaire/ui/layout/parameters.dart';
import 'package:solitaire/utils/game_utils.dart';
class ResumeGameButton extends Parameters {
const ResumeGameButton({super.key, required super.myProvider});
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(Parameters.blockMargin),
padding: const EdgeInsets.all(Parameters.blockPadding),
child: Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
Column(
children: [
TextButton(
child: Parameters.buildImageContainerWidget('button_delete_saved_game'),
onPressed: () => GameUtils.deleteSavedGame(myProvider),
),
],
),
Column(
children: [
TextButton(
child: Parameters.buildImageContainerWidget('button_resume_game'),
onPressed: () => GameUtils.resumeSavedGame(myProvider),
),
],
),
Parameters.buildDecorationImageWidget(),
],
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:solitaire/provider/data.dart';
import 'package:solitaire/ui/layout/parameters.dart';
import 'package:solitaire/utils/game_utils.dart';
class StartNewGameButton extends StatelessWidget {
const StartNewGameButton({super.key, required this.myProvider});
final Data myProvider;
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.all(Parameters.blockMargin),
padding: const EdgeInsets.all(Parameters.blockPadding),
child: Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
Parameters.buildDecorationImageWidget(),
Column(
children: [
TextButton(
child: Parameters.buildImageContainerWidget('button_start'),
onPressed: () => GameUtils.startNewGame(myProvider),
),
],
),
Parameters.buildDecorationImageWidget(),
],
),
],
),
);
}
}
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:unicons/unicons.dart';
import 'package:solitaire/ui/widgets/settings/theme_card.dart';
class SettingsForm extends StatefulWidget {
const SettingsForm({super.key});
@override
State<SettingsForm> createState() => _SettingsFormState();
}
class _SettingsFormState extends State<SettingsForm> {
@override
void dispose() {
super.dispose();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
// Light/dark theme
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
const Text('settings_label_theme').tr(),
const Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ThemeCard(
mode: ThemeMode.system,
icon: UniconsLine.cog,
),
ThemeCard(
mode: ThemeMode.light,
icon: UniconsLine.sun,
),
ThemeCard(
mode: ThemeMode.dark,
icon: UniconsLine.moon,
)
],
),
],
),
const SizedBox(height: 16),
],
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:solitaire/cubit/theme_cubit.dart';
class ThemeCard extends StatelessWidget {
const ThemeCard({
super.key,
required this.mode,
required this.icon,
});
final IconData icon;
final ThemeMode mode;
@override
Widget build(BuildContext context) {
return BlocBuilder<ThemeCubit, ThemeModeState>(
builder: (BuildContext context, ThemeModeState state) {
return Card(
elevation: 2,
shadowColor: Theme.of(context).colorScheme.shadow,
color: state.themeMode == mode
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.surface,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(5),
child: InkWell(
onTap: () => BlocProvider.of<ThemeCubit>(context).getTheme(
ThemeModeState(themeMode: mode),
),
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: Icon(
icon,
size: 32,
color: state.themeMode != mode
? Theme.of(context).colorScheme.primary
: Colors.white,
),
),
);
},
);
}
}
import 'dart:math';
import 'package:solitaire_game/entities/tile.dart';
import 'package:solitaire_game/provider/data.dart';
import 'package:solitaire_game/utils/tools.dart';
import 'package:solitaire/entities/tile.dart';
import 'package:solitaire/provider/data.dart';
import 'package:solitaire/utils/tools.dart';
class BoardUtils {
static printGrid(List cells) {
......@@ -28,8 +28,8 @@ class BoardUtils {
printlog('');
}
static List<List<Tile?>> createBoardFromSavedState(Data myProvider, String savedBoard) {
List<List<Tile?>> board = [];
static Board createBoardFromSavedState(Data myProvider, String savedBoard) {
Board board = [];
int boardSize = pow((savedBoard.length), 1 / 2).round();
myProvider.updateBoardSize(boardSize);
......@@ -99,7 +99,7 @@ class BoardUtils {
List<String>? template = templates[myProvider.parameterLayout];
List<List<Tile?>> grid = [];
Board grid = [];
int row = 0;
template?.forEach((String line) {
List<Tile?> gridLine = [];
......
import 'package:solitaire_game/entities/tile.dart';
import 'package:solitaire_game/provider/data.dart';
import 'package:solitaire_game/utils/board_utils.dart';
import 'package:solitaire_game/utils/tools.dart';
import 'package:solitaire/entities/tile.dart';
import 'package:solitaire/provider/data.dart';
import 'package:solitaire/utils/board_utils.dart';
import 'package:solitaire/utils/tools.dart';
class GameUtils {
static Future<void> quitGame(Data myProvider) async {
......@@ -51,11 +51,11 @@ class GameUtils {
static bool isMoveAllowed(Data myProvider, List<int> source, List<int> target) {
// printlog('(test) Pick from ' + source.toString() + ' and drop on ' + target.toString());
List<List<Tile?>> board = myProvider.board;
int sourceCol = source[0];
int sourceRow = source[1];
int targetCol = target[0];
int targetRow = target[1];
final Board board = myProvider.board;
final int sourceCol = source[0];
final int sourceRow = source[1];
final int targetCol = target[0];
final int targetRow = target[1];
// ensure source and target are inside range
if (sourceRow < 0 ||
......@@ -99,8 +99,8 @@ class GameUtils {
}
// ensure middle tile exists and has a peg
int middleRow = (sourceRow + ((targetRow - sourceRow) / 2)).round();
int middleCol = (sourceCol + ((targetCol - sourceCol) / 2)).round();
final int middleRow = (sourceRow + ((targetRow - sourceRow) / 2)).round();
final int middleCol = (sourceCol + ((targetCol - sourceCol) / 2)).round();
if (board[middleRow][middleCol] == null || board[middleRow][middleCol]?.hasPeg == false) {
// printlog('move forbidden: tile between source and target does not contain a peg');
return false;
......@@ -112,13 +112,13 @@ class GameUtils {
static void move(Data myProvider, List<int> source, List<int> target) {
printlog('Move from $source to $target');
int sourceCol = source[0];
int sourceRow = source[1];
int targetCol = target[0];
int targetRow = target[1];
final int sourceCol = source[0];
final int sourceRow = source[1];
final int targetCol = target[0];
final int targetRow = target[1];
int middleRow = (sourceRow + ((targetRow - sourceRow) / 2)).round();
int middleCol = (sourceCol + ((targetCol - sourceCol) / 2)).round();
final int middleRow = (sourceRow + ((targetRow - sourceRow) / 2)).round();
final int middleCol = (sourceCol + ((targetCol - sourceCol) / 2)).round();
// remove peg from source
myProvider.updatePegValue(sourceRow, sourceCol, false);
......@@ -138,7 +138,7 @@ class GameUtils {
static List<Tile> listRemainingPegs(Data myProvider) {
List<Tile> pegs = [];
List<List<Tile?>> board = myProvider.board;
Board board = myProvider.board;
for (int rowIndex = 0; rowIndex < board.length; rowIndex++) {
for (int colIndex = 0; colIndex < board[rowIndex].length; colIndex++) {
Tile? tile = board[rowIndex][colIndex];
......@@ -159,10 +159,10 @@ class GameUtils {
int allowedMovesCount = 0;
List<Tile> pegs = GameUtils.listRemainingPegs(myProvider);
for (Tile tile in pegs) {
int row = tile.currentRow;
int col = tile.currentCol;
List<int> source = [col, row];
List<List<int>> targets = [
final int row = tile.currentRow;
final int col = tile.currentCol;
final List<int> source = [col, row];
final List<List<int>> targets = [
[col - 2, row],
[col + 2, row],
[col, row - 2],
......
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
args:
dependency: transitive
description:
name: args
sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
url: "https://pub.dev"
source: hosted
version: "2.4.2"
async:
dependency: transitive
description:
......@@ -9,6 +17,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.11.0"
bloc:
dependency: transitive
description:
name: bloc
sha256: f53a110e3b48dcd78136c10daa5d51512443cea5e1348c9d80a320095fa2db9e
url: "https://pub.dev"
source: hosted
version: "8.1.3"
characters:
dependency: transitive
description:
......@@ -17,6 +33,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.0"
clock:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.1"
collection:
dependency: transitive
description:
......@@ -25,6 +49,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.18.0"
crypto:
dependency: transitive
description:
name: crypto
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.3"
easy_localization:
dependency: "direct main"
description:
name: easy_localization
sha256: c145aeb6584aedc7c862ab8c737c3277788f47488bfdf9bae0fe112bd0a4789c
url: "https://pub.dev"
source: hosted
version: "3.0.5"
easy_logger:
dependency: transitive
description:
name: easy_logger
sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7
url: "https://pub.dev"
source: hosted
version: "0.0.2"
equatable:
dependency: "direct main"
description:
name: equatable
sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
url: "https://pub.dev"
source: hosted
version: "2.0.5"
ffi:
dependency: transitive
description:
......@@ -46,6 +102,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_bloc:
dependency: "direct main"
description:
name: flutter_bloc
sha256: "87325da1ac757fcc4813e6b34ed5dd61169973871fdf181d6c2109dd6935ece1"
url: "https://pub.dev"
source: hosted
version: "8.1.4"
flutter_lints:
dependency: "direct dev"
description:
......@@ -54,11 +118,56 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.1"
flutter_localizations:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
hive:
dependency: "direct main"
description:
name: hive
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
url: "https://pub.dev"
source: hosted
version: "2.2.3"
http:
dependency: transitive
description:
name: http
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
url: "https://pub.dev"
source: hosted
version: "1.2.0"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
hydrated_bloc:
dependency: "direct main"
description:
name: hydrated_bloc
sha256: "00a2099680162e74b5a836b8a7f446e478520a9cae9f6032e028ad8129f4432d"
url: "https://pub.dev"
source: hosted
version: "9.1.4"
intl:
dependency: transitive
description:
name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
url: "https://pub.dev"
source: hosted
version: "0.18.1"
lints:
dependency: transitive
description:
......@@ -99,14 +208,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.0"
path:
package_info_plus:
dependency: "direct main"
description:
name: package_info_plus
sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79"
url: "https://pub.dev"
source: hosted
version: "5.0.1"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
path:
dependency: "direct main"
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
path_provider:
dependency: "direct main"
description:
name: path_provider
sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b
url: "https://pub.dev"
source: hosted
version: "2.1.2"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
path_provider_linux:
dependency: transitive
description:
......@@ -199,10 +348,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
version: "2.2.2"
shared_preferences_windows:
dependency: transitive
description:
......@@ -216,6 +365,54 @@ packages:
description: flutter
source: sdk
version: "0.0.99"
source_span:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
synchronized:
dependency: transitive
description:
name: synchronized
sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558"
url: "https://pub.dev"
source: hosted
version: "3.1.0+1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.2"
unicons:
dependency: "direct main"
description:
name: unicons
sha256: dbfcf93ff4d4ea19b324113857e358e4882115ab85db04417a4ba1c72b17a670
url: "https://pub.dev"
source: hosted
version: "2.1.1"
vector_math:
dependency: transitive
description:
......@@ -228,18 +425,18 @@ packages:
dependency: transitive
description:
name: web
sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad"
sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05"
url: "https://pub.dev"
source: hosted
version: "0.5.0"
version: "0.4.2"
win32:
dependency: transitive
description:
name: win32
sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
url: "https://pub.dev"
source: hosted
version: "5.2.0"
version: "5.3.0"
xdg_directories:
dependency: transitive
description:
......@@ -250,4 +447,4 @@ packages:
version: "1.0.4"
sdks:
dart: ">=3.3.0 <4.0.0"
flutter: ">=3.19.0"
flutter: ">=3.16.0"
name: solitaire_game
name: solitaire
description: Solitaire Game
publish_to: 'none'
version: 0.0.16+16
version: 0.0.17+17
environment:
sdk: '^3.0.0'
......@@ -9,9 +10,19 @@ environment:
dependencies:
flutter:
sdk: flutter
easy_localization: ^3.0.1
equatable: ^2.0.5
flutter_bloc: ^8.1.1
hive: ^2.2.3
hydrated_bloc: ^9.0.0
overlay_support: ^2.1.0
provider: ^6.0.5
shared_preferences: ^2.2.1
overlay_support: ^2.1.0
package_info_plus: ^5.0.1
path: ^1.9.0
path_provider: ^2.0.11
unicons: ^2.1.1
dev_dependencies:
flutter_lints: ^3.0.1
......@@ -21,3 +32,17 @@ flutter:
assets:
- assets/icons/
- assets/skins/
- assets/translations/
fonts:
- family: Nunito
fonts:
- asset: assets/fonts/Nunito-Bold.ttf
weight: 700
- asset: assets/fonts/Nunito-Medium.ttf
weight: 500
- asset: assets/fonts/Nunito-Regular.ttf
weight: 400
- asset: assets/fonts/Nunito-Light.ttf
weight: 300
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment