Styling of Tournament list and detail page

This commit is contained in:
2026-03-13 15:25:44 +01:00
parent 95897ccc07
commit dfe99a85a1
3 changed files with 133 additions and 73 deletions

View File

@@ -243,46 +243,50 @@ class _TournamentTeamsWidgetState extends State<TournamentTeamsWidget> {
);
}
return ListView.builder(
padding: const EdgeInsets.fromLTRB(16, 4, 16, 16),
itemCount: teams.length,
itemBuilder: (context, index) {
final team = teams[index];
return ListTile(
leading: CircleAvatar(child: Text(team.tag)),
title: Text(team.name),
subtitle: team.description.isNotEmpty
? Text(team.description)
: null,
trailing: IconButton(
icon: Icon(
Icons.remove_circle_outline,
color: Colors.red,
),
onPressed: () async {
try {
await Provider.of<TeamProvider>(
context,
listen: false,
).removeTeamFromTournament(
widget.tournament.id,
team.id,
);
setState(() {
_teamsFuture = Provider.of<TeamProvider>(
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: ListTile(
leading: CircleAvatar(child: Text(team.tag)),
title: Text(team.name),
subtitle: team.description.isNotEmpty
? Text(team.description)
: null,
trailing: IconButton(
icon: const Icon(
Icons.remove_circle_outline,
color: Colors.red,
),
onPressed: () async {
try {
await Provider.of<TeamProvider>(
context,
listen: false,
).getTeamsByTournament(widget.tournament.id);
});
} catch (e) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Team konnte nicht entfernt werden: ${e.toString().replaceFirst('Exception: ', '')}',
).removeTeamFromTournament(
widget.tournament.id,
team.id,
);
setState(() {
_teamsFuture = Provider.of<TeamProvider>(
context,
listen: false,
).getTeamsByTournament(widget.tournament.id);
});
} catch (e) {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Team konnte nicht entfernt werden: ${e.toString().replaceFirst('Exception: ', '')}',
),
),
),
);
}
},
);
}
},
),
),
);
},
@@ -379,26 +383,34 @@ class DetailHeader extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return SizedBox(
height: 350,
height: 250,
width: double.maxFinite,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadiusDirectional.vertical(
bottom: Radius.circular(8),
borderRadius: const BorderRadiusDirectional.vertical(
bottom: Radius.circular(16),
),
image: DecorationImage(
fit: BoxFit.cover,
//TODO: Replace with proper image
image: NetworkImage(
"https://flutter.dev/assets/image_1.w635.f71cbb614cd16a40bfb87e128278227c.png",
),
gradient: LinearGradient(
colors: [
colorScheme.primaryContainer,
colorScheme.secondaryContainer,
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
padding: EdgeInsets.fromLTRB(16, 0, 0, 12),
padding: const EdgeInsets.fromLTRB(16, 0, 16, 6),
child: Column(
verticalDirection: VerticalDirection.up,
children: [
const SizedBox(height: 80),
Icon(
Icons.emoji_events,
size: 116,
color: colorScheme.onPrimaryContainer.withValues(alpha: 0.7),
),
Spacer(),
Row(
children: [
InputChip(

View File

@@ -9,22 +9,24 @@ class AvailableTournamentList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.fromLTRB(24, 0, 24, 0),
child: Column(
children: [
const Row(children: [Text('Verfügbare Turniere')]),
SizedBox(
width: double.infinity,
height: 350,
child: Consumer<TournamentProvider>(
builder: (context, provider, _) {
return TournamentListFutureBuilder(provider: provider);
},
),
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.fromLTRB(16, 8, 16, 4),
child: Text(
'Verfügbare Turniere',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
],
),
),
Expanded(
child: Consumer<TournamentProvider>(
builder: (context, provider, _) {
return TournamentListFutureBuilder(provider: provider);
},
),
),
],
);
}
}
@@ -58,6 +60,7 @@ class TournamentListFutureBuilder extends StatelessWidget {
}
return ListView.builder(
padding: const EdgeInsets.fromLTRB(16, 4, 16, 16),
shrinkWrap: false,
itemCount: list.length,
itemBuilder: (context, index) {
@@ -70,6 +73,15 @@ class TournamentListFutureBuilder extends StatelessWidget {
}
}
String _fmtDate(String iso) {
try {
final d = DateTime.parse(iso);
return '${d.day.toString().padLeft(2, '0')}.${d.month.toString().padLeft(2, '0')}.${d.year}';
} catch (_) {
return iso;
}
}
class TournamentListItem extends StatelessWidget {
final Tournament tournament;
@@ -77,19 +89,50 @@ class TournamentListItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListTile(
contentPadding: EdgeInsets.all(0),
leading: Icon(Icons.abc),
title: Text(tournament.name),
subtitle: Text(tournament.description),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TournamentDetailPage(tournament: tournament),
final dateRange =
'${_fmtDate(tournament.registrationStartDate)} ${_fmtDate(tournament.registrationEndDate)}';
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
TournamentDetailPage(tournament: tournament),
),
);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row(
children: [
CircleAvatar(
child: const Icon(Icons.emoji_events),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tournament.name,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 4),
Text(
'${tournament.currentTeamAmount}/${tournament.maxTeamAmount} Teams\n$dateRange',
style: const TextStyle(fontSize: 13),
),
],
),
),
const Icon(Icons.chevron_right),
],
),
);
},
),
),
);
}
}