Storing stats done
continuous-integration/drone/push Build is passing Details

ContinueLocalManager
Emre KARTAL 2 years ago
parent b4b031f7dd
commit af233c821b

@ -0,0 +1,10 @@
class GameFields {
static final List<String> values = [
id, date, pointsCurrentUser, userId
];
static final String id = '_id';
static final String date = '_date';
static final String pointsCurrentUser = '_points_current_user';
static final String userId = '_user_id';
}

@ -1,4 +1,16 @@
class StatFields { class StatFields {
static final List<String> values = [
idUser, nbVictory, nbGames, highscore, nbStrikes, nbSpares, nbScore, avgScore, avgPinsPerRound
];
static final String nbVictory = '_nbVictory';
static final String nbGames = '_nbGames';
static final String highscore = '_highscore';
static final String nbStrikes = '_nbStrikes';
static final String nbSpares = '_nbSpares';
static final String nbScore = '_nbScore';
static final String avgScore = '_avgScore';
static final String avgPinsPerRound = '_avgPinsPerRound';
static final String idUser = '_idUser';
} }

@ -0,0 +1,32 @@
import 'package:bowl_in/database/fields/StatFields.dart';
import '../../model/Stat.dart';
import '../../model/User.dart';
class StatMapper {
static Map<String, dynamic> toJson(Stat stat, User user) {
return {
StatFields.idUser: user.id,
StatFields.nbVictory: stat.nbVictory,
StatFields.nbGames: stat.nbGames,
StatFields.highscore: stat.highscore,
StatFields.nbStrikes: stat.nbStrikes,
StatFields.nbSpares: stat.nbSpares,
StatFields.nbScore: stat.nbScore,
StatFields.avgScore: stat.avgScore,
StatFields.avgPinsPerRound: stat.avgPinsPerRound
};
}
static Stat toModel(Map<String, dynamic> json) {
return Stat(
json[StatFields.nbVictory],
json[StatFields.nbGames],
json[StatFields.highscore],
json[StatFields.nbStrikes],
json[StatFields.nbSpares],
json[StatFields.nbScore],
json[StatFields.avgScore],
json[StatFields.avgPinsPerRound]
);
}
}

@ -1,3 +1,4 @@
import '../../model/Stat.dart';
import '../../model/User.dart'; import '../../model/User.dart';
import '../fields/UserFields.dart'; import '../fields/UserFields.dart';
@ -11,14 +12,15 @@ class UserMapper {
}; };
} }
static User toModel(Map<String, dynamic> json) { static User toModel(Map<String, dynamic> json, Stat stat) {
return User( return User.withStat(
json[UserFields.id], json[UserFields.id],
json[UserFields.name], json[UserFields.name],
json[UserFields.image], json[UserFields.image],
json[UserFields.mail], json[UserFields.mail],
[], [],
[], [],
stat
); );
} }
} }

