Styling of Tournament list and detail page
This commit is contained in:
@@ -173,4 +173,9 @@ Folgende Dateien wurden in diesem Prompt verändert:
|
|||||||
- Always require the full amount of teams for initializing the bracket.
|
- Always require the full amount of teams for initializing the bracket.
|
||||||
Folgende Dateien wurden in diesem Prompt verändert:
|
Folgende Dateien wurden in diesem Prompt verändert:
|
||||||
- backend_splatournament_manager/src/app.ts
|
- backend_splatournament_manager/src/app.ts
|
||||||
- frontend_splatournament_manager/lib/pages/tournament_bracket_page.dart
|
- frontend_splatournament_manager/lib/pages/tournament_bracket_page.dart
|
||||||
|
|
||||||
|
- Style the tournament list and detail page to look closer to the rest of the app.
|
||||||
|
Folgende Dateien wurden in diesem Prompt verändert:
|
||||||
|
- frontend_splatournament_manager/lib/widgets/available_tournament_list.dart
|
||||||
|
- frontend_splatournament_manager/lib/pages/tournament_detail_page.dart
|
||||||
@@ -243,46 +243,50 @@ class _TournamentTeamsWidgetState extends State<TournamentTeamsWidget> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 4, 16, 16),
|
||||||
itemCount: teams.length,
|
itemCount: teams.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final team = teams[index];
|
final team = teams[index];
|
||||||
return ListTile(
|
return Card(
|
||||||
leading: CircleAvatar(child: Text(team.tag)),
|
margin: const EdgeInsets.only(bottom: 12),
|
||||||
title: Text(team.name),
|
child: ListTile(
|
||||||
subtitle: team.description.isNotEmpty
|
leading: CircleAvatar(child: Text(team.tag)),
|
||||||
? Text(team.description)
|
title: Text(team.name),
|
||||||
: null,
|
subtitle: team.description.isNotEmpty
|
||||||
trailing: IconButton(
|
? Text(team.description)
|
||||||
icon: Icon(
|
: null,
|
||||||
Icons.remove_circle_outline,
|
trailing: IconButton(
|
||||||
color: Colors.red,
|
icon: const Icon(
|
||||||
),
|
Icons.remove_circle_outline,
|
||||||
onPressed: () async {
|
color: Colors.red,
|
||||||
try {
|
),
|
||||||
await Provider.of<TeamProvider>(
|
onPressed: () async {
|
||||||
context,
|
try {
|
||||||
listen: false,
|
await Provider.of<TeamProvider>(
|
||||||
).removeTeamFromTournament(
|
|
||||||
widget.tournament.id,
|
|
||||||
team.id,
|
|
||||||
);
|
|
||||||
setState(() {
|
|
||||||
_teamsFuture = Provider.of<TeamProvider>(
|
|
||||||
context,
|
context,
|
||||||
listen: false,
|
listen: false,
|
||||||
).getTeamsByTournament(widget.tournament.id);
|
).removeTeamFromTournament(
|
||||||
});
|
widget.tournament.id,
|
||||||
} catch (e) {
|
team.id,
|
||||||
if (!context.mounted) return;
|
);
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
setState(() {
|
||||||
SnackBar(
|
_teamsFuture = Provider.of<TeamProvider>(
|
||||||
content: Text(
|
context,
|
||||||
'Team konnte nicht entfernt werden: ${e.toString().replaceFirst('Exception: ', '')}',
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final colorScheme = Theme.of(context).colorScheme;
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: 350,
|
height: 250,
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadiusDirectional.vertical(
|
borderRadius: const BorderRadiusDirectional.vertical(
|
||||||
bottom: Radius.circular(8),
|
bottom: Radius.circular(16),
|
||||||
),
|
),
|
||||||
image: DecorationImage(
|
gradient: LinearGradient(
|
||||||
fit: BoxFit.cover,
|
colors: [
|
||||||
//TODO: Replace with proper image
|
colorScheme.primaryContainer,
|
||||||
image: NetworkImage(
|
colorScheme.secondaryContainer,
|
||||||
"https://flutter.dev/assets/image_1.w635.f71cbb614cd16a40bfb87e128278227c.png",
|
],
|
||||||
),
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.fromLTRB(16, 0, 0, 12),
|
padding: const EdgeInsets.fromLTRB(16, 0, 16, 6),
|
||||||
child: Column(
|
child: Column(
|
||||||
verticalDirection: VerticalDirection.up,
|
|
||||||
children: [
|
children: [
|
||||||
|
const SizedBox(height: 80),
|
||||||
|
Icon(
|
||||||
|
Icons.emoji_events,
|
||||||
|
size: 116,
|
||||||
|
color: colorScheme.onPrimaryContainer.withValues(alpha: 0.7),
|
||||||
|
),
|
||||||
|
Spacer(),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
InputChip(
|
InputChip(
|
||||||
|
|||||||
@@ -9,22 +9,24 @@ class AvailableTournamentList extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Column(
|
||||||
padding: EdgeInsets.fromLTRB(24, 0, 24, 0),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Column(
|
children: [
|
||||||
children: [
|
const Padding(
|
||||||
const Row(children: [Text('Verfügbare Turniere')]),
|
padding: EdgeInsets.fromLTRB(16, 8, 16, 4),
|
||||||
SizedBox(
|
child: Text(
|
||||||
width: double.infinity,
|
'Verfügbare Turniere',
|
||||||
height: 350,
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
child: Consumer<TournamentProvider>(
|
|
||||||
builder: (context, provider, _) {
|
|
||||||
return TournamentListFutureBuilder(provider: provider);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
Expanded(
|
||||||
|
child: Consumer<TournamentProvider>(
|
||||||
|
builder: (context, provider, _) {
|
||||||
|
return TournamentListFutureBuilder(provider: provider);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,6 +60,7 @@ class TournamentListFutureBuilder extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 4, 16, 16),
|
||||||
shrinkWrap: false,
|
shrinkWrap: false,
|
||||||
itemCount: list.length,
|
itemCount: list.length,
|
||||||
itemBuilder: (context, index) {
|
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 {
|
class TournamentListItem extends StatelessWidget {
|
||||||
final Tournament tournament;
|
final Tournament tournament;
|
||||||
|
|
||||||
@@ -77,19 +89,50 @@ class TournamentListItem extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListTile(
|
final dateRange =
|
||||||
contentPadding: EdgeInsets.all(0),
|
'${_fmtDate(tournament.registrationStartDate)} – ${_fmtDate(tournament.registrationEndDate)}';
|
||||||
leading: Icon(Icons.abc),
|
return Card(
|
||||||
title: Text(tournament.name),
|
margin: const EdgeInsets.only(bottom: 12),
|
||||||
subtitle: Text(tournament.description),
|
child: InkWell(
|
||||||
onTap: () {
|
borderRadius: BorderRadius.circular(12),
|
||||||
Navigator.push(
|
onTap: () {
|
||||||
context,
|
Navigator.push(
|
||||||
MaterialPageRoute(
|
context,
|
||||||
builder: (context) => TournamentDetailPage(tournament: tournament),
|
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),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
},
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user