GameHistoryView anpassen #20

Merged
flixcoo merged 27 commits from feature/2-gamehistoryview-anpassen into development 2025-11-30 15:59:25 +00:00
Showing only changes of commit 32c7d45809 - Show all commits

View File

@@ -1,21 +1,15 @@
import 'package:flutter/material.dart';
import 'package:game_tracker/core/custom_theme.dart';
import 'package:skeletonizer/skeletonizer.dart';
import 'package:game_tracker/data/dto/game.dart';
import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart';
import 'package:intl/intl.dart';
sneeex marked this conversation as resolved
Review

Wofür intl?

Wofür intl?
Review

Zur berechnung vom datum :) idk ob das der optimalste weg ist

Zur berechnung vom datum :) idk ob das der optimalste weg ist
Review

Aber nutzt du da nicht nur datetime?

Aber nutzt du da nicht nur datetime?
Review

Die DateFormat klasse kommt daher:

String _formatDate(DateTime dateTime) {
    final now = DateTime.now();
    final difference = now.difference(dateTime);
    if (difference.inDays == 0) {
      return 'Today at ${DateFormat('HH:mm').format(dateTime)}';
    } else if (difference.inDays == 1) {
      return 'Yesterday at ${DateFormat('HH:mm').format(dateTime)}';
    } else if (difference.inDays < 7) {
      return '${difference.inDays} days ago';
    } else {
      return DateFormat('MMM d, yyyy').format(dateTime);
    }
  }