@ -0,0 +1,251 @@
import 'package:bowl_in/database/mappers/GameMapper.dart';
import 'package:bowl_in/database/mappers/StatMapper.dart';
import 'package:bowl_in/model/Game.dart';
import 'package:bowl_in/model/User.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import '../../model/Stat.dart';
import '../fields/GameDetailFields.dart';
import '../fields/GameFields.dart';
import '../fields/StatFields.dart';
import '../fields/UserFields.dart';
import '../mappers/UserMapper.dart';
class BowlInDatabase {
BowlInDatabase();
static final BowlInDatabase instance = BowlInDatabase._init();
static Database? _database;
BowlInDatabase._init();
static const String tableUser = 'users';
static const String tableGame = 'games';
static const String tableGameDetail = 'gameDetails';
static const String tableStat = 'stats';
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDB('user.db');
return _database!;
}
Future<Database> _initDB(String filePath) async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, filePath);
return await openDatabase(path,
version: 1, onCreate: _createDB, onUpgrade: _upgradeDB);
}
Future _createDB(Database db, int version) async {
const idType = 'INTEGER PRIMARY KEY AUTOINCREMENT';
const textType = 'TEXT NOT NULL';
const boolType = 'BOOLEAN NOT NULL';
const integerType = 'INTEGER NOT NULL';
const realType = 'REAL NOT NULL';
await db.execute('''
CREATE TABLE $tableUser (
${UserFields.id} $idType,
${UserFields.name} $boolType,
${UserFields.image} $textType,
${UserFields.mail} $textType
)
''');
await db.execute('''
CREATE TABLE $tableGame (
${GameFields.id} $idType,
${GameFields.date} $textType,
${GameFields.pointsCurrentUser} $integerType,
${GameFields.userId} $integerType,
FOREIGN KEY(${GameFields.userId}) REFERENCES $tableUser(${UserFields.id})
)
''');
await db.execute('''
CREATE TABLE $tableGameDetail (
${GameDetailFields.id} $idType,
${GameDetailFields.date} $textType,
${GameDetailFields.nameWinner} $textType,
${GameDetailFields.host} $textType
)
''');
await db.execute('''
CREATE TABLE $tableStat (
${StatFields.idUser} $integerType,
${StatFields.nbVictory} $integerType,
${StatFields.nbGames} $integerType,
${StatFields.highscore} $integerType,
${StatFields.nbStrikes} $integerType,
${StatFields.nbSpares} $integerType,
${StatFields.nbScore} $integerType,
${StatFields.avgScore} $realType,
${StatFields.avgPinsPerRound} $realType,
FOREIGN KEY(${StatFields.idUser}) REFERENCES $tableUser(${UserFields.id})
)
''');
}
Future<void> _upgradeDB(Database db, int oldVersion, int newVersion) async {
if (oldVersion == 5) {
await db.execute('DROP TABLE IF EXISTS $tableUser');
await db.execute('DROP TABLE IF EXISTS $tableGame');
await db.execute('DROP TABLE IF EXISTS $tableGameDetail');
await db.execute('DROP TABLE IF EXISTS $tableStat');
await _createDB(db, newVersion);
}
}
// User
Future<void> createUser(User user) async {
final db = await instance.database;
await db.insert(tableUser, UserMapper.toJson(user));
await createStat(user);
}
Future<User?> readUser(int id) async {
final db = await instance.database;
final result = await db
.query(tableUser, where: '${UserFields.id} = ?', whereArgs: [id]);
if (result.isNotEmpty) {
final stat = await readStat(id);
User user;
if (stat != null) {
user = UserMapper.toModel(result.first, stat);
}
else {
user = UserMapper.toModel(result.first, Stat.empty());
}
//final games = await readGame(id);
//for (var game in games!) {
//user.games.add(game);
//}
return user;
} else {
return null;
}
}
Future<void> updateUser(User user) async {
final db = await instance.database;
await db.transaction((txn) async {
await txn.update(tableUser, UserMapper.toJson(user),
where: '${UserFields.id} = ?', whereArgs: [user.id]);
await txn.update(tableStat, StatMapper.toJson(user.stat, user),
where: '${StatFields.idUser} = ?', whereArgs: [user.id]);
// Insert new games for the user
//await createGame(user);
});
}
Future<int> deleteUser(int id) async {
final db = await instance.database;
await deleteGame(id);
await deleteStat(id);
return await db.delete(
tableUser,
where: '${UserFields.id} = ?',
whereArgs: [id],
);
}
// GameDetail
// Game
Future<void> createGame(User user) async {
final db = await instance.database;
await db.transaction((txn) async {
for (var game in user.games) {
await txn.insert(tableGame, GameMapper.toJson(game, user));
}
});
}
Future<List<Game>?> readGame(int id) async {
final db = await instance.database;
final result = await db.query(tableGame,
where: '${GameFields.userId} = ?', whereArgs: [id]);
if (result.isNotEmpty) {
List<Game> games = [];
for (var game in result) {
games.add(GameMapper.toModel(game));
}
return games;
} else {
return null;
}
}
Future<int> deleteGame(int id) async {
final db = await instance.database;
return await db.delete(
tableGame,
where: '${GameFields.userId} = ?',
whereArgs: [id],
);
}
// Stat
Future<void> createStat(User user) async {
final db = await instance.database;
await db.insert(tableStat, StatMapper.toJson(Stat.empty(), user));
}
Future<Stat?> readStat(int id) async {
final db = await instance.database;
final result = await db.query(tableStat,
where: '${StatFields.idUser} = ?', whereArgs: [id]);
if (result.isNotEmpty) {
Stat stat = StatMapper.toModel(result.first);
return stat;
} else {
return null;
}
}
Future<void> updateStat(User user) async {
final db = await instance.database;
await db.transaction((txn) async {
await txn.update(tableStat, StatMapper.toJson(user.stat, user),
where: '${StatFields.idUser} = ?', whereArgs: [user.id]);
});
}
Future<int> deleteStat(int id) async {
final db = await instance.database;
return await db.delete(
tableStat,
where: '${StatFields.idUser} = ?',
whereArgs: [id],
);
}
Future close() async {
final db = await instance.database;
db.close();
}
}

@ -1,135 +0,0 @@
import 'package:bowl_in/database/mappers/GameMapper.dart';
import 'package:bowl_in/model/User.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import '../fields/GameDetailFields.dart';
import '../fields/GameFields.dart';
import '../fields/UserFields.dart';
import '../mappers/UserMapper.dart';
class BowlInDatabase {
BowlInDatabase();
static final BowlInDatabase instance = BowlInDatabase._init();
static Database? _database;
BowlInDatabase._init();
static const String tableUser = 'users';
static const String tableGame = 'games';
static const String tableGameDetail = 'gameDetails';
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDB('user.db');
return _database!;
}
Future<Database> _initDB(String filePath) async {
final dbPath = await getDatabasesPath();
final path = join(dbPath, filePath);
return await openDatabase(path, version: 4, onCreate: _createDB, onUpgrade: _upgradeDB);
}
Future _createDB(Database db, int version) async {
const idType = 'INTEGER PRIMARY KEY AUTOINCREMENT';
const textType = 'TEXT NOT NULL';
const boolType = 'BOOLEAN NOT NULL';
final integerType = 'INTEGER NOT NULL';
await db.execute('''
CREATE TABLE $tableUser (
${UserFields.id} $idType,
${UserFields.name} $boolType,
${UserFields.image} $textType,
${UserFields.mail} $textType
)
''');
await db.execute('''
CREATE TABLE $tableGame (
${GameFields.id} $idType,
${GameFields.date} $textType,
${GameFields.pointsCurrentUser} $integerType,
${GameFields.userId} $integerType,
FOREIGN KEY(${GameFields.userId}) REFERENCES $tableUser(${UserFields.id})
)
''');
await db.execute('''
CREATE TABLE $tableGameDetail (
${GameDetailFields.id} $idType,
${GameDetailFields.date} $textType,
${GameDetailFields.nameWinner} $textType,
${GameDetailFields.host} $textType,
)
''');
}
Future<void> _upgradeDB(Database db, int oldVersion, int newVersion) async {
if (oldVersion < 4) {
await db.execute('DROP TABLE IF EXISTS $tableUser');
await db.execute('DROP TABLE IF EXISTS $tableGame');
await db.execute('DROP TABLE IF EXISTS $tableGameDetail');
await _createDB(db, newVersion);
}
}
Future<void> createUser(User user) async {
final db = await instance.database;
await db.insert(tableUser, UserMapper.toJson(user));
}
Future<User?> readUser(int id) async {
final db = await instance.database;
final result = await db
.query(tableUser, where: '${UserFields.id} = ?', whereArgs: [id]);
if (result.isNotEmpty) {
User user = UserMapper.toModel(result.first);
final games = await db
.query(tableGame, where: '${GameFields.userId} = ?', whereArgs: [user.id]);
for (var game in games) {
user.games.add(GameMapper.toModel(game));
}
return user;
}
else {
return null;
}
}
Future<void> updateUser(User user) async {
final db = await instance.database;
await db.transaction((txn) async {
await txn.update(tableUser, UserMapper.toJson(user),
where: '${UserFields.id} = ?', whereArgs: [user.id]);
// Insert new games for the user
for (var game in user.games) {
await txn.insert(tableGame, GameMapper.toJson(game, user));
}
});
}
Future<int> deleteUser(int id) async {
final db = await instance.database;
return await db.delete(
tableUser,
where: '${UserFields.id} = ?',
whereArgs: [id],
);
}
Future close() async {
final db = await instance.database;
db.close();
}
}

