Compare commits
10 Commits
07d623d963
...
82e28b7509
| Author | SHA1 | Date | |
|---|---|---|---|
| 82e28b7509 | |||
| f2a749cb0f | |||
| 5dcd0826bd | |||
| f6ebda7984 | |||
| 69c95ca672 | |||
| 42ce69f4d3 | |||
| 08fcaa35ee | |||
| fd86f5193f | |||
| 2da2e28cb6 | |||
| d86de09042 |
137
assets/schema.json
Normal file
137
assets/schema.json
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"games": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"players": {
|
||||||
|
"type": "null"
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"type": "null"
|
||||||
|
},
|
||||||
|
"winner": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"players",
|
||||||
|
"group",
|
||||||
|
"winner"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"groups": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"members": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"members"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"players": {
|
||||||
|
"type": "array",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"name"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"games",
|
||||||
|
"groups",
|
||||||
|
"players"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
|
|||||||
GameTableCompanion.insert(
|
GameTableCompanion.insert(
|
||||||
id: game.id,
|
id: game.id,
|
||||||
name: game.name,
|
name: game.name,
|
||||||
winnerId: game.winner,
|
winnerId: Value(game.winner),
|
||||||
),
|
),
|
||||||
mode: InsertMode.insertOrReplace,
|
mode: InsertMode.insertOrReplace,
|
||||||
);
|
);
|
||||||
@@ -88,4 +88,12 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
|
|||||||
final result = await query.getSingleOrNull();
|
final result = await query.getSingleOrNull();
|
||||||
return result != null;
|
return result != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deletes all games from the database.
|
||||||
|
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
||||||
|
Future<bool> deleteAllGames() async {
|
||||||
|
final query = delete(gameTable);
|
||||||
|
final rowsAffected = await query.go();
|
||||||
|
return rowsAffected > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,5 @@ part of 'game_dao.dart';
|
|||||||
|
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
mixin _$GameDaoMixin on DatabaseAccessor<AppDatabase> {
|
mixin _$GameDaoMixin on DatabaseAccessor<AppDatabase> {
|
||||||
$PlayerTableTable get playerTable => attachedDatabase.playerTable;
|
|
||||||
$GameTableTable get gameTable => attachedDatabase.gameTable;
|
$GameTableTable get gameTable => attachedDatabase.gameTable;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,4 +103,12 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
|
|||||||
final result = await query.getSingleOrNull();
|
final result = await query.getSingleOrNull();
|
||||||
return result != null;
|
return result != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deletes all groups from the database.
|
||||||
|
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
||||||
|
Future<bool> deleteAllGroups() async {
|
||||||
|
final query = delete(groupTable);
|
||||||
|
final rowsAffected = await query.go();
|
||||||
|
return rowsAffected > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ part of 'group_game_dao.dart';
|
|||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
mixin _$GroupGameDaoMixin on DatabaseAccessor<AppDatabase> {
|
mixin _$GroupGameDaoMixin on DatabaseAccessor<AppDatabase> {
|
||||||
$GroupTableTable get groupTable => attachedDatabase.groupTable;
|
$GroupTableTable get groupTable => attachedDatabase.groupTable;
|
||||||
$PlayerTableTable get playerTable => attachedDatabase.playerTable;
|
|
||||||
$GameTableTable get gameTable => attachedDatabase.gameTable;
|
$GameTableTable get gameTable => attachedDatabase.gameTable;
|
||||||
$GroupGameTableTable get groupGameTable => attachedDatabase.groupGameTable;
|
$GroupGameTableTable get groupGameTable => attachedDatabase.groupGameTable;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,4 +70,12 @@ class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
|
|||||||
.getSingle();
|
.getSingle();
|
||||||
return count ?? 0;
|
return count ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deletes all players from the database.
|
||||||
|
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
||||||
|
Future<bool> deleteAllPlayers() async {
|
||||||
|
final query = delete(playerTable);
|
||||||
|
final rowsAffected = await query.go();
|
||||||
|
return rowsAffected > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,15 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
@override
|
@override
|
||||||
int get schemaVersion => 1;
|
int get schemaVersion => 1;
|
||||||
|
|
||||||
|
@override
|
||||||
|
MigrationStrategy get migration {
|
||||||
|
return MigrationStrategy(
|
||||||
|
beforeOpen: (details) async {
|
||||||
|
await customStatement('PRAGMA foreign_keys = ON');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static QueryExecutor _openConnection() {
|
static QueryExecutor _openConnection() {
|
||||||
return driftDatabase(
|
return driftDatabase(
|
||||||
name: 'gametracker_db',
|
name: 'gametracker_db',
|
||||||
|
|||||||
@@ -444,12 +444,9 @@ class $GameTableTable extends GameTable
|
|||||||
late final GeneratedColumn<String> winnerId = GeneratedColumn<String>(
|
late final GeneratedColumn<String> winnerId = GeneratedColumn<String>(
|
||||||
'winner_id',
|
'winner_id',
|
||||||
aliasedName,
|
aliasedName,
|
||||||
false,
|
true,
|
||||||
type: DriftSqlType.string,
|
type: DriftSqlType.string,
|
||||||
requiredDuringInsert: true,
|
requiredDuringInsert: false,
|
||||||
defaultConstraints: GeneratedColumn.constraintIsAlways(
|
|
||||||
'REFERENCES player_table (id) ON DELETE CASCADE',
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
List<GeneratedColumn> get $columns => [id, name, winnerId];
|
List<GeneratedColumn> get $columns => [id, name, winnerId];
|
||||||
@@ -483,8 +480,6 @@ class $GameTableTable extends GameTable
|
|||||||
_winnerIdMeta,
|
_winnerIdMeta,
|
||||||
winnerId.isAcceptableOrUnknown(data['winner_id']!, _winnerIdMeta),
|
winnerId.isAcceptableOrUnknown(data['winner_id']!, _winnerIdMeta),
|
||||||
);
|
);
|
||||||
} else if (isInserting) {
|
|
||||||
context.missing(_winnerIdMeta);
|
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
@@ -506,7 +501,7 @@ class $GameTableTable extends GameTable
|
|||||||
winnerId: attachedDatabase.typeMapping.read(
|
winnerId: attachedDatabase.typeMapping.read(
|
||||||
DriftSqlType.string,
|
DriftSqlType.string,
|
||||||
data['${effectivePrefix}winner_id'],
|
data['${effectivePrefix}winner_id'],
|
||||||
)!,
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -519,18 +514,16 @@ class $GameTableTable extends GameTable
|
|||||||
class GameTableData extends DataClass implements Insertable<GameTableData> {
|
class GameTableData extends DataClass implements Insertable<GameTableData> {
|
||||||
final String id;
|
final String id;
|
||||||
final String name;
|
final String name;
|
||||||
final String winnerId;
|
final String? winnerId;
|
||||||
const GameTableData({
|
const GameTableData({required this.id, required this.name, this.winnerId});
|
||||||
required this.id,
|
|
||||||
required this.name,
|
|
||||||
required this.winnerId,
|
|
||||||
});
|
|
||||||
@override
|
@override
|
||||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||||
final map = <String, Expression>{};
|
final map = <String, Expression>{};
|
||||||
map['id'] = Variable<String>(id);
|
map['id'] = Variable<String>(id);
|
||||||
map['name'] = Variable<String>(name);
|
map['name'] = Variable<String>(name);
|
||||||
map['winner_id'] = Variable<String>(winnerId);
|
if (!nullToAbsent || winnerId != null) {
|
||||||
|
map['winner_id'] = Variable<String>(winnerId);
|
||||||
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,7 +531,9 @@ class GameTableData extends DataClass implements Insertable<GameTableData> {
|
|||||||
return GameTableCompanion(
|
return GameTableCompanion(
|
||||||
id: Value(id),
|
id: Value(id),
|
||||||
name: Value(name),
|
name: Value(name),
|
||||||
winnerId: Value(winnerId),
|
winnerId: winnerId == null && nullToAbsent
|
||||||
|
? const Value.absent()
|
||||||
|
: Value(winnerId),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -550,7 +545,7 @@ class GameTableData extends DataClass implements Insertable<GameTableData> {
|
|||||||
return GameTableData(
|
return GameTableData(
|
||||||
id: serializer.fromJson<String>(json['id']),
|
id: serializer.fromJson<String>(json['id']),
|
||||||
name: serializer.fromJson<String>(json['name']),
|
name: serializer.fromJson<String>(json['name']),
|
||||||
winnerId: serializer.fromJson<String>(json['winnerId']),
|
winnerId: serializer.fromJson<String?>(json['winnerId']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@override
|
@override
|
||||||
@@ -559,16 +554,19 @@ class GameTableData extends DataClass implements Insertable<GameTableData> {
|
|||||||
return <String, dynamic>{
|
return <String, dynamic>{
|
||||||
'id': serializer.toJson<String>(id),
|
'id': serializer.toJson<String>(id),
|
||||||
'name': serializer.toJson<String>(name),
|
'name': serializer.toJson<String>(name),
|
||||||
'winnerId': serializer.toJson<String>(winnerId),
|
'winnerId': serializer.toJson<String?>(winnerId),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
GameTableData copyWith({String? id, String? name, String? winnerId}) =>
|
GameTableData copyWith({
|
||||||
GameTableData(
|
String? id,
|
||||||
id: id ?? this.id,
|
String? name,
|
||||||
name: name ?? this.name,
|
Value<String?> winnerId = const Value.absent(),
|
||||||
winnerId: winnerId ?? this.winnerId,
|
}) => GameTableData(
|
||||||
);
|
id: id ?? this.id,
|
||||||
|
name: name ?? this.name,
|
||||||
|
winnerId: winnerId.present ? winnerId.value : this.winnerId,
|
||||||
|
);
|
||||||
GameTableData copyWithCompanion(GameTableCompanion data) {
|
GameTableData copyWithCompanion(GameTableCompanion data) {
|
||||||
return GameTableData(
|
return GameTableData(
|
||||||
id: data.id.present ? data.id.value : this.id,
|
id: data.id.present ? data.id.value : this.id,
|
||||||
@@ -601,7 +599,7 @@ class GameTableData extends DataClass implements Insertable<GameTableData> {
|
|||||||
class GameTableCompanion extends UpdateCompanion<GameTableData> {
|
class GameTableCompanion extends UpdateCompanion<GameTableData> {
|
||||||
final Value<String> id;
|
final Value<String> id;
|
||||||
final Value<String> name;
|
final Value<String> name;
|
||||||
final Value<String> winnerId;
|
final Value<String?> winnerId;
|
||||||
final Value<int> rowid;
|
final Value<int> rowid;
|
||||||
const GameTableCompanion({
|
const GameTableCompanion({
|
||||||
this.id = const Value.absent(),
|
this.id = const Value.absent(),
|
||||||
@@ -612,11 +610,10 @@ class GameTableCompanion extends UpdateCompanion<GameTableData> {
|
|||||||
GameTableCompanion.insert({
|
GameTableCompanion.insert({
|
||||||
required String id,
|
required String id,
|
||||||
required String name,
|
required String name,
|
||||||
required String winnerId,
|
this.winnerId = const Value.absent(),
|
||||||
this.rowid = const Value.absent(),
|
this.rowid = const Value.absent(),
|
||||||
}) : id = Value(id),
|
}) : id = Value(id),
|
||||||
name = Value(name),
|
name = Value(name);
|
||||||
winnerId = Value(winnerId);
|
|
||||||
static Insertable<GameTableData> custom({
|
static Insertable<GameTableData> custom({
|
||||||
Expression<String>? id,
|
Expression<String>? id,
|
||||||
Expression<String>? name,
|
Expression<String>? name,
|
||||||
@@ -634,7 +631,7 @@ class GameTableCompanion extends UpdateCompanion<GameTableData> {
|
|||||||
GameTableCompanion copyWith({
|
GameTableCompanion copyWith({
|
||||||
Value<String>? id,
|
Value<String>? id,
|
||||||
Value<String>? name,
|
Value<String>? name,
|
||||||
Value<String>? winnerId,
|
Value<String?>? winnerId,
|
||||||
Value<int>? rowid,
|
Value<int>? rowid,
|
||||||
}) {
|
}) {
|
||||||
return GameTableCompanion(
|
return GameTableCompanion(
|
||||||
@@ -1381,13 +1378,6 @@ abstract class _$AppDatabase extends GeneratedDatabase {
|
|||||||
];
|
];
|
||||||
@override
|
@override
|
||||||
StreamQueryUpdateRules get streamUpdateRules => const StreamQueryUpdateRules([
|
StreamQueryUpdateRules get streamUpdateRules => const StreamQueryUpdateRules([
|
||||||
WritePropagation(
|
|
||||||
on: TableUpdateQuery.onTableName(
|
|
||||||
'player_table',
|
|
||||||
limitUpdateKind: UpdateKind.delete,
|
|
||||||
),
|
|
||||||
result: [TableUpdate('game_table', kind: UpdateKind.delete)],
|
|
||||||
),
|
|
||||||
WritePropagation(
|
WritePropagation(
|
||||||
on: TableUpdateQuery.onTableName(
|
on: TableUpdateQuery.onTableName(
|
||||||
'player_table',
|
'player_table',
|
||||||
@@ -1450,24 +1440,6 @@ final class $$PlayerTableTableReferences
|
|||||||
extends BaseReferences<_$AppDatabase, $PlayerTableTable, PlayerTableData> {
|
extends BaseReferences<_$AppDatabase, $PlayerTableTable, PlayerTableData> {
|
||||||
$$PlayerTableTableReferences(super.$_db, super.$_table, super.$_typedResult);
|
$$PlayerTableTableReferences(super.$_db, super.$_table, super.$_typedResult);
|
||||||
|
|
||||||
static MultiTypedResultKey<$GameTableTable, List<GameTableData>>
|
|
||||||
_gameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable(
|
|
||||||
db.gameTable,
|
|
||||||
aliasName: $_aliasNameGenerator(db.playerTable.id, db.gameTable.winnerId),
|
|
||||||
);
|
|
||||||
|
|
||||||
$$GameTableTableProcessedTableManager get gameTableRefs {
|
|
||||||
final manager = $$GameTableTableTableManager(
|
|
||||||
$_db,
|
|
||||||
$_db.gameTable,
|
|
||||||
).filter((f) => f.winnerId.id.sqlEquals($_itemColumn<String>('id')!));
|
|
||||||
|
|
||||||
final cache = $_typedResult.readTableOrNull(_gameTableRefsTable($_db));
|
|
||||||
return ProcessedTableManager(
|
|
||||||
manager.$state.copyWith(prefetchedData: cache),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static MultiTypedResultKey<$PlayerGroupTableTable, List<PlayerGroupTableData>>
|
static MultiTypedResultKey<$PlayerGroupTableTable, List<PlayerGroupTableData>>
|
||||||
_playerGroupTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable(
|
_playerGroupTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable(
|
||||||
db.playerGroupTable,
|
db.playerGroupTable,
|
||||||
@@ -1534,31 +1506,6 @@ class $$PlayerTableTableFilterComposer
|
|||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
Expression<bool> gameTableRefs(
|
|
||||||
Expression<bool> Function($$GameTableTableFilterComposer f) f,
|
|
||||||
) {
|
|
||||||
final $$GameTableTableFilterComposer composer = $composerBuilder(
|
|
||||||
composer: this,
|
|
||||||
getCurrentColumn: (t) => t.id,
|
|
||||||
referencedTable: $db.gameTable,
|
|
||||||
getReferencedColumn: (t) => t.winnerId,
|
|
||||||
builder:
|
|
||||||
(
|
|
||||||
joinBuilder, {
|
|
||||||
$addJoinBuilderToRootComposer,
|
|
||||||
$removeJoinBuilderFromRootComposer,
|
|
||||||
}) => $$GameTableTableFilterComposer(
|
|
||||||
$db: $db,
|
|
||||||
$table: $db.gameTable,
|
|
||||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
|
||||||
joinBuilder: joinBuilder,
|
|
||||||
$removeJoinBuilderFromRootComposer:
|
|
||||||
$removeJoinBuilderFromRootComposer,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return f(composer);
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression<bool> playerGroupTableRefs(
|
Expression<bool> playerGroupTableRefs(
|
||||||
Expression<bool> Function($$PlayerGroupTableTableFilterComposer f) f,
|
Expression<bool> Function($$PlayerGroupTableTableFilterComposer f) f,
|
||||||
) {
|
) {
|
||||||
@@ -1645,31 +1592,6 @@ class $$PlayerTableTableAnnotationComposer
|
|||||||
GeneratedColumn<String> get name =>
|
GeneratedColumn<String> get name =>
|
||||||
$composableBuilder(column: $table.name, builder: (column) => column);
|
$composableBuilder(column: $table.name, builder: (column) => column);
|
||||||
|
|
||||||
Expression<T> gameTableRefs<T extends Object>(
|
|
||||||
Expression<T> Function($$GameTableTableAnnotationComposer a) f,
|
|
||||||
) {
|
|
||||||
final $$GameTableTableAnnotationComposer composer = $composerBuilder(
|
|
||||||
composer: this,
|
|
||||||
getCurrentColumn: (t) => t.id,
|
|
||||||
referencedTable: $db.gameTable,
|
|
||||||
getReferencedColumn: (t) => t.winnerId,
|
|
||||||
builder:
|
|
||||||
(
|
|
||||||
joinBuilder, {
|
|
||||||
$addJoinBuilderToRootComposer,
|
|
||||||
$removeJoinBuilderFromRootComposer,
|
|
||||||
}) => $$GameTableTableAnnotationComposer(
|
|
||||||
$db: $db,
|
|
||||||
$table: $db.gameTable,
|
|
||||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
|
||||||
joinBuilder: joinBuilder,
|
|
||||||
$removeJoinBuilderFromRootComposer:
|
|
||||||
$removeJoinBuilderFromRootComposer,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return f(composer);
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression<T> playerGroupTableRefs<T extends Object>(
|
Expression<T> playerGroupTableRefs<T extends Object>(
|
||||||
Expression<T> Function($$PlayerGroupTableTableAnnotationComposer a) f,
|
Expression<T> Function($$PlayerGroupTableTableAnnotationComposer a) f,
|
||||||
) {
|
) {
|
||||||
@@ -1735,7 +1657,6 @@ class $$PlayerTableTableTableManager
|
|||||||
(PlayerTableData, $$PlayerTableTableReferences),
|
(PlayerTableData, $$PlayerTableTableReferences),
|
||||||
PlayerTableData,
|
PlayerTableData,
|
||||||
PrefetchHooks Function({
|
PrefetchHooks Function({
|
||||||
bool gameTableRefs,
|
|
||||||
bool playerGroupTableRefs,
|
bool playerGroupTableRefs,
|
||||||
bool playerGameTableRefs,
|
bool playerGameTableRefs,
|
||||||
})
|
})
|
||||||
@@ -1773,42 +1694,16 @@ class $$PlayerTableTableTableManager
|
|||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
prefetchHooksCallback:
|
prefetchHooksCallback:
|
||||||
({
|
({playerGroupTableRefs = false, playerGameTableRefs = false}) {
|
||||||
gameTableRefs = false,
|
|
||||||
playerGroupTableRefs = false,
|
|
||||||
playerGameTableRefs = false,
|
|
||||||
}) {
|
|
||||||
return PrefetchHooks(
|
return PrefetchHooks(
|
||||||
db: db,
|
db: db,
|
||||||
explicitlyWatchedTables: [
|
explicitlyWatchedTables: [
|
||||||
if (gameTableRefs) db.gameTable,
|
|
||||||
if (playerGroupTableRefs) db.playerGroupTable,
|
if (playerGroupTableRefs) db.playerGroupTable,
|
||||||
if (playerGameTableRefs) db.playerGameTable,
|
if (playerGameTableRefs) db.playerGameTable,
|
||||||
],
|
],
|
||||||
addJoins: null,
|
addJoins: null,
|
||||||
getPrefetchedDataCallback: (items) async {
|
getPrefetchedDataCallback: (items) async {
|
||||||
return [
|
return [
|
||||||
if (gameTableRefs)
|
|
||||||
await $_getPrefetchedData<
|
|
||||||
PlayerTableData,
|
|
||||||
$PlayerTableTable,
|
|
||||||
GameTableData
|
|
||||||
>(
|
|
||||||
currentTable: table,
|
|
||||||
referencedTable: $$PlayerTableTableReferences
|
|
||||||
._gameTableRefsTable(db),
|
|
||||||
managerFromTypedResult: (p0) =>
|
|
||||||
$$PlayerTableTableReferences(
|
|
||||||
db,
|
|
||||||
table,
|
|
||||||
p0,
|
|
||||||
).gameTableRefs,
|
|
||||||
referencedItemsForCurrentItem:
|
|
||||||
(item, referencedItems) => referencedItems.where(
|
|
||||||
(e) => e.winnerId == item.id,
|
|
||||||
),
|
|
||||||
typedResults: items,
|
|
||||||
),
|
|
||||||
if (playerGroupTableRefs)
|
if (playerGroupTableRefs)
|
||||||
await $_getPrefetchedData<
|
await $_getPrefetchedData<
|
||||||
PlayerTableData,
|
PlayerTableData,
|
||||||
@@ -1872,7 +1767,6 @@ typedef $$PlayerTableTableProcessedTableManager =
|
|||||||
(PlayerTableData, $$PlayerTableTableReferences),
|
(PlayerTableData, $$PlayerTableTableReferences),
|
||||||
PlayerTableData,
|
PlayerTableData,
|
||||||
PrefetchHooks Function({
|
PrefetchHooks Function({
|
||||||
bool gameTableRefs,
|
|
||||||
bool playerGroupTableRefs,
|
bool playerGroupTableRefs,
|
||||||
bool playerGameTableRefs,
|
bool playerGameTableRefs,
|
||||||
})
|
})
|
||||||
@@ -2227,14 +2121,14 @@ typedef $$GameTableTableCreateCompanionBuilder =
|
|||||||
GameTableCompanion Function({
|
GameTableCompanion Function({
|
||||||
required String id,
|
required String id,
|
||||||
required String name,
|
required String name,
|
||||||
required String winnerId,
|
Value<String?> winnerId,
|
||||||
Value<int> rowid,
|
Value<int> rowid,
|
||||||
});
|
});
|
||||||
typedef $$GameTableTableUpdateCompanionBuilder =
|
typedef $$GameTableTableUpdateCompanionBuilder =
|
||||||
GameTableCompanion Function({
|
GameTableCompanion Function({
|
||||||
Value<String> id,
|
Value<String> id,
|
||||||
Value<String> name,
|
Value<String> name,
|
||||||
Value<String> winnerId,
|
Value<String?> winnerId,
|
||||||
Value<int> rowid,
|
Value<int> rowid,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2242,25 +2136,6 @@ final class $$GameTableTableReferences
|
|||||||
extends BaseReferences<_$AppDatabase, $GameTableTable, GameTableData> {
|
extends BaseReferences<_$AppDatabase, $GameTableTable, GameTableData> {
|
||||||
$$GameTableTableReferences(super.$_db, super.$_table, super.$_typedResult);
|
$$GameTableTableReferences(super.$_db, super.$_table, super.$_typedResult);
|
||||||
|
|
||||||
static $PlayerTableTable _winnerIdTable(_$AppDatabase db) =>
|
|
||||||
db.playerTable.createAlias(
|
|
||||||
$_aliasNameGenerator(db.gameTable.winnerId, db.playerTable.id),
|
|
||||||
);
|
|
||||||
|
|
||||||
$$PlayerTableTableProcessedTableManager get winnerId {
|
|
||||||
final $_column = $_itemColumn<String>('winner_id')!;
|
|
||||||
|
|
||||||
final manager = $$PlayerTableTableTableManager(
|
|
||||||
$_db,
|
|
||||||
$_db.playerTable,
|
|
||||||
).filter((f) => f.id.sqlEquals($_column));
|
|
||||||
final item = $_typedResult.readTableOrNull(_winnerIdTable($_db));
|
|
||||||
if (item == null) return manager;
|
|
||||||
return ProcessedTableManager(
|
|
||||||
manager.$state.copyWith(prefetchedData: [item]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static MultiTypedResultKey<$PlayerGameTableTable, List<PlayerGameTableData>>
|
static MultiTypedResultKey<$PlayerGameTableTable, List<PlayerGameTableData>>
|
||||||
_playerGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable(
|
_playerGameTableRefsTable(_$AppDatabase db) => MultiTypedResultKey.fromTable(
|
||||||
db.playerGameTable,
|
db.playerGameTable,
|
||||||
@@ -2319,28 +2194,10 @@ class $$GameTableTableFilterComposer
|
|||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
$$PlayerTableTableFilterComposer get winnerId {
|
ColumnFilters<String> get winnerId => $composableBuilder(
|
||||||
final $$PlayerTableTableFilterComposer composer = $composerBuilder(
|
column: $table.winnerId,
|
||||||
composer: this,
|
builder: (column) => ColumnFilters(column),
|
||||||
getCurrentColumn: (t) => t.winnerId,
|
);
|
||||||
referencedTable: $db.playerTable,
|
|
||||||
getReferencedColumn: (t) => t.id,
|
|
||||||
builder:
|
|
||||||
(
|
|
||||||
joinBuilder, {
|
|
||||||
$addJoinBuilderToRootComposer,
|
|
||||||
$removeJoinBuilderFromRootComposer,
|
|
||||||
}) => $$PlayerTableTableFilterComposer(
|
|
||||||
$db: $db,
|
|
||||||
$table: $db.playerTable,
|
|
||||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
|
||||||
joinBuilder: joinBuilder,
|
|
||||||
$removeJoinBuilderFromRootComposer:
|
|
||||||
$removeJoinBuilderFromRootComposer,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return composer;
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression<bool> playerGameTableRefs(
|
Expression<bool> playerGameTableRefs(
|
||||||
Expression<bool> Function($$PlayerGameTableTableFilterComposer f) f,
|
Expression<bool> Function($$PlayerGameTableTableFilterComposer f) f,
|
||||||
@@ -2412,28 +2269,10 @@ class $$GameTableTableOrderingComposer
|
|||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
$$PlayerTableTableOrderingComposer get winnerId {
|
ColumnOrderings<String> get winnerId => $composableBuilder(
|
||||||
final $$PlayerTableTableOrderingComposer composer = $composerBuilder(
|
column: $table.winnerId,
|
||||||
composer: this,
|
builder: (column) => ColumnOrderings(column),
|
||||||
getCurrentColumn: (t) => t.winnerId,
|
);
|
||||||
referencedTable: $db.playerTable,
|
|
||||||
getReferencedColumn: (t) => t.id,
|
|
||||||
builder:
|
|
||||||
(
|
|
||||||
joinBuilder, {
|
|
||||||
$addJoinBuilderToRootComposer,
|
|
||||||
$removeJoinBuilderFromRootComposer,
|
|
||||||
}) => $$PlayerTableTableOrderingComposer(
|
|
||||||
$db: $db,
|
|
||||||
$table: $db.playerTable,
|
|
||||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
|
||||||
joinBuilder: joinBuilder,
|
|
||||||
$removeJoinBuilderFromRootComposer:
|
|
||||||
$removeJoinBuilderFromRootComposer,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return composer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class $$GameTableTableAnnotationComposer
|
class $$GameTableTableAnnotationComposer
|
||||||
@@ -2451,28 +2290,8 @@ class $$GameTableTableAnnotationComposer
|
|||||||
GeneratedColumn<String> get name =>
|
GeneratedColumn<String> get name =>
|
||||||
$composableBuilder(column: $table.name, builder: (column) => column);
|
$composableBuilder(column: $table.name, builder: (column) => column);
|
||||||
|
|
||||||
$$PlayerTableTableAnnotationComposer get winnerId {
|
GeneratedColumn<String> get winnerId =>
|
||||||
final $$PlayerTableTableAnnotationComposer composer = $composerBuilder(
|
$composableBuilder(column: $table.winnerId, builder: (column) => column);
|
||||||
composer: this,
|
|
||||||
getCurrentColumn: (t) => t.winnerId,
|
|
||||||
referencedTable: $db.playerTable,
|
|
||||||
getReferencedColumn: (t) => t.id,
|
|
||||||
builder:
|
|
||||||
(
|
|
||||||
joinBuilder, {
|
|
||||||
$addJoinBuilderToRootComposer,
|
|
||||||
$removeJoinBuilderFromRootComposer,
|
|
||||||
}) => $$PlayerTableTableAnnotationComposer(
|
|
||||||
$db: $db,
|
|
||||||
$table: $db.playerTable,
|
|
||||||
$addJoinBuilderToRootComposer: $addJoinBuilderToRootComposer,
|
|
||||||
joinBuilder: joinBuilder,
|
|
||||||
$removeJoinBuilderFromRootComposer:
|
|
||||||
$removeJoinBuilderFromRootComposer,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return composer;
|
|
||||||
}
|
|
||||||
|
|
||||||
Expression<T> playerGameTableRefs<T extends Object>(
|
Expression<T> playerGameTableRefs<T extends Object>(
|
||||||
Expression<T> Function($$PlayerGameTableTableAnnotationComposer a) f,
|
Expression<T> Function($$PlayerGameTableTableAnnotationComposer a) f,
|
||||||
@@ -2539,7 +2358,6 @@ class $$GameTableTableTableManager
|
|||||||
(GameTableData, $$GameTableTableReferences),
|
(GameTableData, $$GameTableTableReferences),
|
||||||
GameTableData,
|
GameTableData,
|
||||||
PrefetchHooks Function({
|
PrefetchHooks Function({
|
||||||
bool winnerId,
|
|
||||||
bool playerGameTableRefs,
|
bool playerGameTableRefs,
|
||||||
bool groupGameTableRefs,
|
bool groupGameTableRefs,
|
||||||
})
|
})
|
||||||
@@ -2559,7 +2377,7 @@ class $$GameTableTableTableManager
|
|||||||
({
|
({
|
||||||
Value<String> id = const Value.absent(),
|
Value<String> id = const Value.absent(),
|
||||||
Value<String> name = const Value.absent(),
|
Value<String> name = const Value.absent(),
|
||||||
Value<String> winnerId = const Value.absent(),
|
Value<String?> winnerId = const Value.absent(),
|
||||||
Value<int> rowid = const Value.absent(),
|
Value<int> rowid = const Value.absent(),
|
||||||
}) => GameTableCompanion(
|
}) => GameTableCompanion(
|
||||||
id: id,
|
id: id,
|
||||||
@@ -2571,7 +2389,7 @@ class $$GameTableTableTableManager
|
|||||||
({
|
({
|
||||||
required String id,
|
required String id,
|
||||||
required String name,
|
required String name,
|
||||||
required String winnerId,
|
Value<String?> winnerId = const Value.absent(),
|
||||||
Value<int> rowid = const Value.absent(),
|
Value<int> rowid = const Value.absent(),
|
||||||
}) => GameTableCompanion.insert(
|
}) => GameTableCompanion.insert(
|
||||||
id: id,
|
id: id,
|
||||||
@@ -2588,49 +2406,14 @@ class $$GameTableTableTableManager
|
|||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
prefetchHooksCallback:
|
prefetchHooksCallback:
|
||||||
({
|
({playerGameTableRefs = false, groupGameTableRefs = false}) {
|
||||||
winnerId = false,
|
|
||||||
playerGameTableRefs = false,
|
|
||||||
groupGameTableRefs = false,
|
|
||||||
}) {
|
|
||||||
return PrefetchHooks(
|
return PrefetchHooks(
|
||||||
db: db,
|
db: db,
|
||||||
explicitlyWatchedTables: [
|
explicitlyWatchedTables: [
|
||||||
if (playerGameTableRefs) db.playerGameTable,
|
if (playerGameTableRefs) db.playerGameTable,
|
||||||
if (groupGameTableRefs) db.groupGameTable,
|
if (groupGameTableRefs) db.groupGameTable,
|
||||||
],
|
],
|
||||||
addJoins:
|
addJoins: null,
|
||||||
<
|
|
||||||
T extends TableManagerState<
|
|
||||||
dynamic,
|
|
||||||
dynamic,
|
|
||||||
dynamic,
|
|
||||||
dynamic,
|
|
||||||
dynamic,
|
|
||||||
dynamic,
|
|
||||||
dynamic,
|
|
||||||
dynamic,
|
|
||||||
dynamic,
|
|
||||||
dynamic,
|
|
||||||
dynamic
|
|
||||||
>
|
|
||||||
>(state) {
|
|
||||||
if (winnerId) {
|
|
||||||
state =
|
|
||||||
state.withJoin(
|
|
||||||
currentTable: table,
|
|
||||||
currentColumn: table.winnerId,
|
|
||||||
referencedTable: $$GameTableTableReferences
|
|
||||||
._winnerIdTable(db),
|
|
||||||
referencedColumn: $$GameTableTableReferences
|
|
||||||
._winnerIdTable(db)
|
|
||||||
.id,
|
|
||||||
)
|
|
||||||
as T;
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
},
|
|
||||||
getPrefetchedDataCallback: (items) async {
|
getPrefetchedDataCallback: (items) async {
|
||||||
return [
|
return [
|
||||||
if (playerGameTableRefs)
|
if (playerGameTableRefs)
|
||||||
@@ -2696,7 +2479,6 @@ typedef $$GameTableTableProcessedTableManager =
|
|||||||
(GameTableData, $$GameTableTableReferences),
|
(GameTableData, $$GameTableTableReferences),
|
||||||
GameTableData,
|
GameTableData,
|
||||||
PrefetchHooks Function({
|
PrefetchHooks Function({
|
||||||
bool winnerId,
|
|
||||||
bool playerGameTableRefs,
|
bool playerGameTableRefs,
|
||||||
bool groupGameTableRefs,
|
bool groupGameTableRefs,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
|
||||||
|
|
||||||
class GameTable extends Table {
|
class GameTable extends Table {
|
||||||
TextColumn get id => text()();
|
TextColumn get id => text()();
|
||||||
TextColumn get name => text()();
|
TextColumn get name => text()();
|
||||||
TextColumn get winnerId =>
|
late final winnerId = text().nullable()();
|
||||||
text().references(PlayerTable, #id, onDelete: KeyAction.cascade)();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Set<Column<Object>> get primaryKey => {id};
|
Set<Column<Object>> get primaryKey => {id};
|
||||||
|
|||||||
@@ -7,18 +7,34 @@ class Game {
|
|||||||
final String name;
|
final String name;
|
||||||
final List<Player>? players;
|
final List<Player>? players;
|
||||||
final Group? group;
|
final Group? group;
|
||||||
final String winner;
|
final String? winner;
|
||||||
|
|
||||||
Game({
|
Game({String? id, required this.name, this.players, this.group, this.winner})
|
||||||
String? id,
|
: id = id ?? const Uuid().v4();
|
||||||
required this.name,
|
|
||||||
this.players,
|
|
||||||
this.group,
|
|
||||||
this.winner = '',
|
|
||||||
}) : id = id ?? const Uuid().v4();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'Game{\n\tid: $id,\n\tname: $name,\n\tplayers: $players,\n\tgroup: $group,\n\twinner: $winner\n}';
|
return 'Game{\n\tid: $id,\n\tname: $name,\n\tplayers: $players,\n\tgroup: $group,\n\twinner: $winner\n}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a Game instance from a JSON object.
|
||||||
|
Game.fromJson(Map<String, dynamic> json)
|
||||||
|
: id = json['id'],
|
||||||
|
name = json['name'],
|
||||||
|
players = json['players'] != null
|
||||||
|
? (json['players'] as List)
|
||||||
|
.map((playerJson) => Player.fromJson(playerJson))
|
||||||
|
.toList()
|
||||||
|
: null,
|
||||||
|
group = json['group'] != null ? Group.fromJson(json['group']) : null,
|
||||||
|
winner = json['winner'] ?? '';
|
||||||
|
|
||||||
|
/// Converts the Game instance to a JSON object.
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'id': id,
|
||||||
|
'name': name,
|
||||||
|
'players': players?.map((player) => player.toJson()).toList(),
|
||||||
|
'group': group?.toJson(),
|
||||||
|
'winner': winner,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,4 +13,19 @@ class Group {
|
|||||||
String toString() {
|
String toString() {
|
||||||
return 'Group{id: $id, name: $name,members: $members}';
|
return 'Group{id: $id, name: $name,members: $members}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a Group instance from a JSON object.
|
||||||
|
Group.fromJson(Map<String, dynamic> json)
|
||||||
|
: id = json['id'],
|
||||||
|
name = json['name'],
|
||||||
|
members = (json['members'] as List)
|
||||||
|
.map((memberJson) => Player.fromJson(memberJson))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
/// Converts the Group instance to a JSON object.
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'id': id,
|
||||||
|
'name': name,
|
||||||
|
'members': members.map((member) => member.toJson()).toList(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,4 +10,12 @@ class Player {
|
|||||||
String toString() {
|
String toString() {
|
||||||
return 'Player{id: $id,name: $name}';
|
return 'Player{id: $id,name: $name}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a Player instance from a JSON object.
|
||||||
|
Player.fromJson(Map<String, dynamic> json)
|
||||||
|
: id = json['id'],
|
||||||
|
name = json['name'];
|
||||||
|
|
||||||
|
/// Converts the Player instance to a JSON object.
|
||||||
|
Map<String, dynamic> toJson() => {'id': id, 'name': name};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,41 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:game_tracker/core/custom_theme.dart';
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/settings_list_tile.dart';
|
import 'package:game_tracker/presentation/widgets/tiles/settings_list_tile.dart';
|
||||||
|
import 'package:game_tracker/services/data_transfer_service.dart';
|
||||||
|
import 'package:json_schema/json_schema.dart';
|
||||||
|
|
||||||
class SettingsView extends StatelessWidget {
|
class SettingsView extends StatefulWidget {
|
||||||
const SettingsView({super.key});
|
const SettingsView({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SettingsView> createState() => _SettingsViewState();
|
||||||
|
|
||||||
|
static Future<bool> validateJsonSchema(String jsonString) async {
|
||||||
|
final String schemaString;
|
||||||
|
|
||||||
|
schemaString = await rootBundle.loadString('assets/schema.json');
|
||||||
|
|
||||||
|
try {
|
||||||
|
final schema = JsonSchema.create(json.decode(schemaString));
|
||||||
|
final jsonData = json.decode(jsonString);
|
||||||
|
final result = schema.validate(jsonData);
|
||||||
|
|
||||||
|
if (result.isValid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (e, stack) {
|
||||||
|
print('[validateJsonSchema] $e');
|
||||||
|
print(stack);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SettingsViewState extends State<SettingsView> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@@ -39,41 +70,30 @@ class SettingsView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
SettingsListTile(
|
SettingsListTile(
|
||||||
title: 'Export Data',
|
title: 'Export data',
|
||||||
icon: Icons.upload_outlined,
|
icon: Icons.upload_outlined,
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
onPressed: () => exportData(),
|
onPressed: () async {
|
||||||
|
final String json =
|
||||||
|
await DataTransferService.getAppDataAsJson(context);
|
||||||
|
await DataTransferService.exportData(
|
||||||
|
json,
|
||||||
|
'exported_data',
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
SettingsListTile(
|
SettingsListTile(
|
||||||
title: 'Import Data',
|
title: 'Import data',
|
||||||
icon: Icons.download_outlined,
|
icon: Icons.download_outlined,
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
onPressed: () => importData(),
|
onPressed: () => DataTransferService.importData(context),
|
||||||
),
|
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 10),
|
|
||||||
child: Text(
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
'Example Headline',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 22,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
SettingsListTile(
|
SettingsListTile(
|
||||||
title: 'Example Tile',
|
title: 'Delete all data',
|
||||||
icon: Icons.upload_outlined,
|
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
|
||||||
onPressed: () => print('Example Tile'),
|
|
||||||
),
|
|
||||||
SettingsListTile(
|
|
||||||
title: 'Example Tile',
|
|
||||||
icon: Icons.download_outlined,
|
icon: Icons.download_outlined,
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
onPressed: () => print('Example Tile'),
|
onPressed: () => DataTransferService.deleteAllData(context),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -81,10 +101,4 @@ class SettingsView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement export functionality
|
|
||||||
void exportData() {}
|
|
||||||
|
|
||||||
// TODO: Implement import functionality
|
|
||||||
void importData() {}
|
|
||||||
}
|
}
|
||||||
|
|||||||
135
lib/services/data_transfer_service.dart
Normal file
135
lib/services/data_transfer_service.dart
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:game_tracker/data/db/database.dart';
|
||||||
|
import 'package:game_tracker/data/dto/game.dart';
|
||||||
|
import 'package:game_tracker/data/dto/group.dart';
|
||||||
|
import 'package:game_tracker/data/dto/player.dart';
|
||||||
|
import 'package:game_tracker/presentation/views/main_menu/settings_view.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class DataTransferService {
|
||||||
|
/// Deletes all data from the database.
|
||||||
|
static Future<void> deleteAllData(BuildContext context) async {
|
||||||
|
final db = Provider.of<AppDatabase>(context, listen: false);
|
||||||
|
await db.gameDao.deleteAllGames();
|
||||||
|
await db.groupDao.deleteAllGroups();
|
||||||
|
await db.playerDao.deleteAllPlayers();
|
||||||
|
print('[deleteAllData] All data deleted');
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<String> getAppDataAsJson(BuildContext context) async {
|
||||||
|
final db = Provider.of<AppDatabase>(context, listen: false);
|
||||||
|
final games = await db.gameDao.getAllGames();
|
||||||
|
final groups = await db.groupDao.getAllGroups();
|
||||||
|
final players = await db.playerDao.getAllPlayers();
|
||||||
|
|
||||||
|
// Construct a JSON representation of the data
|
||||||
|
final Map<String, dynamic> jsonMap = {
|
||||||
|
'games': games.map((game) => game.toJson()).toList(),
|
||||||
|
'groups': groups.map((group) => group.toJson()).toList(),
|
||||||
|
'players': players.map((player) => player.toJson()).toList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return json.encode(jsonMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Exports the given JSON string to a file with the specified name.
|
||||||
|
static Future<bool> exportData(String jsonString, String fileName) async {
|
||||||
|
try {
|
||||||
|
final bytes = Uint8List.fromList(utf8.encode(jsonString));
|
||||||
|
await FilePicker.platform.saveFile(
|
||||||
|
fileName: '$fileName.json',
|
||||||
|
bytes: bytes,
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
} catch (e, stack) {
|
||||||
|
print('[exportData] $e');
|
||||||
|
print(stack);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Imports data from a selected JSON file into the database.
|
||||||
|
static Future<void> importData(BuildContext context) async {
|
||||||
|
final db = Provider.of<AppDatabase>(context, listen: false);
|
||||||
|
|
||||||
|
final path = await FilePicker.platform.pickFiles(
|
||||||
|
type: FileType.custom,
|
||||||
|
allowedExtensions: ['json'],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (path == null) {
|
||||||
|
print('[importData] No file selected');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final jsonString = await _readFileContent(path.files.single);
|
||||||
|
|
||||||
|
if (await SettingsView.validateJsonSchema(jsonString)) {
|
||||||
|
final Map<String, dynamic> jsonData =
|
||||||
|
json.decode(jsonString) as Map<String, dynamic>;
|
||||||
|
|
||||||
|
final List<dynamic>? gamesJson = jsonData['games'] as List<dynamic>?;
|
||||||
|
final List<dynamic>? groupsJson = jsonData['groups'] as List<dynamic>?;
|
||||||
|
final List<dynamic>? playersJson =
|
||||||
|
jsonData['players'] as List<dynamic>?;
|
||||||
|
|
||||||
|
final List<Game> importedGames =
|
||||||
|
gamesJson
|
||||||
|
?.map((g) => Game.fromJson(g as Map<String, dynamic>))
|
||||||
|
.toList() ??
|
||||||
|
[];
|
||||||
|
final List<Group> importedGroups =
|
||||||
|
groupsJson
|
||||||
|
?.map((g) => Group.fromJson(g as Map<String, dynamic>))
|
||||||
|
.toList() ??
|
||||||
|
[];
|
||||||
|
final List<Player> importedPlayers =
|
||||||
|
playersJson
|
||||||
|
?.map((p) => Player.fromJson(p as Map<String, dynamic>))
|
||||||
|
.toList() ??
|
||||||
|
[];
|
||||||
|
|
||||||
|
for (Player player in importedPlayers) {
|
||||||
|
await db.playerDao.addPlayer(player: player);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Group group in importedGroups) {
|
||||||
|
await db.groupDao.addGroup(group: group);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Game game in importedGames) {
|
||||||
|
await db.gameDao.addGame(game: game);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print('[importData] Invalid JSON schema');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
print('[importData] Data imported successfully');
|
||||||
|
return;
|
||||||
|
} on FormatException catch (e, stack) {
|
||||||
|
print('[importData] FormatException');
|
||||||
|
print('[importData] $e');
|
||||||
|
print(stack);
|
||||||
|
return;
|
||||||
|
} on Exception catch (e, stack) {
|
||||||
|
print('[importData] Exception');
|
||||||
|
print('[importData] $e');
|
||||||
|
print(stack);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper method to read file content from either bytes or path
|
||||||
|
static Future<String> _readFileContent(PlatformFile file) async {
|
||||||
|
if (file.bytes != null) return utf8.decode(file.bytes!);
|
||||||
|
if (file.path != null) return await File(file.path!).readAsString();
|
||||||
|
|
||||||
|
throw Exception('Die Datei hat keinen lesbaren Inhalt');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,9 @@ dependencies:
|
|||||||
provider: ^6.1.5
|
provider: ^6.1.5
|
||||||
skeletonizer: ^2.1.0+1
|
skeletonizer: ^2.1.0+1
|
||||||
uuid: ^4.5.2
|
uuid: ^4.5.2
|
||||||
|
file_picker: ^10.3.6
|
||||||
|
json_schema: ^5.2.2
|
||||||
|
file_saver: ^0.3.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@@ -30,3 +33,5 @@ dev_dependencies:
|
|||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
assets:
|
||||||
|
- assets/schema.json
|
||||||
|
|||||||
Reference in New Issue
Block a user