Compare commits
3 Commits
7cd53aa695
...
2ebd4274f0
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ebd4274f0 | |||
| 70307016b3 | |||
| 1b3334f3e0 |
@@ -107,6 +107,7 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
|
|||||||
mode: InsertMode.insertOrReplace,
|
mode: InsertMode.insertOrReplace,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add all groups of the games in batch
|
// Add all groups of the games in batch
|
||||||
await db.batch(
|
await db.batch(
|
||||||
(b) => b.insertAll(
|
(b) => b.insertAll(
|
||||||
@@ -125,8 +126,42 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add all players of the games in batch
|
// Add all players of the games in batch (unique)
|
||||||
await db.batch((b) async {
|
final uniquePlayers = <String, Player>{};
|
||||||
|
for (final game in games) {
|
||||||
|
if (game.players != null) {
|
||||||
|
for (final p in game.players!) {
|
||||||
|
uniquePlayers[p.id] = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Also include members of groups
|
||||||
|
if (game.group != null) {
|
||||||
|
for (final m in game.group!.members) {
|
||||||
|
uniquePlayers[m.id] = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uniquePlayers.isNotEmpty) {
|
||||||
|
await db.batch(
|
||||||
|
(b) => b.insertAll(
|
||||||
|
db.playerTable,
|
||||||
|
uniquePlayers.values
|
||||||
|
.map(
|
||||||
|
(p) => PlayerTableCompanion.insert(
|
||||||
|
id: p.id,
|
||||||
|
name: p.name,
|
||||||
|
createdAt: p.createdAt,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
mode: InsertMode.insertOrReplace,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add all player-game associations in batch
|
||||||
|
await db.batch((b) {
|
||||||
for (final game in games) {
|
for (final game in games) {
|
||||||
if (game.players != null) {
|
if (game.players != null) {
|
||||||
for (final p in game.players ?? []) {
|
for (final p in game.players ?? []) {
|
||||||
@@ -143,8 +178,26 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Add all player-group associations in batch
|
||||||
|
await db.batch((b) {
|
||||||
|
for (final game in games) {
|
||||||
|
if (game.group != null) {
|
||||||
|
for (final m in game.group!.members) {
|
||||||
|
b.insert(
|
||||||
|
db.playerGroupTable,
|
||||||
|
PlayerGroupTableCompanion.insert(
|
||||||
|
playerId: m.id,
|
||||||
|
groupId: game.group!.id,
|
||||||
|
),
|
||||||
|
mode: InsertMode.insertOrReplace,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Add all group-game associations in batch
|
// Add all group-game associations in batch
|
||||||
await db.batch((b) async {
|
await db.batch((b) {
|
||||||
for (final game in games) {
|
for (final game in games) {
|
||||||
if (game.group != null) {
|
if (game.group != null) {
|
||||||
b.insert(
|
b.insert(
|
||||||
@@ -158,25 +211,6 @@ class GameDao extends DatabaseAccessor<AppDatabase> with _$GameDaoMixin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add all player-game associations in batch
|
|
||||||
await db.batch((b) async {
|
|
||||||
for (final game in games) {
|
|
||||||
if (game.players != null) {
|
|
||||||
for (final p in game.players ?? []) {
|
|
||||||
b.insert(
|
|
||||||
db.playerTable,
|
|
||||||
PlayerTableCompanion.insert(
|
|
||||||
id: p.id,
|
|
||||||
name: p.name,
|
|
||||||
createdAt: p.createdAt,
|
|
||||||
),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,10 +87,17 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
|
|||||||
Future<void> addGroups({required List<Group> groups}) async {
|
Future<void> addGroups({required List<Group> groups}) async {
|
||||||
if (groups.isEmpty) return;
|
if (groups.isEmpty) return;
|
||||||
await db.transaction(() async {
|
await db.transaction(() async {
|
||||||
|
// Deduplicate groups by id - keep first occurrence
|
||||||
|
final Map<String, Group> uniqueGroups = {};
|
||||||
|
for (final g in groups) {
|
||||||
|
uniqueGroups.putIfAbsent(g.id, () => g);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert unique groups in batch
|
||||||
await db.batch(
|
await db.batch(
|
||||||
(b) => b.insertAll(
|
(b) => b.insertAll(
|
||||||
groupTable,
|
groupTable,
|
||||||
groups
|
uniqueGroups.values
|
||||||
.map(
|
.map(
|
||||||
(group) => GroupTableCompanion.insert(
|
(group) => GroupTableCompanion.insert(
|
||||||
id: group.id,
|
id: group.id,
|
||||||
@@ -103,17 +110,24 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (final group in groups) {
|
// Collect unique players from all groups
|
||||||
await db.playerDao.addPlayers(players: group.members);
|
final uniquePlayers = <String, Player>{};
|
||||||
|
for (final g in uniqueGroups.values) {
|
||||||
|
for (final m in g.members) {
|
||||||
|
uniquePlayers[m.id] = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uniquePlayers.isNotEmpty) {
|
||||||
await db.batch(
|
await db.batch(
|
||||||
(b) => b.insertAll(
|
(b) => b.insertAll(
|
||||||
db.playerGroupTable,
|
db.playerTable,
|
||||||
group.members
|
uniquePlayers.values
|
||||||
.map(
|
.map(
|
||||||
(member) => PlayerGroupTableCompanion.insert(
|
(p) => PlayerTableCompanion.insert(
|
||||||
playerId: member.id,
|
id: p.id,
|
||||||
groupId: group.id,
|
name: p.name,
|
||||||
|
createdAt: p.createdAt,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
@@ -121,6 +135,29 @@ class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prepare all player-group associations in one list (unique pairs)
|
||||||
|
final Set<String> seenPairs = {};
|
||||||
|
final List<PlayerGroupTableCompanion> pgRows = [];
|
||||||
|
for (final g in uniqueGroups.values) {
|
||||||
|
for (final m in g.members) {
|
||||||
|
final key = '${m.id}|${g.id}';
|
||||||
|
if (!seenPairs.contains(key)) {
|
||||||
|
seenPairs.add(key);
|
||||||
|
pgRows.add(
|
||||||
|
PlayerGroupTableCompanion.insert(playerId: m.id, groupId: g.id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pgRows.isNotEmpty) {
|
||||||
|
await db.batch((b) {
|
||||||
|
for (final pg in pgRows) {
|
||||||
|
b.insert(db.playerGroupTable, pg, mode: InsertMode.insertOrReplace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +1,14 @@
|
|||||||
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/core/enums.dart';
|
import 'package:game_tracker/core/enums.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:game_tracker/services/data_transfer_service.dart';
|
||||||
import 'package:json_schema/json_schema.dart';
|
|
||||||
|
|
||||||
class SettingsView extends StatefulWidget {
|
class SettingsView extends StatefulWidget {
|
||||||
const SettingsView({super.key});
|
const SettingsView({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SettingsView> createState() => _SettingsViewState();
|
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> {
|
class _SettingsViewState extends State<SettingsView> {
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:game_tracker/core/enums.dart';
|
import 'package:game_tracker/core/enums.dart';
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
import 'package:game_tracker/data/db/database.dart';
|
||||||
import 'package:game_tracker/data/dto/game.dart';
|
import 'package:game_tracker/data/dto/game.dart';
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
import 'package:game_tracker/data/dto/group.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:game_tracker/data/dto/player.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/settings_view.dart';
|
import 'package:json_schema/json_schema.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class DataTransferService {
|
class DataTransferService {
|
||||||
@@ -85,7 +85,7 @@ class DataTransferService {
|
|||||||
return ImportResult.fileReadError;
|
return ImportResult.fileReadError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await SettingsView.validateJsonSchema(jsonString)) {
|
if (await _validateJsonSchema(jsonString)) {
|
||||||
final Map<String, dynamic> jsonData =
|
final Map<String, dynamic> jsonData =
|
||||||
json.decode(jsonString) as Map<String, dynamic>;
|
json.decode(jsonString) as Map<String, dynamic>;
|
||||||
|
|
||||||
@@ -136,4 +136,26 @@ class DataTransferService {
|
|||||||
if (file.path != null) return await File(file.path!).readAsString();
|
if (file.path != null) return await File(file.path!).readAsString();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Validates the given JSON string against the predefined schema.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user