Die `DateFormat` klasse kommt daher: ```dart String _formatDate(DateTime dateTime) { final now = DateTime.now(); final difference = now.difference(dateTime); if (difference.inDays == 0) { return 'Today at ${DateFormat('HH:mm').format(dateTime)}'; } else if (difference.inDays == 1) { return 'Yesterday at ${DateFormat('HH:mm').format(dateTime)}'; } else if (difference.inDays < 7) { return '${difference.inDays} days ago'; } else { return DateFormat('MMM d, yyyy').format(dateTime); } } ```
class GameHistoryTile extends StatefulWidget {
gelbeinhalb marked this conversation as resolved
Review

(Code-Zeile ist falsch, weil die Datei wird nicht angezeigt) doubleRowInfoTile entfernen, wird nicht mehr genutzt

(Code-Zeile ist falsch, weil die Datei wird nicht angezeigt) `doubleRowInfoTile` entfernen, wird nicht mehr genutzt
Review

check ich nicht. wo wird das denn verwendet?

check ich nicht. wo wird das denn verwendet?
Review

Nirgendwo, deswegen kann es ja weg. Wurde vorher in GameHistoryView verwendet

Nirgendwo, deswegen kann es ja weg. Wurde vorher in `GameHistoryView` verwendet
Review

nirgendwo in meinem code steht doubleRowInfoTile 😭 oder ich bin blöd und finde es nicht

nirgendwo in meinem code steht `doubleRowInfoTile` 😭 oder ich bin blöd und finde es nicht
final String gameTitle;
final String gameType;
final String date;
final String groupName;
final String winner;
final Game game;
const GameHistoryTile({
super.key,
required this.gameTitle,
required this.gameType,
required this.date,
required this.groupName,
required this.winner,
required this.game,
});
@override
@@ -23,55 +17,171 @@ class GameHistoryTile extends StatefulWidget {
}
class _GameHistoryTileState extends State<GameHistoryTile> {
String _formatDate(DateTime dateTime) {
gelbeinhalb marked this conversation as resolved Outdated

Funktionen eines Widgets immer nach der build() Methode, diese soll in einem Widget immer als erstes kommen (nach den Variabel-Deklarationen)

Funktionen eines Widgets immer nach der `build()` Methode, diese soll in einem Widget immer als erstes kommen (nach den Variabel-Deklarationen)

👍

👍
final now = DateTime.now();
final difference = now.difference(dateTime);
if (difference.inDays == 0) {
return 'Today at ${DateFormat('HH:mm').format(dateTime)}';
} else if (difference.inDays == 1) {
return 'Yesterday at ${DateFormat('HH:mm').format(dateTime)}';
} else if (difference.inDays < 7) {
return '${difference.inDays} days ago';
} else {
return DateFormat('MMM d, yyyy').format(dateTime);
}
}
List<dynamic> _getAllPlayers() {
gelbeinhalb marked this conversation as resolved
Review

Hier auch hinter buid() Methode schieben

Hier auch hinter `buid()` Methode schieben
Review

👍

👍
final allPlayers = <dynamic>[];
final playerIds = <String>{};
// Add players from game.players
if (widget.game.players != null) {
for (var player in widget.game.players!) {
if (!playerIds.contains(player.id)) {
allPlayers.add(player);
playerIds.add(player.id);
}
}
}
// Add players from game.group.players
if (widget.game.group?.members != null) {
for (var player in widget.game.group!.members) {
if (!playerIds.contains(player.id)) {
allPlayers.add(player);
playerIds.add(player.id);
}
}
}
return allPlayers;
}
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
final group = widget.game.group;
final winner = widget.game.winner;
final allPlayers = _getAllPlayers();
return Container(
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: CustomTheme.boxColor,
border: Border.all(color: CustomTheme.boxBorder),
borderRadius: BorderRadius.circular(12),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
widget.gameTitle,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
Expanded(
child: Text(
widget.game.name,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
overflow: TextOverflow.ellipsis,
),
),
Text(
_formatDate(widget.game.createdAt),
style: const TextStyle(
fontSize: 12,
color: Colors.grey,
),
),
],
),
const SizedBox(height: 8),
if (group != null)
gelbeinhalb marked this conversation as resolved Outdated

Entweder die beiden Group Widgets in ein Visibility bzw Offstage Widget wrappen, oder in ein If-Statement zusammenführen:

if(group != null)
[...SizedBox(), Row()]
Entweder die beiden Group Widgets in ein `Visibility` bzw `Offstage` Widget wrappen, oder in ein If-Statement zusammenführen: ```dart if(group != null) [...SizedBox(), Row()] ```

Von Docs: "Offstage can be used to measure the dimensions of a widget without bringing it on screen (yet). To hide a widget from view while it is not needed, prefer removing the widget from the tree entirely rather than keeping it alive in an Offstage subtree" also eher das if

Von Docs: "Offstage can be used to measure the dimensions of a widget without bringing it on screen (yet). To hide a widget from view while it is not needed, prefer removing the widget from the tree entirely rather than keeping it alive in an Offstage subtree" also eher das if

Ja dann mach das lieber mit If

Ja dann mach das lieber mit If
Row(
children: [
Text(
widget.date,
style: const TextStyle(fontSize: 14, color: Colors.grey),
textAlign: TextAlign.left,
const Icon(
Icons.group,
size: 16,
color: Colors.grey,
),
const SizedBox(width: 6),
Expanded(
child: Text(
group.name,
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
),
overflow: TextOverflow.ellipsis,
),
const SizedBox(width: 5),
const Text('·'),
const SizedBox(width: 5),
Text(
widget.gameType,
style: const TextStyle(fontSize: 14, color: Colors.grey),
textAlign: TextAlign.left,
),
],
),
const SizedBox(height: 15),
gelbeinhalb marked this conversation as resolved Outdated

Ggf. ohne Doppelpunkt? Da dass ja nur so ne Zwischenüberschrift ist und die Spielernamen ja nicht dahinter in der gleichen Zeile stehen

Ggf. ohne Doppelpunkt? Da dass ja nur so ne Zwischenüberschrift ist und die Spielernamen ja nicht dahinter in der gleichen Zeile stehen
]
)
if (group != null) const SizedBox(height: 12),
if (winner != null)
gelbeinhalb marked this conversation as resolved
Review

Hier auch zusammenfassen oder Visibility bzw. Offstage Widget nutzen

Hier auch zusammenfassen oder `Visibility` bzw. `Offstage` Widget nutzen
Container(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
decoration: BoxDecoration(
color: Colors.green.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: Colors.green.withValues(alpha: 0.3),
width: 1,
),
),
child: Row(
children: [
const Icon(
Icons.emoji_events,
size: 20,
color: Colors.amber,
),
const SizedBox(width: 8),
Text(
'Winner: ${winner.name}',
gelbeinhalb marked this conversation as resolved Outdated

renderoverflow bei langen namen

renderoverflow bei langen namen
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
],
),
),
if (winner != null) const SizedBox(height: 12),
if (allPlayers.isNotEmpty) ...[
const Text(
'Players:',
style: TextStyle(
fontSize: 13,
color: Colors.grey,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 6),
Wrap(
spacing: 6,
runSpacing: 6,
children: allPlayers.map((player) {
final isWinner = winner != null && player.id == winner.id;
gelbeinhalb marked this conversation as resolved Outdated

is winenr wird nicht genutzt

is winenr wird nicht genutzt
return TextIconTile(
text: player.name,
iconEnabled: false,
);
}).toList(),
),
],
],
),
);
}
}