@ -1,5 +1,4 @@
import 'package:bowl_in/model/LocalManager/LocalData.dart'; import 'package:bowl_in/model/LocalManager/LocalData.dart';
import 'package:bowl_in/model/StubManager/StubData.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:bowl_in/config/app_router.dart'; import 'package:bowl_in/config/app_router.dart';
@ -11,7 +10,7 @@ void main() {
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
static IManager controller = StubData(); static IManager controller = LocalData();
const MyApp({super.key}); const MyApp({super.key});

@ -40,6 +40,7 @@ class GamePlayer {
_parent.gameMgr.addGame(game); _parent.gameMgr.addGame(game);
game.computeScores(); game.computeScores();
_parent.userMgr.saveUser(_parent.userCurrent);
context?.go("/scoreboard", extra: game); context?.go("/scoreboard", extra: game);
} else { } else {
print("IN GAME : " + currentRoundIndex.toString()); print("IN GAME : " + currentRoundIndex.toString());

@ -12,5 +12,6 @@ abstract class IUserManager {
IAuthManager get authMgr => _authMgr; IAuthManager get authMgr => _authMgr;
List<Player> getUsersByName(String name); List<Player> getUsersByName(String name);
Player getUserById(int id); Player getUserById(int id);
saveUser(User user);
List<User> getRankingWithFriends(); List<User> getRankingWithFriends();
} }

@ -3,57 +3,89 @@ import 'package:bowl_in/model/IGameManager.dart';
import 'package:bowl_in/model/LocalManager/LocalData.dart'; import 'package:bowl_in/model/LocalManager/LocalData.dart';
import 'package:bowl_in/model/Player.dart'; import 'package:bowl_in/model/Player.dart';
import '../User.dart';
class GameManager extends IGameManager { class GameManager extends IGameManager {
final LocalData parent; final LocalData parent;
// Constructor // Constructor
GameManager(this.parent); GameManager(this.parent);
@override // Methods
addGame(GameDetail gd) { GameDetail getGameById(int id) {
// TODO: implement addGame for (var element in parent.gameDetails) {
throw UnimplementedError(); if (element.id == id) {
return element;
}
}
throw Exception("Game not found.");
} }
@override List<GameDetail> getGamesByPlayerId(int id) {
GameDetail getGameById(int id) { List<GameDetail> games = [];
// TODO: implement getGameById for (var element in parent.gameDetails) {
throw UnimplementedError(); for (Player player in element.players) {
if (player is User && player.id == id) {
games.add(element);
break;
}
}
}
return games;
} }
@override
List<GameDetail> getGamesByPlayer(Player user) { List<GameDetail> getGamesByPlayer(Player user) {
// TODO: implement getGamesByPlayer List<GameDetail> games = [];
throw UnimplementedError(); for (var element in parent.gameDetails) {
for (Player player in element.players) {
if (player is User && user is User && player.id == user.id) {
games.add(element);
break;
}
}
}
return games;
} }
@override List<GameDetail> getGamesByPlayers(List<Player> users) {
List<GameDetail> getGamesByPlayerId(int id) { List<GameDetail> games = [];
// TODO: implement getGamesByPlayerId for (var element in parent.gameDetails) {
throw UnimplementedError(); if (element.players.toSet().containsAll(users.toSet())) {
games.add(element);
}
}
return games;
} }
@override List<Player> getPlayersByIdGame(int id) {
List<GameDetail> getGamesByPlayers(List<Player> users) { List<Player> players = [];
// TODO: implement getGamesByPlayers for (var element in parent.gameDetails) {
throw UnimplementedError(); if (element.id == id) {
for (var player in element.players) {
players.add(player);
}
return players;
}
}
throw Exception("Game not found.");
} }
@override Map<Player, int> getRankByIdGame(int id) {
int getNextId() { for (var game in parent.gameDetails) {
// TODO: implement getNextId if (game.id == id) {
throw UnimplementedError(); return game.getRank();
}
}
throw Exception("Game not found.");
} }
@override @override
List<Player> getPlayersByIdGame(int id) { addGame(GameDetail gd) {
// TODO: implement getPlayersByIdGame parent.gameDetails.add(gd);
throw UnimplementedError();
} }
@override @override
Map<Player, int> getRankByIdGame(int id) { int getNextId() {
// TODO: implement getRankByIdGame return parent.gameDetails.length;
throw UnimplementedError();
} }
} }

@ -1,13 +1,19 @@
import 'package:bowl_in/database/sqlflite/UserDataBase.dart'; import 'package:bowl_in/database/sqlflite/BowlInDatabase.dart';
import 'package:bowl_in/model/IManager.dart'; import 'package:bowl_in/model/IManager.dart';
import '../GameDetail.dart';
import 'GameManager.dart'; import 'GameManager.dart';
import 'UserManager.dart'; import 'UserManager.dart';
class LocalData extends IManager { class LocalData extends IManager {
final BowlInDatabase userDatabase = BowlInDatabase(); final BowlInDatabase database = BowlInDatabase();
LocalData() { LocalData() {
userMgr = UserManager(this); userMgr = UserManager(this);
gameMgr = GameManager(this); gameMgr = GameManager(this);
} }
List<GameDetail> _gameDetails = [];
List<GameDetail> get gameDetails => _gameDetails;
} }

