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

Merge branch '1-create-initial-empty-application' into 'master'

Resolve "Create initial empty application"

Closes #1

See merge request !1
parents 7955710a cc2eefa6
No related branches found
No related tags found
1 merge request!1Resolve "Create initial empty application"
Pipeline #3283 passed
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 102 102" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect x="1" y="1" width="100" height="100" ry="0" fill="#be6ade" stroke="#000" stroke-width="2"/></svg>
<?xml version="1.0" encoding="UTF-8"?>
<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 100 100" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" ry="2" fill="none"/><rect width="100" height="100" fill="#c5c5c5" stroke="#505050" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.6"/></svg>
// This is a generated file; do not edit or check into version control.
FLUTTER_ROOT=/home/benoit/snap/flutter/common/flutter
FLUTTER_APPLICATION_PATH=/home/benoit/dev/perso/android/org.benoitharrault.solitaire
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_TARGET=lib/main.dart
FLUTTER_BUILD_DIR=build
FLUTTER_BUILD_NAME=1.0.0
FLUTTER_BUILD_NUMBER=1
EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386
DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=false
TREE_SHAKE_ICONS=false
PACKAGE_CONFIG=.dart_tool/package_config.json
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/home/benoit/snap/flutter/common/flutter"
export "FLUTTER_APPLICATION_PATH=/home/benoit/dev/perso/android/org.benoitharrault.solitaire"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_TARGET=lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=false"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.dart_tool/package_config.json"
//
// Generated file. Do not edit.
//
// clang-format off
#ifndef GeneratedPluginRegistrant_h
#define GeneratedPluginRegistrant_h
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface GeneratedPluginRegistrant : NSObject
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry;
@end
NS_ASSUME_NONNULL_END
#endif /* GeneratedPluginRegistrant_h */
//
// Generated file. Do not edit.
//
// clang-format off
#import "GeneratedPluginRegistrant.h"
#if __has_include(<shared_preferences_ios/FLTSharedPreferencesPlugin.h>)
#import <shared_preferences_ios/FLTSharedPreferencesPlugin.h>
#else
@import shared_preferences_ios;
#endif
@implementation GeneratedPluginRegistrant
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
[FLTSharedPreferencesPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTSharedPreferencesPlugin"]];
}
@end
import 'package:flutter/material.dart';
import 'package:solitaire_game/provider/data.dart';
class Board {
static Container buildGameBoard(Data myProvider) {
return Container(
margin: EdgeInsets.all(4),
padding: EdgeInsets.all(4),
child: Column(
children: [
buildGameTileset(myProvider),
],
),
);
}
static Table buildGameTileset(Data myProvider) {
int boardSize = 9;
return Table(
defaultColumnWidth: IntrinsicColumnWidth(),
children: [
for (var row = 0; row < boardSize; row++)
TableRow(
children: [
for (var col = 0; col < boardSize; col++)
Column(
children: [
Text('[' + col.toString() + ',' + row.toString() + "]"),
],
),
],
),
],
);
}
}
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 Container buildGameWidget(Data myProvider) {
bool gameIsFinished = myProvider.isGameFinished;
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: 8),
Game.buildTopIndicatorWidget(myProvider),
SizedBox(height: 2),
Expanded(
child: Board.buildGameBoard(myProvider),
),
SizedBox(height: 2),
Container(
child: gameIsFinished ? Game.buildEndGameMessage(myProvider) : SizedBox(height: 2),
),
],
),
);
}
static Widget buildTopIndicatorWidget(Data myProvider) {
return Table(
children: [
TableRow(
children: [
Column(
children: [
Text(
'SCORE',
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
Text(
'TARGET',
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
color: Colors.grey,
),
),
],
),
Column(
children: [
Text(
'INFOS',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
color: Colors.green,
),
),
],
),
],
),
],
);
}
static TextButton buildQuitGameButton(Data myProvider) {
return TextButton(
child: Container(
child: Image(
image: AssetImage('assets/icons/button_back.png'),
fit: BoxFit.fill,
),
),
onPressed: () => GameUtils.quitGame(myProvider),
);
}
static Container buildEndGameMessage(Data myProvider) {
String decorationImageAssetName = '';
if (myProvider.gameWon()) {
decorationImageAssetName = 'assets/icons/game_win.png';
} else {
decorationImageAssetName = 'assets/icons/game_fail.png';
}
Image decorationImage = Image(
image: AssetImage(decorationImageAssetName),
fit: BoxFit.fill,
);
return Container(
margin: EdgeInsets.all(2),
padding: EdgeInsets.all(2),
child: Table(
defaultColumnWidth: IntrinsicColumnWidth(),
children: [
TableRow(
children: [
Column(
children: [decorationImage],
),
Column(
children: [buildQuitGameButton(myProvider)],
),
Column(
children: [decorationImage],
),
],
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:solitaire_game/provider/data.dart';
import 'package:solitaire_game/utils/game_utils.dart';
class Parameters {
static double separatorHeight = 2.0;
static double blockMargin = 3.0;
static double blockPadding = 2.0;
static Color buttonBackgroundColor = Colors.white;
static Color buttonBorderColorActive = Colors.blue;
static Color buttonBorderColorInactive = Colors.white;
static double buttonBorderWidth = 10.0;
static double buttonBorderRadius = 8.0;
static double buttonPadding = 0.0;
static double buttonMargin = 0.0;
static Container buildParametersSelector(Data myProvider) {
List<Widget> lines = [];
List parameters = myProvider.availableParameters;
for (var index = 0; index < parameters.length; index++) {
lines.add(buildParameterSelector(myProvider, parameters[index]));
lines.add(SizedBox(height: separatorHeight));
}
myProvider.loadCurrentSavedState();
Widget buttonsBlock = myProvider.hasCurrentSavedState()
? buildResumeGameButton(myProvider)
: buildStartNewGameButton(myProvider);
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: separatorHeight),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: lines,
),
),
SizedBox(height: separatorHeight),
Container(
child: buttonsBlock,
),
],
),
);
}
static Image buildImageWidget(String imageAssetCode) {
return Image(
image: AssetImage('assets/icons/' + imageAssetCode + '.png'),
fit: BoxFit.fill,
);
}
static Container buildImageContainerWidget(String imageAssetCode) {
return Container(
child: buildImageWidget(imageAssetCode),
);
}
static Column buildDecorationImageWidget() {
return Column(
children: [
TextButton(
child: buildImageContainerWidget('placeholder'),
onPressed: () => null,
),
],
);
}
static Container buildStartNewGameButton(Data myProvider) {
return Container(
margin: EdgeInsets.all(blockMargin),
padding: EdgeInsets.all(blockPadding),
child: Table(
defaultColumnWidth: IntrinsicColumnWidth(),
children: [
TableRow(
children: [
buildDecorationImageWidget(),
Column(
children: [
TextButton(
child: buildImageContainerWidget('button_start'),
onPressed: () => GameUtils.startNewGame(myProvider),
),
],
),
buildDecorationImageWidget(),
],
),
],
),
);
}
static Container buildResumeGameButton(Data myProvider) {
return Container(
margin: EdgeInsets.all(blockMargin),
padding: EdgeInsets.all(blockPadding),
child: Table(
defaultColumnWidth: IntrinsicColumnWidth(),
children: [
TableRow(
children: [
Column(
children: [
TextButton(
child: buildImageContainerWidget('button_delete_saved_game'),
onPressed: () => GameUtils.deleteSavedGame(myProvider),
),
],
),
Column(
children: [
TextButton(
child: buildImageContainerWidget('button_resume_game'),
onPressed: () => GameUtils.resumeSavedGame(myProvider),
),
],
),
buildDecorationImageWidget(),
],
),
],
),
);
}
static Widget buildParameterSelector(Data myProvider, String parameterCode) {
List availableValues = myProvider.getParameterAvailableValues(parameterCode);
if (availableValues.length == 1) {
return SizedBox(height: 0.0);
}
return Table(
defaultColumnWidth: IntrinsicColumnWidth(),
children: [
TableRow(
children: [
for (var index = 0; index < availableValues.length; index++)
Column(
children: [
_buildParameterButton(myProvider, parameterCode, availableValues[index])
],
),
],
),
],
);
}
static Widget _buildParameterButton(
Data myProvider, String parameterCode, String parameterValue) {
String currentValue = myProvider.getParameterValue(parameterCode).toString();
bool isActive = (parameterValue == currentValue);
String imageAsset = parameterCode + '_' + parameterValue;
return TextButton(
child: Container(
margin: EdgeInsets.all(buttonMargin),
padding: EdgeInsets.all(buttonPadding),
decoration: BoxDecoration(
color: buttonBackgroundColor,
borderRadius: BorderRadius.circular(buttonBorderRadius),
border: Border.all(
color: isActive ? buttonBorderColorActive : buttonBorderColorInactive,
width: buttonBorderWidth,
),
),
child: buildImageWidget(imageAsset),
),
onPressed: () => myProvider.setParameterValue(parameterCode, parameterValue),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:overlay_support/overlay_support.dart';
import 'package:solitaire_game/provider/data.dart';
import 'package:solitaire_game/screens/home.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((value) => runApp(MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (BuildContext context) => Data(),
child: Consumer<Data>(builder: (context, data, child) {
return OverlaySupport(
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Home(),
routes: {
Home.id: (context) => Home(),
},
),
);
}),
);
}
}
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Data extends ChangeNotifier {
// Configuration available values
List _availableParameters = ['skin'];
List _availableSkinValues = ['default'];
List get availableParameters => _availableParameters;
List get availableSkinValues => _availableSkinValues;
// Application default configuration
String _parameterSkin = '';
String _parameterSkinDefault = 'default';
// Application current configuration
String get parameterSkin => _parameterSkin;
// Game data
bool _assetsPreloaded = false;
bool _gameIsRunning = false;
String _currentState = '';
void updateParameterSkin(String parameterSkin) {
_parameterSkin = parameterSkin;
notifyListeners();
}
String getParameterValue(String parameterCode) {
switch (parameterCode) {
case 'skin':
return _parameterSkin;
}
return '';
}
List getParameterAvailableValues(String parameterCode) {
switch (parameterCode) {
case 'skin':
return _availableSkinValues;
}
return [];
}
void setParameterValue(String parameterCode, String parameterValue) async {
switch (parameterCode) {
case 'skin':
updateParameterSkin(parameterValue);
break;
}
final prefs = await SharedPreferences.getInstance();
prefs.setString(parameterCode, parameterValue);
}
void initParametersValues() async {
final prefs = await SharedPreferences.getInstance();
setParameterValue('skin', prefs.getString('skin') ?? _parameterSkinDefault);
}
String get currentState => _currentState;
String computeCurrentGameState() {
var currentState = {
'skin': _parameterSkin,
};
return json.encode(currentState);
}
void saveCurrentGameState() async {
if (_gameIsRunning) {
_currentState = computeCurrentGameState();
final prefs = await SharedPreferences.getInstance();
prefs.setString('savedState', _currentState);
} else {
resetCurrentSavedState();
}
}
void resetCurrentSavedState() async {
_currentState = '';
final prefs = await SharedPreferences.getInstance();
prefs.setString('savedState', _currentState);
notifyListeners();
}
void loadCurrentSavedState() async {
final prefs = await SharedPreferences.getInstance();
_currentState = prefs.getString('savedState') ?? '';
}
bool hasCurrentSavedState() {
return (_currentState != '');
}
Map<String, dynamic> getCurrentSavedState() {
if (_currentState != '') {
Map<String, dynamic> savedState = json.decode(_currentState);
if (savedState.isNotEmpty) {
return savedState;
}
}
return {};
}
bool get assetsPreloaded => _assetsPreloaded;
void updateAssetsPreloaded(bool assetsPreloaded) {
_assetsPreloaded = assetsPreloaded;
}
bool get gameIsRunning => _gameIsRunning;
bool get isGameFinished => !_gameIsRunning;
void updateGameIsRunning(bool gameIsRunning) {
_gameIsRunning = gameIsRunning;
notifyListeners();
}
bool gameWon() {
return isGameFinished;
}
void resetGame() {
_gameIsRunning = false;
notifyListeners();
}
}
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 {
static const String id = 'home';
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
@override
void initState() {
super.initState();
Data myProvider = Provider.of<Data>(context, listen: false);
myProvider.initParametersValues();
myProvider.loadCurrentSavedState();
}
List getImagesAssets(Data myProvider) {
List assets = [];
List gameImages = [
'button_back',
'button_delete_saved_game',
'button_resume_game',
'button_start',
'game_fail',
'game_win',
'placeholder',
];
myProvider.availableSkinValues.forEach((skin) => gameImages.add('skin_' + skin));
gameImages.forEach((image) => assets.add('assets/icons/' + image + '.png'));
List skinImages = [
'empty',
];
myProvider.availableSkinValues.forEach((skin) => skinImages
.forEach((image) => assets.add('assets/skins/' + skin + '_' + image + '.png')));
return assets;
}
@override
Widget build(BuildContext context) {
Data myProvider = Provider.of<Data>(context);
if (!myProvider.assetsPreloaded) {
List assets = getImagesAssets(myProvider);
assets.forEach((asset) => precacheImage(AssetImage(asset), context));
myProvider.updateAssetsPreloaded(true);
}
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: 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),
),
),
);
}
}
import 'package:solitaire_game/provider/data.dart';
class GameUtils {
static Future<void> quitGame(Data myProvider) async {
myProvider.updateGameIsRunning(false);
}
static Future<void> startNewGame(Data myProvider) async {
print('Starting game');
myProvider.resetGame();
myProvider.updateGameIsRunning(true);
}
static void deleteSavedGame(Data myProvider) {
myProvider.resetCurrentSavedState();
}
static void resumeSavedGame(Data myProvider) {
Map<String, dynamic> savedState = myProvider.getCurrentSavedState();
if (savedState.isNotEmpty) {
try {
myProvider.setParameterValue('skin', savedState['skin']);
myProvider.updateGameIsRunning(true);
} catch (e) {
print('Failed to resume game. Will start new one instead.');
myProvider.resetCurrentSavedState();
myProvider.initParametersValues();
startNewGame(myProvider);
}
} else {
myProvider.resetCurrentSavedState();
myProvider.initParametersValues();
startNewGame(myProvider);
}
}
}
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.2"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.16.0"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.4"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
js:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.4"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.11"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.4"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
nested:
dependency: transitive
description:
name: nested
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
overlay_support:
dependency: "direct main"
description:
name: overlay_support
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.7"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
process:
dependency: transitive
description:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.2.4"
provider:
dependency: "direct main"
description:
name: provider
url: "https://pub.dartlang.org"
source: hosted
version: "6.0.3"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.15"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.12"
shared_preferences_ios:
dependency: transitive
description:
name: shared_preferences_ios
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
shared_preferences_macos:
dependency: transitive
description:
name: shared_preferences_macos
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.4"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
source_span:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.2"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
source: hosted
version: "1.10.0"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.9"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.2"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "2.7.0"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0+1"
sdks:
dart: ">=2.17.0 <3.0.0"
flutter: ">=3.0.0"
name: solitaire_game
description: Solitaire Game
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: ">=2.16.1 <3.0.0"
dependencies:
flutter:
sdk: flutter
provider: ^6.0.2
shared_preferences: ^2.0.6
overlay_support: ^2.0.1
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
assets:
- assets/icons/
- assets/skins/
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment