Translate App into German

This commit is contained in:
2026-03-13 14:12:00 +01:00
parent 6360600eca
commit 780afb0c56
34 changed files with 477 additions and 304 deletions

View File

@@ -2,7 +2,7 @@
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:label="frontend_splatournament_manager"
android:label="Splatournament Manager"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity

View File

@@ -7,7 +7,7 @@
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Frontend Splatournament Manager</string>
<string>Splatournament Manager</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@@ -15,7 +15,7 @@
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>frontend_splatournament_manager</string>
<string>Splatournament Manager</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>

View File

@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:frontend_splatournament_manager/pages/home_page.dart';
import 'package:frontend_splatournament_manager/pages/login_page.dart';
import 'package:frontend_splatournament_manager/pages/settings_page.dart';
@@ -34,6 +35,13 @@ class SplatournamentApp extends StatelessWidget {
return MaterialApp.router(
title: 'Splatournament Manager',
routerConfig: routes,
locale: const Locale('de', 'DE'),
supportedLocales: const [Locale('de', 'DE')],
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
themeMode: themeProvider.themeMode,
theme: themeProvider.lightTheme,
darkTheme: themeProvider.darkTheme,

View File

@@ -23,9 +23,13 @@ class _CreateTeamPageState extends State<CreateTeamPage> {
@override
void initState() {
super.initState();
_nameController = TextEditingController(text: widget.teamToEdit?.name ?? '');
_nameController = TextEditingController(
text: widget.teamToEdit?.name ?? '',
);
_tagController = TextEditingController(text: widget.teamToEdit?.tag ?? '');
_descriptionController = TextEditingController(text: widget.teamToEdit?.description ?? '');
_descriptionController = TextEditingController(
text: widget.teamToEdit?.description ?? '',
);
}
void _submitForm() async {
@@ -42,9 +46,9 @@ class _CreateTeamPageState extends State<CreateTeamPage> {
tag: _tagController.text,
description: _descriptionController.text,
);
if (!context.mounted) return;
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Team updated successfully')),
const SnackBar(content: Text('Team erfolgreich aktualisiert')),
);
} else {
await provider.createTeam(
@@ -52,20 +56,24 @@ class _CreateTeamPageState extends State<CreateTeamPage> {
tag: _tagController.text,
description: _descriptionController.text,
);
if (!context.mounted) return;
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Team created successfully')),
const SnackBar(content: Text('Team erfolgreich erstellt')),
);
}
if (!context.mounted) return;
if (!mounted) return;
Navigator.pop(context);
} catch (e) {
if (!context.mounted) return;
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
SnackBar(
content: Text(
'Fehler: ${e.toString().replaceFirst('Exception: ', '')}',
),
),
);
} finally {
if (context.mounted) setState(() => _isLoading = false);
if (mounted) setState(() => _isLoading = false);
}
}
@@ -82,7 +90,7 @@ class _CreateTeamPageState extends State<CreateTeamPage> {
final isEditing = widget.teamToEdit != null;
return Scaffold(
appBar: AppBar(
title: Text(isEditing ? 'Edit Team' : 'Create Team'),
title: Text(isEditing ? 'Team bearbeiten' : 'Team erstellen'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
@@ -94,12 +102,12 @@ class _CreateTeamPageState extends State<CreateTeamPage> {
TextFormField(
controller: _nameController,
decoration: const InputDecoration(
labelText: 'Team Name',
hintText: 'Enter team name',
labelText: 'Teamname',
hintText: 'Teamname eingeben',
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Team name is required';
return 'Der Teamname ist erforderlich';
}
return null;
},
@@ -108,17 +116,17 @@ class _CreateTeamPageState extends State<CreateTeamPage> {
TextFormField(
controller: _tagController,
decoration: const InputDecoration(
labelText: 'Team Tag',
hintText: 'Enter team tag (max 3 characters)',
labelText: 'Teamkürzel',
hintText: 'Teamkürzel eingeben (max. 3 Zeichen)',
),
maxLength: 3,
textCapitalization: TextCapitalization.characters,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Team tag is required';
return 'Das Teamkürzel ist erforderlich';
}
if (value.length > 3) {
return 'Tag must be at most 3 characters';
return 'Das Kürzel darf höchstens 3 Zeichen lang sein';
}
return null;
},
@@ -127,8 +135,8 @@ class _CreateTeamPageState extends State<CreateTeamPage> {
TextFormField(
controller: _descriptionController,
decoration: const InputDecoration(
labelText: 'Description',
hintText: 'Enter team description (optional)',
labelText: 'Beschreibung',
hintText: 'Teambeschreibung eingeben (optional)',
),
maxLines: 3,
),
@@ -137,7 +145,7 @@ class _CreateTeamPageState extends State<CreateTeamPage> {
onPressed: _isLoading ? null : _submitForm,
child: _isLoading
? const CircularProgressIndicator()
: Text(isEditing ? 'Update Team' : 'Create Team'),
: Text(isEditing ? 'Team aktualisieren' : 'Team erstellen'),
),
],
),

View File

@@ -22,12 +22,13 @@ class _CreateTournamentPageState extends State<CreateTournamentPage> {
bool _isLoading = false;
final DateFormat _dateFormat = DateFormat('yyyy-MM-dd');
final DateFormat _dateFormat = DateFormat('dd.MM.yyyy', 'de_DE');
Future<void> _selectDate(BuildContext context, bool isStart) async {
final initialDate = DateTime.now();
final picked = await showDatePicker(
context: context,
locale: const Locale('de', 'DE'),
initialDate: initialDate,
firstDate: initialDate,
lastDate: DateTime(2101),
@@ -47,14 +48,20 @@ class _CreateTournamentPageState extends State<CreateTournamentPage> {
if (!_formKey.currentState!.validate()) return;
if (_startDate == null || _endDate == null) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Please select both start and end dates.')),
const SnackBar(
content: Text(
'Bitte wähle sowohl ein Start- als auch ein Enddatum aus.',
),
),
);
return;
}
if (_endDate!.isBefore(_startDate!)) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('End date cannot be before start date.')),
const SnackBar(
content: Text('Das Enddatum darf nicht vor dem Startdatum liegen.'),
),
);
return;
}
@@ -70,15 +77,19 @@ class _CreateTournamentPageState extends State<CreateTournamentPage> {
_startDate!,
_endDate!,
);
if (!context.mounted) return;
if (!mounted) return;
Navigator.pop(context);
} catch (e) {
if (!context.mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Error: $e')));
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Fehler: ${e.toString().replaceFirst('Exception: ', '')}',
),
),
);
} finally {
if (context.mounted) setState(() => _isLoading = false);
if (mounted) setState(() => _isLoading = false);
}
}
@@ -92,7 +103,7 @@ class _CreateTournamentPageState extends State<CreateTournamentPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Create Tournament')),
appBar: AppBar(title: const Text('Turnier erstellen')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Form(
@@ -104,20 +115,20 @@ class _CreateTournamentPageState extends State<CreateTournamentPage> {
controller: _nameController,
decoration: const InputDecoration(labelText: 'Name'),
validator: (value) =>
value == null || value.isEmpty ? 'Required' : null,
value == null || value.isEmpty ? 'Pflichtfeld' : null,
),
const SizedBox(height: 16),
TextFormField(
controller: _descriptionController,
decoration: const InputDecoration(labelText: 'Description'),
decoration: const InputDecoration(labelText: 'Beschreibung'),
maxLines: 3,
validator: (value) =>
value == null || value.isEmpty ? 'Required' : null,
value == null || value.isEmpty ? 'Pflichtfeld' : null,
),
const SizedBox(height: 16),
DropdownButtonFormField<int>(
initialValue: _maxTeamAmount,
decoration: const InputDecoration(labelText: 'Max Teams'),
decoration: const InputDecoration(labelText: 'Maximale Teams'),
items: [2, 4, 8].map((int value) {
return DropdownMenuItem<int>(
value: value,
@@ -140,7 +151,7 @@ class _CreateTournamentPageState extends State<CreateTournamentPage> {
onPressed: () => _selectDate(context, true),
child: Text(
_startDate == null
? 'Select Start Date'
? 'Startdatum wählen'
: 'Start: ${_dateFormat.format(_startDate!)}',
),
),
@@ -151,8 +162,8 @@ class _CreateTournamentPageState extends State<CreateTournamentPage> {
onPressed: () => _selectDate(context, false),
child: Text(
_endDate == null
? 'Select End Date'
: 'End: ${_dateFormat.format(_endDate!)}',
? 'Enddatum wählen'
: 'Ende: ${_dateFormat.format(_endDate!)}',
),
),
),
@@ -163,7 +174,7 @@ class _CreateTournamentPageState extends State<CreateTournamentPage> {
onPressed: _isLoading ? null : _submitForm,
child: _isLoading
? const CircularProgressIndicator()
: const Text('Create Tournament'),
: const Text('Turnier erstellen'),
),
],
),

View File

@@ -42,7 +42,7 @@ class _HomePageState extends State<HomePage>
return Scaffold(
appBar: AppBar(
title: Text(_selectedIndex == 0 ? "Tournaments" : "Teams"),
title: Text(_selectedIndex == 0 ? 'Turniere' : 'Teams'),
bottom: _selectedIndex == 1
? TabBar(
controller: _tabController,
@@ -54,8 +54,8 @@ class _HomePageState extends State<HomePage>
fontWeight: FontWeight.w500,
),
tabs: const [
Tab(text: 'All Teams'),
Tab(text: 'My Teams'),
Tab(text: 'Alle Teams'),
Tab(text: 'Meine Teams'),
],
)
: null,
@@ -81,7 +81,7 @@ class _HomePageState extends State<HomePage>
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Failed to refresh ${_selectedIndex == 0 ? "tournaments" : "teams"}',
'Aktualisierung der ${_selectedIndex == 0 ? "Turniere" : "Teams"} fehlgeschlagen',
),
),
);
@@ -95,7 +95,9 @@ class _HomePageState extends State<HomePage>
},
offset: const Offset(0, 48),
itemBuilder: (context) {
return [const PopupMenuItem(value: 1, child: Text("Settings"))];
return [
const PopupMenuItem(value: 1, child: Text('Einstellungen')),
];
},
),
],
@@ -127,7 +129,7 @@ class _HomePageState extends State<HomePage>
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.emoji_events),
label: 'Tournaments',
label: 'Turniere',
),
BottomNavigationBarItem(icon: Icon(Icons.groups), label: 'Teams'),
],

