made icon optional and default to empty string & adjust all game instances
All checks were successful
Pull Request Pipeline / test (pull_request) Successful in 36s
Pull Request Pipeline / lint (pull_request) Successful in 46s

This commit is contained in:
2026-03-09 16:24:04 +01:00
parent 16dc9746bc
commit 43e9196dca
11 changed files with 367 additions and 254 deletions

View File

@@ -1,6 +1,6 @@
import 'package:clock/clock.dart';
import 'package:uuid/uuid.dart';
import 'package:tallee/core/enums.dart';
import 'package:uuid/uuid.dart';
class Game {
final String id;
@@ -18,10 +18,11 @@ class Game {
required this.ruleset,
String? description,
required this.color,
required this.icon,
String? icon,
}) : id = id ?? const Uuid().v4(),
createdAt = createdAt ?? clock.now(),
description = description ?? '';
description = description ?? '',
icon = icon ?? '';
@override
String toString() {
@@ -49,4 +50,3 @@ class Game {
'icon': icon,
};
}

View File

@@ -27,8 +27,8 @@ class Match {
String? notes,
this.winner,
}) : id = id ?? const Uuid().v4(),
createdAt = createdAt ?? clock.now(),
notes = notes ?? '';
createdAt = createdAt ?? clock.now(),
notes = notes ?? '';
@override
String toString() {
@@ -38,14 +38,21 @@ class Match {
/// Creates a Match instance from a JSON object (ID references format).
/// Related objects are reconstructed from IDs by the DataTransferService.
Match.fromJson(Map<String, dynamic> json)
: id = json['id'],
createdAt = DateTime.parse(json['createdAt']),
endedAt = json['endedAt'] != null ? DateTime.parse(json['endedAt']) : null,
name = json['name'],
game = Game(name: '', ruleset: Ruleset.singleWinner, description: '', color: GameColor.blue, icon: ''), // Populated during import via DataTransferService
group = null, // Populated during import via DataTransferService
players = [], // Populated during import via DataTransferService
notes = json['notes'] ?? '';
: id = json['id'],
createdAt = DateTime.parse(json['createdAt']),
endedAt = json['endedAt'] != null
? DateTime.parse(json['endedAt'])
: null,
name = json['name'],
game = Game(
name: '',
ruleset: Ruleset.singleWinner,
description: '',
color: GameColor.blue,
), // Populated during import via DataTransferService
group = null, // Populated during import via DataTransferService
players = [], // Populated during import via DataTransferService
notes = json['notes'] ?? '';
/// Converts the Match instance to a JSON object using normalized format (ID references only).
Map<String, dynamic> toJson() => {

View File

@@ -42,7 +42,12 @@ class _HomeViewState extends State<HomeView> {
2,
Match(
name: 'Skeleton Match',
game: Game(name: '', ruleset: Ruleset.singleWinner, description: '', color: GameColor.blue, icon: ''),
game: Game(
name: '',
ruleset: Ruleset.singleWinner,
description: '',
color: GameColor.blue,
),
group: Group(
name: 'Skeleton Group',
description: '',
@@ -104,7 +109,9 @@ class _HomeViewState extends State<HomeView> {
if (recentMatches.isNotEmpty)
for (Match match in recentMatches)
Padding(
padding: const EdgeInsets.symmetric(vertical: 6.0),
padding: const EdgeInsets.symmetric(
vertical: 6.0,
),
child: MatchTile(
compact: true,
width: constraints.maxWidth * 0.9,
@@ -113,7 +120,8 @@ class _HomeViewState extends State<HomeView> {
await Navigator.of(context).push(
adaptivePageRoute(
fullscreenDialog: true,
builder: (context) => MatchResultView(match: match),
builder: (context) =>
MatchResultView(match: match),
),
);
await updatedWinnerInRecentMatches(match.id);
@@ -121,7 +129,10 @@ class _HomeViewState extends State<HomeView> {
),
)
else
Center(heightFactor: 5, child: Text(loc.no_recent_matches_available)),
Center(
heightFactor: 5,
child: Text(loc.no_recent_matches_available),
),
],
),
),
@@ -137,22 +148,40 @@ class _HomeViewState extends State<HomeView> {
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
QuickCreateButton(text: 'Category 1', onPressed: () {}),
QuickCreateButton(text: 'Category 2', onPressed: () {}),
QuickCreateButton(
text: 'Category 1',
onPressed: () {},
),
QuickCreateButton(
text: 'Category 2',
onPressed: () {},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
QuickCreateButton(text: 'Category 3', onPressed: () {}),
QuickCreateButton(text: 'Category 4', onPressed: () {}),
QuickCreateButton(
text: 'Category 3',
onPressed: () {},
),
QuickCreateButton(
text: 'Category 4',
onPressed: () {},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
QuickCreateButton(text: 'Category 5', onPressed: () {}),
QuickCreateButton(text: 'Category 6', onPressed: () {}),
QuickCreateButton(
text: 'Category 5',
onPressed: () {},
),
QuickCreateButton(
text: 'Category 6',
onPressed: () {},
),
],
),
],
@@ -181,9 +210,11 @@ class _HomeViewState extends State<HomeView> {
matchCount = results[0] as int;
groupCount = results[1] as int;
loadedRecentMatches = results[2] as List<Match>;
recentMatches = (loadedRecentMatches..sort((a, b) => b.createdAt.compareTo(a.createdAt)))
.take(2)
.toList();
recentMatches =
(loadedRecentMatches
..sort((a, b) => b.createdAt.compareTo(a.createdAt)))
.take(2)
.toList();
if (mounted) {
setState(() {
isLoading = false;

View File

@@ -261,7 +261,6 @@ class _CreateGameViewState extends State<CreateGameView> {
description: _descriptionController.text.trim(),
ruleset: selectedRuleset!,
color: selectedColor!,
icon: '',
);
if (isEditing) {
await handleGameUpdate(newGame);

View File

@@ -44,7 +44,6 @@ class _MatchViewState extends State<MatchView> {
ruleset: Ruleset.singleWinner,
description: '',
color: GameColor.blue,
icon: '',
),
group: Group(
name: 'Group name',

View File

@@ -40,33 +40,39 @@ class DataTransferService {
'players': players.map((p) => p.toJson()).toList(),
'games': games.map((g) => g.toJson()).toList(),
'groups': groups
.map((g) => {
'id': g.id,
'name': g.name,
'description': g.description,
'createdAt': g.createdAt.toIso8601String(),
'memberIds': (g.members).map((m) => m.id).toList(),
})
.map(
(g) => {
'id': g.id,
'name': g.name,
'description': g.description,
'createdAt': g.createdAt.toIso8601String(),
'memberIds': (g.members).map((m) => m.id).toList(),
},
)
.toList(),
'teams': teams
.map((t) => {
'id': t.id,
'name': t.name,
'createdAt': t.createdAt.toIso8601String(),
'memberIds': (t.members).map((m) => m.id).toList(),
})
.map(
(t) => {
'id': t.id,
'name': t.name,
'createdAt': t.createdAt.toIso8601String(),
'memberIds': (t.members).map((m) => m.id).toList(),
},
)
.toList(),
'matches': matches
.map((m) => {
'id': m.id,
'name': m.name,
'createdAt': m.createdAt.toIso8601String(),
'endedAt': m.endedAt?.toIso8601String(),
'gameId': m.game.id,
'groupId': m.group?.id,
'playerIds': m.players.map((p) => p.id).toList(),
'notes': m.notes,
})
.map(
(m) => {
'id': m.id,
'name': m.name,
'createdAt': m.createdAt.toIso8601String(),
'endedAt': m.endedAt?.toIso8601String(),
'gameId': m.game.id,
'groupId': m.group?.id,
'playerIds': m.players.map((p) => p.id).toList(),
'notes': m.notes,
},
)
.toList(),
};
@@ -79,9 +85,9 @@ class DataTransferService {
/// [jsonString] The JSON string to be exported.
/// [fileName] The desired name for the exported file (without extension).
static Future<ExportResult> exportData(
String jsonString,
String fileName
) async {
String jsonString,
String fileName,
) async {
try {
final bytes = Uint8List.fromList(utf8.encode(jsonString));
final path = await FilePicker.platform.saveFile(
@@ -94,7 +100,6 @@ class DataTransferService {
} else {
return ExportResult.success;
}
} catch (e, stack) {
print('[exportData] $e');
print(stack);
@@ -122,13 +127,19 @@ class DataTransferService {
final isValid = await _validateJsonSchema(jsonString);
if (!isValid) return ImportResult.invalidSchema;
final Map<String, dynamic> decoded = json.decode(jsonString) as Map<String, dynamic>;
final Map<String, dynamic> decoded =
json.decode(jsonString) as Map<String, dynamic>;
final List<dynamic> playersJson = (decoded['players'] as List<dynamic>?) ?? [];
final List<dynamic> gamesJson = (decoded['games'] as List<dynamic>?) ?? [];
final List<dynamic> groupsJson = (decoded['groups'] as List<dynamic>?) ?? [];
final List<dynamic> teamsJson = (decoded['teams'] as List<dynamic>?) ?? [];
final List<dynamic> matchesJson = (decoded['matches'] as List<dynamic>?) ?? [];
final List<dynamic> playersJson =
(decoded['players'] as List<dynamic>?) ?? [];
final List<dynamic> gamesJson =
(decoded['games'] as List<dynamic>?) ?? [];
final List<dynamic> groupsJson =
(decoded['groups'] as List<dynamic>?) ?? [];
final List<dynamic> teamsJson =
(decoded['teams'] as List<dynamic>?) ?? [];
final List<dynamic> matchesJson =
(decoded['matches'] as List<dynamic>?) ?? [];
// Import Players
final List<Player> importedPlayers = playersJson
@@ -151,7 +162,8 @@ class DataTransferService {
// Import Groups
final List<Group> importedGroups = groupsJson.map((g) {
final map = g as Map<String, dynamic>;
final memberIds = (map['memberIds'] as List<dynamic>? ?? []).cast<String>();
final memberIds = (map['memberIds'] as List<dynamic>? ?? [])
.cast<String>();
final members = memberIds
.map((id) => playerById[id])
@@ -174,7 +186,8 @@ class DataTransferService {
// Import Teams
final List<Team> importedTeams = teamsJson.map((t) {
final map = t as Map<String, dynamic>;
final memberIds = (map['memberIds'] as List<dynamic>? ?? []).cast<String>();
final memberIds = (map['memberIds'] as List<dynamic>? ?? [])
.cast<String>();
final members = memberIds
.map((id) => playerById[id])
@@ -195,8 +208,11 @@ class DataTransferService {
final String gameId = map['gameId'] as String;
final String? groupId = map['groupId'] as String?;
final List<String> playerIds = (map['playerIds'] as List<dynamic>? ?? []).cast<String>();
final DateTime? endedAt = map['endedAt'] != null ? DateTime.parse(map['endedAt'] as String) : null;
final List<String> playerIds =
(map['playerIds'] as List<dynamic>? ?? []).cast<String>();
final DateTime? endedAt = map['endedAt'] != null
? DateTime.parse(map['endedAt'] as String)
: null;
final game = gameById[gameId];
final group = (groupId == null) ? null : groupById[groupId];
@@ -208,7 +224,14 @@ class DataTransferService {
return Match(
id: map['id'] as String,
name: map['name'] as String,
game: game ?? Game(name: 'Unknown', ruleset: Ruleset.singleWinner, description: '', color: GameColor.blue, icon: ''),
game:
game ??
Game(
name: 'Unknown',
ruleset: Ruleset.singleWinner,
description: '',
color: GameColor.blue,
),
group: group,
players: players,
createdAt: DateTime.parse(map['createdAt'] as String),
@@ -266,4 +289,4 @@ class DataTransferService {
return false;
}
}
}
}