@ -2,7 +2,6 @@ import 'package:bowl_in/model/IUserManager.dart';
import 'package:bowl_in/model/LocalManager/LocalData.dart'; import 'package:bowl_in/model/LocalManager/LocalData.dart';
import 'package:bowl_in/model/Player.dart'; import 'package:bowl_in/model/Player.dart';
import 'package:bowl_in/model/User.dart'; import 'package:bowl_in/model/User.dart';
import '../Game.dart';
import 'AuthManager.dart'; import 'AuthManager.dart';
class UserManager extends IUserManager { class UserManager extends IUserManager {
@ -10,14 +9,15 @@ class UserManager extends IUserManager {
// Constructor // Constructor
UserManager(this.parent) : super(AuthManager(parent)) { UserManager(this.parent) : super(AuthManager(parent)) {
User user = User(0, "Dave", "./assets/images/image_user_red.png", "", [], []); //User user = User(0, "Victor", "./assets/images/image_user_red.png", "", [], []);
user.games.add(Game(0,DateTime.now(), 30, [])); //saveUser(user);
saveUser(user); //parent.database.deleteUser(0);
//test();
_initUser(); _initUser();
} }
_initUser() async { _initUser() async {
var user = await parent.userDatabase.readUser(0); var user = await parent.database.readUser(0);
if (user == null) { if (user == null) {
User user2 = User user2 =
User(1, "Unknown", "./assets/images/image_user_cyan.png", "", [], []); User(1, "Unknown", "./assets/images/image_user_cyan.png", "", [], []);
@ -27,8 +27,13 @@ class UserManager extends IUserManager {
} }
} }
saveUser(User user) { saveUser(User user) async {
parent.userDatabase.updateUser(user); var result = await parent.database.readUser(0);
if (result == null) {
await parent.database.createUser(user);
} else {
await parent.database.updateUser(user);
}
} }
Map<String, dynamic> userToMap(User user) { Map<String, dynamic> userToMap(User user) {
@ -42,8 +47,9 @@ class UserManager extends IUserManager {
@override @override
List<User> getRankingWithFriends() { List<User> getRankingWithFriends() {
// TODO: implement getRankingWithFriends List<User> sortedPlayers = List.from(parent.userCurrent.friends);
throw UnimplementedError(); sortedPlayers.sort((a, b) => b.stat.highscore.compareTo(a.stat.highscore));
return sortedPlayers;
} }
@override @override

@ -11,6 +11,7 @@ import 'UserManager.dart';
import 'GameManager.dart'; import 'GameManager.dart';
class StubData extends IManager { class StubData extends IManager {
StubData() { StubData() {
userMgr = UserManager(this); userMgr = UserManager(this);
gameMgr = GameManager(this); gameMgr = GameManager(this);

@ -38,4 +38,9 @@ class UserManager extends IUserManager {
sortedPlayers.sort((a, b) => b.stat.highscore.compareTo(a.stat.highscore)); sortedPlayers.sort((a, b) => b.stat.highscore.compareTo(a.stat.highscore));
return sortedPlayers; return sortedPlayers;
} }
@override
saveUser(User user) {
return ;
}
} }

@ -8,12 +8,18 @@ class User extends Player {
String _mail; String _mail;
List<Achievement> _achievements = <Achievement>[]; List<Achievement> _achievements = <Achievement>[];
List<User> _friends = <User>[]; List<User> _friends = <User>[];
final Stat _stat = Stat.empty(); late final Stat _stat;
List<Game> games = []; List<Game> games = [];
// Constructor // Constructor
User(this._id, String name, String image, this._mail, this._achievements, User(this._id, String name, String image, this._mail, this._achievements,
this._friends) this._friends)
: super(name, image){
_stat = Stat.empty();
}
User.withStat(this._id, String name, String image, this._mail, this._achievements,
this._friends, this._stat)
: super(name, image); : super(name, image);
int get id => _id; int get id => _id;

Loading…
Cancel
Save