View File

@@ -66,13 +66,13 @@ class _LoginPageState extends State<LoginPage> {
TextFormField(
controller: _usernameController,
decoration: const InputDecoration(
labelText: 'Username',
labelText: 'Benutzername',
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.trim().isEmpty) {
return 'Please enter a username';
return 'Bitte gib einen Benutzernamen ein';
}
return null;
},
@@ -82,16 +82,16 @@ class _LoginPageState extends State<LoginPage> {
controller: _passwordController,
obscureText: true,
decoration: const InputDecoration(
labelText: 'Password',
labelText: 'Passwort',
prefixIcon: Icon(Icons.lock),
border: OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.trim().isEmpty) {
return 'Please enter a password';
return 'Bitte gib ein Passwort ein';
}
if (_isRegistering && value.trim().length < 4) {
return 'Password must be at least 6 characters';
return 'Das Passwort muss mindestens 4 Zeichen lang sein';
}
return null;
},
@@ -124,9 +124,13 @@ class _LoginPageState extends State<LoginPage> {
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(strokeWidth: 2),
child: CircularProgressIndicator(
strokeWidth: 2,
),
)
: Text(_isRegistering ? 'Register' : 'Login'),
: Text(
_isRegistering ? 'Registrieren' : 'Anmelden',
),
);
},
),
@@ -141,8 +145,8 @@ class _LoginPageState extends State<LoginPage> {
},
child: Text(
_isRegistering
? 'Already have an account? Login'
: 'Don\'t have an account? Register',
? 'Bereits ein Konto? Anmelden'
: 'Noch kein Konto? Registrieren',
),
),
],
@@ -154,4 +158,3 @@ class _LoginPageState extends State<LoginPage> {
);
}
}

View File

@@ -17,11 +17,11 @@ class _SettingsPageState extends State<SettingsPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Splatournament")),
appBar: AppBar(title: const Text('Einstellungen')),
body: Column(
children: [
SizedBox(height: 24),
ProfileWidget(),
const SizedBox(height: 24),
const ProfileWidget(),
Column(
mainAxisSize: MainAxisSize.min,
children: [
@@ -29,7 +29,7 @@ class _SettingsPageState extends State<SettingsPage> {
ListTile(
leading: const Icon(Icons.logout, color: Colors.red),
title: const Text(
'Sign Out',
'Abmelden',
style: TextStyle(color: Colors.red),
),
onTap: () {

View File

@@ -35,13 +35,19 @@ class _TournamentBracketPageState extends State<TournamentBracketPage> {
if (mounted) {
setState(() {});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Bracket initialized successfully')),
const SnackBar(
content: Text('Turnierbaum erfolgreich initialisiert'),
),
);
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Failed to initialize bracket: $e')),
SnackBar(
content: Text(
'Initialisierung des Turnierbaums fehlgeschlagen: ${e.toString().replaceFirst('Exception: ', '')}',
),
),
);
}
}
@@ -51,7 +57,7 @@ class _TournamentBracketPageState extends State<TournamentBracketPage> {
final result = await showDialog<int>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Select Winner'),
title: const Text('Sieger auswählen'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
@@ -69,11 +75,11 @@ class _TournamentBracketPageState extends State<TournamentBracketPage> {
if (match.hasWinner)
TextButton(
onPressed: () => Navigator.pop(context, -1), // Reset signal
child: const Text('Reset'),
child: const Text('Zurücksetzen'),
),
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
child: const Text('Abbrechen'),
),
],
),
@@ -91,14 +97,22 @@ class _TournamentBracketPageState extends State<TournamentBracketPage> {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(result == -1 ? 'Match reset' : 'Winner set successfully'),
content: Text(
result == -1
? 'Match zurückgesetzt'
: 'Sieger erfolgreich festgelegt',
),
),
);
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
SnackBar(
content: Text(
'Fehler: ${e.toString().replaceFirst('Exception: ', '')}',
),
),
);
}
}
@@ -122,7 +136,11 @@ class _TournamentBracketPageState extends State<TournamentBracketPage> {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
return Center(
child: Text(
'Fehler: ${snapshot.error.toString().replaceFirst('Exception: ', '')}',
),
);
}
final teams = snapshot.data![0] as List<Team>;
@@ -135,19 +153,19 @@ class _TournamentBracketPageState extends State<TournamentBracketPage> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Bracket not initialized yet',
'Der Turnierbaum wurde noch nicht initialisiert',
style: TextStyle(fontSize: 18),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: teams.length >= 2 ? _initializeBracket : null,
child: const Text('Initialize Bracket'),
child: const Text('Turnierbaum initialisieren'),
),
if (teams.length < 2)
const Padding(
padding: EdgeInsets.only(top: 8),
child: Text(
'Need at least 2 teams',
'Mindestens 2 Teams erforderlich',
style: TextStyle(color: Colors.red),
),
),
@@ -208,11 +226,11 @@ class _BracketBoard extends StatelessWidget {
});
String _roundLabel(int round) {
if (round == roundCount - 1) return 'Winner';
if (round == roundCount - 1) return 'Sieger';
final teamsInRound = bracketSize ~/ (1 << round);
if (teamsInRound == 2) return 'Final';
if (teamsInRound == 4) return 'Semi-finals';
return 'Quarter-finals';
if (teamsInRound == 2) return 'Finale';
if (teamsInRound == 4) return 'Halbfinale';
return 'Viertelfinale';
}
double _cardTop(int round, int index) {
@@ -273,7 +291,7 @@ class _BracketBoard extends StatelessWidget {
// Match cards
for (int i = 0; i < cardsInRound; i++) {
final match = _findMatch(round, i);
children.add(
Positioned(
left: left,
@@ -292,14 +310,14 @@ class _BracketBoard extends StatelessWidget {
}
}
: match != null && match.hasWinner
? () {
final team1 = teamMap[match.team1Id];
final team2 = teamMap[match.team2Id];
if (team1 != null && team2 != null) {
onMatchTap(match, team1, team2);
}
}
: null,
? () {
final team1 = teamMap[match.team1Id];
final team2 = teamMap[match.team2Id];
if (team1 != null && team2 != null) {
onMatchTap(match, team1, team2);
}
}
: null,
),
),
);
@@ -376,11 +394,7 @@ class _MatchCard extends StatelessWidget {
final Map<int, Team> teamMap;
final VoidCallback? onTap;
const _MatchCard({
this.match,
required this.teamMap,
this.onTap,
});
const _MatchCard({this.match, required this.teamMap, this.onTap});
@override
Widget build(BuildContext context) {
@@ -430,7 +444,7 @@ class _MatchCard extends StatelessWidget {
),
const SizedBox(height: 4),
Text(
'vs',
'vs.',
style: TextStyle(
fontSize: 10,
color: colorScheme.onSurface.withValues(alpha: 0.6),

View File

@@ -3,8 +3,15 @@ import 'package:frontend_splatournament_manager/models/team.dart';
import 'package:frontend_splatournament_manager/models/tournament.dart';
import 'package:frontend_splatournament_manager/pages/tournament_bracket_page.dart';
import 'package:frontend_splatournament_manager/providers/team_provider.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
final DateFormat _tournamentDateFormat = DateFormat('dd.MM.yyyy', 'de_DE');
String _formatTournamentDate(String value) {
return _tournamentDateFormat.format(DateTime.parse(value));
}
class TournamentDetailPage extends StatefulWidget {
final Tournament tournament;
@@ -29,7 +36,7 @@ class _TournamentDetailPageState extends State<TournamentDetailPage> {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'You are not a member of any team. Join or create a team first!',
'Du bist in keinem Team. Tritt zuerst einem Team bei oder erstelle eines.',
),
),
);
@@ -40,7 +47,7 @@ class _TournamentDetailPageState extends State<TournamentDetailPage> {
context: context,
builder: (BuildContext dialogContext) {
return AlertDialog(
title: const Text('Select Your Team'),
title: const Text('Team auswählen'),
content: SizedBox(
width: double.maxFinite,
child: ListView.builder(
@@ -62,7 +69,7 @@ class _TournamentDetailPageState extends State<TournamentDetailPage> {
actions: [
TextButton(
onPressed: () => Navigator.pop(dialogContext),
child: const Text('Cancel'),
child: const Text('Abbrechen'),
),
],
);
@@ -80,7 +87,9 @@ class _TournamentDetailPageState extends State<TournamentDetailPage> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('${selectedTeam.name} joined the tournament!'),
content: Text(
'${selectedTeam.name} wurde für das Turnier angemeldet.',
),
),
);
@@ -93,7 +102,7 @@ class _TournamentDetailPageState extends State<TournamentDetailPage> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Failed to join: ${e.toString().replaceAll('Exception: ', '')}',
'Anmeldung fehlgeschlagen: ${e.toString().replaceAll('Exception: ', '')}',
),
),
);
@@ -101,9 +110,13 @@ class _TournamentDetailPageState extends State<TournamentDetailPage> {
}
} catch (e) {
if (!context.mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text('Failed to load your teams: $e')));
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Deine Teams konnten nicht geladen werden: ${e.toString().replaceFirst('Exception: ', '')}',
),
),
);
}
}
@@ -161,10 +174,10 @@ class _TournamentDetailPageState extends State<TournamentDetailPage> {
: null,
child: Text(
widget.tournament.isRegistrationFuture
? "Registration not open yet"
? 'Anmeldung noch nicht geöffnet'
: widget.tournament.isRegistrationPast
? "Registration closed"
: "Join with Team",
? 'Anmeldung geschlossen'
: 'Mit Team anmelden',
),
),
),
@@ -205,7 +218,7 @@ class _TournamentTeamsWidgetState extends State<TournamentTeamsWidget> {
Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 4),
child: Text(
'Registered Teams',
'Angemeldete Teams',
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 17),
),
),
@@ -217,11 +230,17 @@ class _TournamentTeamsWidgetState extends State<TournamentTeamsWidget> {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
return Center(
child: Text(
'Fehler: ${snapshot.error.toString().replaceFirst('Exception: ', '')}',
),
);
}
final teams = snapshot.data ?? [];
if (teams.isEmpty) {
return Center(child: Text('No teams registered yet.'));
return const Center(
child: Text('Noch keine Teams angemeldet.'),
);
}
return ListView.builder(
itemCount: teams.length,
@@ -257,7 +276,9 @@ class _TournamentTeamsWidgetState extends State<TournamentTeamsWidget> {
if (!context.mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Failed to remove team: $e'),
content: Text(
'Team konnte nicht entfernt werden: ${e.toString().replaceFirst('Exception: ', '')}',
),
),
);
}
@@ -282,6 +303,9 @@ class TournamentContentWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final registrationPeriod =
'${_formatTournamentDate(tournament.registrationStartDate)} - ${_formatTournamentDate(tournament.registrationEndDate)}';
return Expanded(
child: Column(
children: [
@@ -300,24 +324,22 @@ class TournamentContentWidget extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Registration Period",
'Anmeldezeitraum',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 17,
),
),
Text(
"${tournament.registrationStartDate} - ${tournament.registrationEndDate}",
),
Text(registrationPeriod),
SizedBox(height: 24),
Text(
"Format",
'Format',
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 17,
),
),
Text("Single Elimination"),
const Text('Einfaches K.-o.-System'),
Spacer(),
SizedBox(
width: double.infinity,
@@ -331,7 +353,7 @@ class TournamentContentWidget extends StatelessWidget {
),
);
},
child: Text("View ongoing"),
child: const Text('Turnierbaum ansehen'),
),
),
],
@@ -382,7 +404,7 @@ class DetailHeader extends StatelessWidget {
InputChip(
onPressed: () => onTeamsChipClicked(),
label: Text(
"${tournament.currentTeamAmount} out of ${tournament.maxTeamAmount} Teams",
'${tournament.currentTeamAmount} von ${tournament.maxTeamAmount} Teams',
),
),
],

View File

@@ -7,20 +7,27 @@ import 'package:frontend_splatournament_manager/services/api_client.dart';
class MatchProvider extends ChangeNotifier {
Future<void> initializeBracket(int tournamentId) async {
final response = await ApiClient.post('/tournaments/$tournamentId/bracket', {});
final response = await ApiClient.post(
'/tournaments/$tournamentId/bracket',
{},
);
if (response.statusCode != HttpStatus.created) {
throw Exception('Failed to initialize bracket (${response.statusCode})');
throw Exception(
'Turnierbaum konnte nicht initialisiert werden (${response.statusCode})',
);
}
notifyListeners();
}
Future<List<Match>> getMatchesByTournament(int tournamentId) async {
final response = await ApiClient.get('/tournaments/$tournamentId/matches');
if (response.statusCode != HttpStatus.ok) {
throw Exception('Failed to load matches (${response.statusCode})');
throw Exception(
'Matches konnten nicht geladen werden (${response.statusCode})',
);
}
final List<dynamic> list = json.decode(response.body);
@@ -34,9 +41,11 @@ class MatchProvider extends ChangeNotifier {
if (response.statusCode != HttpStatus.ok) {
final error = json.decode(response.body);
throw Exception(error['error'] ?? 'Failed to set winner');
throw Exception(
error['error'] ?? 'Sieger konnte nicht festgelegt werden',
);
}
notifyListeners();
}
@@ -44,9 +53,11 @@ class MatchProvider extends ChangeNotifier {
final response = await ApiClient.delete('/matches/$matchId/winner');
if (response.statusCode != HttpStatus.ok) {
throw Exception('Failed to reset match (${response.statusCode})');
throw Exception(
'Match konnte nicht zurückgesetzt werden (${response.statusCode})',
);
}
notifyListeners();
}
}

View File

@@ -6,7 +6,6 @@ import 'package:frontend_splatournament_manager/models/tournament.dart';
import 'package:frontend_splatournament_manager/services/api_client.dart';
class TournamentProvider extends ChangeNotifier {
List<Tournament> _availableTournaments = [];
Future<List<Tournament>>? _initialLoadFuture;
@@ -15,7 +14,9 @@ class TournamentProvider extends ChangeNotifier {
Future<List<Tournament>> _fetchTournaments() async {
final response = await ApiClient.get('/tournaments');
if (response.statusCode != HttpStatus.ok) {
throw Exception('Failed to load tournaments (${response.statusCode})');
throw Exception(
'Turniere konnten nicht geladen werden (${response.statusCode})',
);
}
final List<dynamic> list = json.decode(response.body);
@@ -45,19 +46,22 @@ class TournamentProvider extends ChangeNotifier {
DateTime registrationStartDate,
DateTime registrationEndDate,
) async {
final response = await ApiClient.post(
'/tournaments',
{
'name': name,
'description': description,
'maxTeamAmount': maxTeamAmount,
'registrationStartDate': registrationStartDate.toIso8601String().split('T')[0],
'registrationEndDate': registrationEndDate.toIso8601String().split('T')[0],
},
);
final response = await ApiClient.post('/tournaments', {
'name': name,
'description': description,
'maxTeamAmount': maxTeamAmount,
'registrationStartDate': registrationStartDate.toIso8601String().split(
'T',
)[0],
'registrationEndDate': registrationEndDate.toIso8601String().split(
'T',
)[0],
});
if (response.statusCode != HttpStatus.created) {
throw Exception('Failed to create tournament (${response.statusCode})');
throw Exception(
'Turnier konnte nicht erstellt werden (${response.statusCode})',
);
}
await refreshAvailableTournaments();

View File

@@ -4,7 +4,10 @@ import 'package:http/http.dart' as http;
class AuthService {
final String baseUrl = SplatournamentApp.baseUrl;
Future<Map<String, dynamic>> register(String username, String password) async {
Future<Map<String, dynamic>> register(
String username,
String password,
) async {
final response = await http.post(
Uri.parse('$baseUrl/register'),
headers: {'Content-Type': 'application/json'},
@@ -15,7 +18,7 @@ class AuthService {
return json.decode(response.body);
} else {
final body = json.decode(response.body);
throw Exception(body['error'] ?? 'Registration failed');
throw Exception(body['error'] ?? 'Registrierung fehlgeschlagen');
}
}
@@ -30,8 +33,7 @@ class AuthService {
return json.decode(response.body);
} else {
final body = json.decode(response.body);
throw Exception(body['error'] ?? 'Login failed');
throw Exception(body['error'] ?? 'Anmeldung fehlgeschlagen');
}
}
}

View File

@@ -5,11 +5,12 @@ import 'package:frontend_splatournament_manager/models/team.dart';
import 'package:frontend_splatournament_manager/services/api_client.dart';
class TeamService {
Future<List<Team>> getAllTeams() async {
final response = await ApiClient.get('/teams');
if (response.statusCode != HttpStatus.ok) {
throw Exception('Failed to load teams (${response.statusCode})');
throw Exception(
'Teams konnten nicht geladen werden (${response.statusCode})',
);
}
final List<dynamic> list = json.decode(response.body);
return list.map((j) => Team.fromJson(j as Map<String, dynamic>)).toList();
@@ -18,10 +19,12 @@ class TeamService {
Future<Team> getTeamById(int id) async {
final response = await ApiClient.get('/teams/$id');
if (response.statusCode == HttpStatus.notFound) {
throw Exception('Team not found');
throw Exception('Team nicht gefunden');
}
if (response.statusCode != HttpStatus.ok) {
throw Exception('Failed to load team (${response.statusCode})');
throw Exception(
'Team konnte nicht geladen werden (${response.statusCode})',
);
}
return Team.fromJson(json.decode(response.body) as Map<String, dynamic>);
}
@@ -31,13 +34,14 @@ class TeamService {
required String tag,
String description = '',
}) async {
final response = await ApiClient.post(
'/teams',
{'name': name, 'tag': tag, 'description': description},
);
final response = await ApiClient.post('/teams', {
'name': name,
'tag': tag,
'description': description,
});
if (response.statusCode != HttpStatus.created) {
final body = json.decode(response.body);
throw Exception(body['error'] ?? 'Failed to create team');
throw Exception(body['error'] ?? 'Team konnte nicht erstellt werden');
}
return Team.fromJson(json.decode(response.body) as Map<String, dynamic>);
}
@@ -48,17 +52,14 @@ class TeamService {
String? tag,
String? description,
}) async {
final response = await ApiClient.put(
'/teams/$id',
{
if (name != null) 'name': name,
if (tag != null) 'tag': tag,
if (description != null) 'description': description,
},
);
final response = await ApiClient.put('/teams/$id', {
'name': name,
'tag': tag,
'description': description,
});
if (response.statusCode != HttpStatus.ok) {
final body = json.decode(response.body);
throw Exception(body['error'] ?? 'Failed to update team');
throw Exception(body['error'] ?? 'Team konnte nicht aktualisiert werden');
}
}
@@ -66,7 +67,7 @@ class TeamService {
final response = await ApiClient.delete('/teams/$id');
if (response.statusCode != HttpStatus.ok) {
final body = json.decode(response.body);
throw Exception(body['error'] ?? 'Failed to delete team');
throw Exception(body['error'] ?? 'Team konnte nicht gelöscht werden');
}
}
@@ -74,7 +75,7 @@ class TeamService {
final response = await ApiClient.get('/tournaments/$tournamentId/teams');
if (response.statusCode != HttpStatus.ok) {
throw Exception(
'Failed to load teams for tournament (${response.statusCode})',
'Teams für das Turnier konnten nicht geladen werden (${response.statusCode})',
);
}
final List<dynamic> list = json.decode(response.body);
@@ -82,24 +83,29 @@ class TeamService {
}
Future<void> registerTeamForTournament(int tournamentId, int teamId) async {
final response = await ApiClient.post(
'/tournaments/$tournamentId/teams',
{'teamId': teamId},
);
final response = await ApiClient.post('/tournaments/$tournamentId/teams', {
'teamId': teamId,
});
if (response.statusCode == 409) {
throw Exception('Team is already registered for this tournament');
throw Exception('Das Team ist bereits für dieses Turnier angemeldet');
}
if (response.statusCode != HttpStatus.created) {
final body = json.decode(response.body);
throw Exception(body['error'] ?? 'Failed to register team');
throw Exception(
body['error'] ?? 'Team konnte nicht für das Turnier angemeldet werden',
);
}
}
Future<void> removeTeamFromTournament(int tournamentId, int teamId) async {
final response = await ApiClient.delete('/tournaments/$tournamentId/teams/$teamId');
final response = await ApiClient.delete(
'/tournaments/$tournamentId/teams/$teamId',
);
if (response.statusCode != HttpStatus.ok) {
final body = json.decode(response.body);
throw Exception(body['error'] ?? 'Failed to remove team from tournament');
throw Exception(
body['error'] ?? 'Team konnte nicht aus dem Turnier entfernt werden',
);
}
}
@@ -107,7 +113,7 @@ class TeamService {
final response = await ApiClient.get('/teams/$teamId/tournaments');
if (response.statusCode != HttpStatus.ok) {
throw Exception(
'Failed to load tournaments for team (${response.statusCode})',
'Turniere für das Team konnten nicht geladen werden (${response.statusCode})',
);
}
final List<dynamic> list = json.decode(response.body);
@@ -117,7 +123,9 @@ class TeamService {
Future<List<Team>> getUserTeams() async {
final response = await ApiClient.get('/users/me/teams');
if (response.statusCode != HttpStatus.ok) {
throw Exception('Failed to load user teams (${response.statusCode})');
throw Exception(
'Eigene Teams konnten nicht geladen werden (${response.statusCode})',
);
}
final List<dynamic> list = json.decode(response.body);
return list.map((j) => Team.fromJson(j as Map<String, dynamic>)).toList();
@@ -126,11 +134,11 @@ class TeamService {
Future<void> joinTeam(int teamId) async {
final response = await ApiClient.post('/teams/$teamId/members', {});
if (response.statusCode == 409) {
throw Exception('You are already a member of this team');
throw Exception('Du bist bereits Mitglied dieses Teams');
}
if (response.statusCode != HttpStatus.created) {
final body = json.decode(response.body);
throw Exception(body['error'] ?? 'Failed to join team');
throw Exception(body['error'] ?? 'Beitritt zum Team fehlgeschlagen');
}
}
@@ -138,14 +146,16 @@ class TeamService {
final response = await ApiClient.delete('/teams/$teamId/members/me');
if (response.statusCode != HttpStatus.ok) {
final body = json.decode(response.body);
throw Exception(body['error'] ?? 'Failed to leave team');
throw Exception(body['error'] ?? 'Team konnte nicht verlassen werden');
}
}
Future<List<Map<String, dynamic>>> getTeamMembers(int teamId) async {
final response = await ApiClient.get('/teams/$teamId/members');
if (response.statusCode != HttpStatus.ok) {
throw Exception('Failed to load team members (${response.statusCode})');
throw Exception(
'Teammitglieder konnten nicht geladen werden (${response.statusCode})',
);
}
final List<dynamic> list = json.decode(response.body);
return list.cast<Map<String, dynamic>>();

View File

@@ -13,7 +13,7 @@ class AvailableTournamentList extends StatelessWidget {
padding: EdgeInsets.fromLTRB(24, 0, 24, 0),
child: Column(
children: [
Row(children: [Text("Available Tournaments")]),
const Row(children: [Text('Verfügbare Turniere')]),
SizedBox(
width: double.infinity,
height: 350,
@@ -40,18 +40,21 @@ class TournamentListFutureBuilder extends StatelessWidget {
future: provider.ensureTournamentsLoaded(),
builder: (context, snapshot) {
final list = provider.availableTournaments;
print(list);
if (snapshot.connectionState == ConnectionState.waiting &&
list.isEmpty) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError && list.isEmpty) {
return Center(child: Text('Error: ${snapshot.error}'));
return Center(
child: Text(
'Fehler: ${snapshot.error.toString().replaceFirst('Exception: ', '')}',
),
);
}
if (list.isEmpty) {
return Center(child: Text('No tournaments found'));
return const Center(child: Text('Keine Turniere gefunden'));
}
return ListView.builder(

View File

@@ -20,7 +20,10 @@ class _MyTeamsWidgetState extends State<MyTeamsWidget> {
}
void _loadMyTeams() {
_myTeamsFuture = Provider.of<TeamProvider>(context, listen: false).getUserTeams();
_myTeamsFuture = Provider.of<TeamProvider>(
context,
listen: false,
).getUserTeams();
}
@override
@@ -33,13 +36,19 @@ class _MyTeamsWidgetState extends State<MyTeamsWidget> {
}
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
return Center(
child: Text(
'Fehler: ${snapshot.error.toString().replaceFirst('Exception: ', '')}',
),
);
}
final teams = snapshot.data ?? [];
if (teams.isEmpty) {
return const Center(
child: Text('You are not in any teams yet\nJoin teams from the All Teams tab'),
child: Text(
'Du bist noch in keinem Team.\nTritt einem Team im Tab Alle Teams bei.',
),
);
}
@@ -53,11 +62,13 @@ class _MyTeamsWidgetState extends State<MyTeamsWidget> {
}
Widget _buildTeamCard(Team team) {
final memberCountText = team.memberCount != null
? '${team.memberCount}/4 members'
: 'No members';
final description = team.description.isEmpty ? 'No description' : team.description;
final memberCountText = team.memberCount != null
? '${team.memberCount}/4 Mitglieder'
: 'Keine Mitglieder';
final description = team.description.isEmpty
? 'Keine Beschreibung'
: team.description;
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: ListTile(
@@ -79,16 +90,16 @@ class _MyTeamsWidgetState extends State<MyTeamsWidget> {
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Leave Team?'),
content: Text('Leave "${team.name}"?'),
title: const Text('Team verlassen?'),
content: Text('Soll "${team.name}" verlassen werden?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('Cancel'),
child: const Text('Abbrechen'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('Leave', style: TextStyle(color: Colors.red)),
child: const Text('Verlassen', style: TextStyle(color: Colors.red)),
),
],
),
@@ -96,18 +107,25 @@ class _MyTeamsWidgetState extends State<MyTeamsWidget> {
if (confirmed == true && mounted) {
try {
await Provider.of<TeamProvider>(context, listen: false).leaveTeam(team.id);
await Provider.of<TeamProvider>(
context,
listen: false,
).leaveTeam(team.id);
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Left team')),
);
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('Team verlassen')));
_loadMyTeams();
setState(() {});
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
SnackBar(
content: Text(
'Fehler: ${e.toString().replaceFirst('Exception: ', '')}',
),
),
);
}
}

View File

@@ -38,7 +38,7 @@ class _MyTournamentsCarouselState extends State<MyTournamentsCarousel> {
const Padding(
padding: EdgeInsets.fromLTRB(16, 16, 16, 8),
child: Text(
'My Tournaments',
'Meine Turniere',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
@@ -58,7 +58,7 @@ class _MyTournamentsCarouselState extends State<MyTournamentsCarousel> {
),
const SizedBox(height: 8),
const Text(
'No tournaments found',
'Keine Turniere gefunden',
style: TextStyle(fontSize: 16, color: Colors.grey),
),
],
@@ -77,7 +77,7 @@ class _MyTournamentsCarouselState extends State<MyTournamentsCarousel> {
const Padding(
padding: EdgeInsets.fromLTRB(16, 16, 16, 8),
child: Text(
'My Tournaments',
'Meine Turniere',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
@@ -162,13 +162,13 @@ class _TournamentCard extends StatelessWidget {
const SizedBox(width: 4),
Text(
tournament.isRegistrationOpen
? 'Registration Open'
: 'Registration Closed',
? 'Anmeldung offen'
: 'Anmeldung geschlossen',
style: const TextStyle(fontSize: 14),
),
const Spacer(),
Text(
'${tournament.currentTeamAmount}/${tournament.maxTeamAmount} teams',
'${tournament.currentTeamAmount}/${tournament.maxTeamAmount} Teams',
style: const TextStyle(fontSize: 14),
),
],

View File

@@ -14,11 +14,11 @@ class _ProfileWidgetState extends State<ProfileWidget> {
Widget build(BuildContext context) {
return Consumer<AuthProvider>(
builder: (context, provider, child) {
final username = provider.username ?? "Unknown User";
final avatarText = username.length >= 3
? username.substring(0, 3).toUpperCase()
final username = provider.username ?? 'Unbekannter Benutzer';
final avatarText = username.length >= 3
? username.substring(0, 3).toUpperCase()
: username.toUpperCase();
return Column(
children: [
SizedBox(

View File

@@ -18,21 +18,27 @@ class TeamsListWidget extends StatelessWidget {
builder: (context, snapshot) {
final teams = provider.teams;
if (snapshot.connectionState == ConnectionState.waiting && teams.isEmpty) {
if (snapshot.connectionState == ConnectionState.waiting &&
teams.isEmpty) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError && teams.isEmpty) {
return Center(child: Text('Error: ${snapshot.error}'));
return Center(
child: Text(
'Fehler: ${snapshot.error.toString().replaceFirst('Exception: ', '')}',
),
);
}
if (teams.isEmpty) {
return const Center(child: Text('No teams found'));
return const Center(child: Text('Keine Teams gefunden'));
}
return ListView.builder(
itemCount: teams.length,
itemBuilder: (context, index) => TeamListItem(team: teams[index]),
itemBuilder: (context, index) =>
TeamListItem(team: teams[index]),
);
},
);
@@ -49,11 +55,13 @@ class TeamListItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final memberCountText = team.memberCount != null
? '${team.memberCount}/4 members'
: 'No members';
final description = team.description.isEmpty ? 'No description' : team.description;
final memberCountText = team.memberCount != null
? '${team.memberCount}/4 Mitglieder'
: 'Keine Mitglieder';
final description = team.description.isEmpty
? 'Keine Beschreibung'
: team.description;
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: ListTile(
@@ -66,11 +74,11 @@ class TeamListItem extends StatelessWidget {
trailing: PopupMenuButton(
icon: const Icon(Icons.more_vert),
itemBuilder: (context) => [
const PopupMenuItem(value: 'join', child: Text('Join Team')),
const PopupMenuItem(value: 'edit', child: Text('Edit Team')),
const PopupMenuItem(value: 'join', child: Text('Team beitreten')),
const PopupMenuItem(value: 'edit', child: Text('Team bearbeiten')),
const PopupMenuItem(
value: 'delete',
child: Text('Delete Team', style: TextStyle(color: Colors.red)),
child: Text('Team löschen', style: TextStyle(color: Colors.red)),
),
],
onSelected: (value) async {
@@ -98,7 +106,7 @@ class TeamListItem extends StatelessWidget {
await Provider.of<TeamProvider>(context, listen: false).joinTeam(team.id);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Joined ${team.name}!')),
SnackBar(content: Text('Du bist ${team.name} beigetreten.')),
);
}
} catch (e) {
@@ -114,16 +122,18 @@ class TeamListItem extends StatelessWidget {
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Delete Team?'),
content: Text('Delete "${team.name}"? This cannot be undone.'),
title: const Text('Team löschen?'),
content: Text(
'Soll "${team.name}" gelöscht werden? Das kann nicht rückgängig gemacht werden.',
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('Cancel'),
child: const Text('Abbrechen'),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('Delete', style: TextStyle(color: Colors.red)),
child: const Text('Löschen', style: TextStyle(color: Colors.red)),
),
],
),
@@ -131,16 +141,23 @@ class TeamListItem extends StatelessWidget {
if (confirmed == true && context.mounted) {
try {
await Provider.of<TeamProvider>(context, listen: false).deleteTeam(team.id);
await Provider.of<TeamProvider>(
context,
listen: false,
).deleteTeam(team.id);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Team deleted')),
);
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('Team gelöscht')));
}
} catch (e) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
SnackBar(
content: Text(
'Fehler: ${e.toString().replaceFirst('Exception: ', '')}',
),
),
);
}
}

View File

@@ -9,21 +9,21 @@ class ThemeSelectorWidget extends StatelessWidget {
final List<DropdownMenuItem<AppThemeOption>> dropdownElements = [
const DropdownMenuItem(
value: AppThemeOption.lightBlue,
child: Text("Light Blue"),
child: Text('Helles Blau'),
),
const DropdownMenuItem(
value: AppThemeOption.darkPurple,
child: Text("Dark Purple"),
child: Text('Dunkles Lila'),
),
const DropdownMenuItem(
value: AppThemeOption.lightMint,
child: Text("Light Mint"),
child: Text('Helles Mint'),
),
const DropdownMenuItem(
value: AppThemeOption.darkAmber,
child: Text("Dark Amber"),
child: Text('Dunkles Bernstein'),
),
const DropdownMenuItem(value: AppThemeOption.system, child: Text("System")),
const DropdownMenuItem(value: AppThemeOption.system, child: Text('System')),
];
@override
@@ -39,7 +39,7 @@ class ThemeSelectorWidget extends StatelessWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Theme"),
const Text('Design'),
SizedBox(
width: 250,
child: DropdownButtonFormField<AppThemeOption>(

View File

@@ -45,11 +45,11 @@ static void my_application_activate(GApplication* application) {
if (use_header_bar) {
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
gtk_widget_show(GTK_WIDGET(header_bar));
gtk_header_bar_set_title(header_bar, "frontend_splatournament_manager");
gtk_header_bar_set_title(header_bar, "Splatournament Manager");
gtk_header_bar_set_show_close_button(header_bar, TRUE);
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
} else {
gtk_window_set_title(window, "frontend_splatournament_manager");
gtk_window_set_title(window, "Splatournament Manager");
}
gtk_window_set_default_size(window, 1280, 720);

View File

@@ -41,6 +41,8 @@ dependencies:
flutter_secure_storage: ^10.0.0
jwt_decoder: ^2.0.1
shared_preferences: ^2.3.3
flutter_localizations:
sdk: flutter
dev_dependencies:
flutter_test:

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="de">
<head>
<!--
If you are serving your web app in a path other than the root, change the
@@ -18,18 +18,18 @@
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A tournament Manager for Splatoon">
<meta name="description" content="Ein Turnier-Manager für Splatoon">
<!-- iOS meta tags & icons -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="frontend_splatournament_manager">
<meta name="apple-mobile-web-app-title" content="Splatournament Manager">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>frontend_splatournament_manager</title>
<title>Splatournament Manager</title>
<link rel="manifest" href="manifest.json">
</head>
<body>

View File

@@ -1,11 +1,11 @@
{
"name": "frontend_splatournament_manager",
"short_name": "frontend_splatournament_manager",
"name": "Splatournament Manager",
"short_name": "Splatournament",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",
"theme_color": "#0175C2",
"description": "A tournament Manager for Splatoon",
"description": "Ein Turnier-Manager für Splatoon",
"orientation": "portrait-primary",
"prefer_related_applications": false,
"icons": [

View File

@@ -90,12 +90,12 @@ BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "com.tikaiz" "\0"
VALUE "FileDescription", "frontend_splatournament_manager" "\0"
VALUE "FileDescription", "Splatournament Manager" "\0"
VALUE "FileVersion", VERSION_AS_STRING "\0"
VALUE "InternalName", "frontend_splatournament_manager" "\0"
VALUE "LegalCopyright", "Copyright (C) 2026 com.tikaiz. All rights reserved." "\0"
VALUE "OriginalFilename", "frontend_splatournament_manager.exe" "\0"
VALUE "ProductName", "frontend_splatournament_manager" "\0"
VALUE "ProductName", "Splatournament Manager" "\0"
VALUE "ProductVersion", VERSION_AS_STRING "\0"
END
END

View File

@@ -27,7 +27,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
FlutterWindow window(project);
Win32Window::Point origin(10, 10);
Win32Window::Size size(1280, 720);
if (!window.Create(L"frontend_splatournament_manager", origin, size)) {
if (!window.Create(L"Splatournament Manager", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);