Compare commits
4 Commits
d7f08c5f50
...
enhancemen
| Author | SHA1 | Date | |
|---|---|---|---|
| ab20bd764b | |||
| 8ca4e3210e | |||
| a480530919 | |||
| 799b7d8403 |
27
.gitignore
vendored
27
.gitignore
vendored
@@ -150,9 +150,25 @@ app.*.symbols
|
|||||||
.gclient_previous_custom_vars
|
.gclient_previous_custom_vars
|
||||||
.gclient_previous_sync_commits
|
.gclient_previous_sync_commits
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.build/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
.swiftpm/
|
.swiftpm/
|
||||||
migrate_working_dir/
|
migrate_working_dir/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
# The .vscode folder contains launch configuration and tasks you configure in
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
# VS Code which you may wish to be included in version control, so this line
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
@@ -160,8 +176,17 @@ migrate_working_dir/
|
|||||||
#.vscode/
|
#.vscode/
|
||||||
|
|
||||||
# Flutter/Dart/Pub related
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
**/ios/Flutter/.last_build_id
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
/build/
|
/build/
|
||||||
|
|
||||||
|
# Symbolication related
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
# Obfuscation related
|
# Obfuscation related
|
||||||
app.*.map.json
|
app.*.map.json
|
||||||
@@ -171,5 +196,3 @@ app.*.map.json
|
|||||||
/android/app/profile
|
/android/app/profile
|
||||||
/android/app/release
|
/android/app/release
|
||||||
/devtools_options.yaml
|
/devtools_options.yaml
|
||||||
|
|
||||||
untranslated_messages.json
|
|
||||||
@@ -18,7 +18,7 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||||
id("com.android.application") version "8.9.1" apply false
|
id("com.android.application") version "8.7.3" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
|
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,6 @@
|
|||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>LSApplicationQueriesSchemes</key>
|
|
||||||
<array>
|
|
||||||
<string>https</string>
|
|
||||||
<string>http</string>
|
|
||||||
</array>
|
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
<key>UIMainStoryboardFile</key>
|
<key>UIMainStoryboardFile</key>
|
||||||
|
|||||||
@@ -3,4 +3,3 @@ template-arb-file: app_en.arb
|
|||||||
output-localization-file: app_localizations.dart
|
output-localization-file: app_localizations.dart
|
||||||
output-dir: lib/l10n/generated
|
output-dir: lib/l10n/generated
|
||||||
nullable-getter: false
|
nullable-getter: false
|
||||||
untranslated-messages-file: lib/l10n/untranslated_messages.json
|
|
||||||
@@ -11,6 +11,8 @@ class CustomTheme {
|
|||||||
static Color onBoxColor = const Color(0xFF181818);
|
static Color onBoxColor = const Color(0xFF181818);
|
||||||
static Color boxBorder = const Color(0xFF272727);
|
static Color boxBorder = const Color(0xFF272727);
|
||||||
static const Color textColor = Colors.white;
|
static const Color textColor = Colors.white;
|
||||||
|
static Color navBarItemSelectedColor = primaryColor.withValues(green: 0.4);
|
||||||
|
static Color navBarItemUnselectedColor = Colors.white.withValues(alpha: 0.6);
|
||||||
|
|
||||||
// ==================== Border Radius ====================
|
// ==================== Border Radius ====================
|
||||||
static const double standardBorderRadius = 12.0;
|
static const double standardBorderRadius = 12.0;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
"all_players": "Alle Spieler:innen",
|
"all_players": "Alle Spieler:innen",
|
||||||
"all_players_selected": "Alle Spieler:innen ausgewählt",
|
"all_players_selected": "Alle Spieler:innen ausgewählt",
|
||||||
"amount_of_matches": "Anzahl der Spiele",
|
"amount_of_matches": "Anzahl der Spiele",
|
||||||
"app_name": "Game Tracker",
|
|
||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
"choose_game": "Spielvorlage wählen",
|
"choose_game": "Spielvorlage wählen",
|
||||||
"choose_group": "Gruppe wählen",
|
"choose_group": "Gruppe wählen",
|
||||||
@@ -34,10 +33,6 @@
|
|||||||
"import_data": "Daten importieren",
|
"import_data": "Daten importieren",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"invalid_schema": "Ungültiges Schema",
|
"invalid_schema": "Ungültiges Schema",
|
||||||
"licenses": "Lizenzen",
|
|
||||||
"no_licenses_found": "Keine Lizenzen gefunden",
|
|
||||||
"no_license_text_available": "Kein Lizenztext verfügbar",
|
|
||||||
"error": "Fehler",
|
|
||||||
"least_points": "Niedrigste Punkte",
|
"least_points": "Niedrigste Punkte",
|
||||||
"match_in_progress": "Spiel läuft...",
|
"match_in_progress": "Spiel läuft...",
|
||||||
"match_name": "Spieltitel",
|
"match_name": "Spieltitel",
|
||||||
|
|||||||
@@ -107,18 +107,6 @@
|
|||||||
"@invalid_schema": {
|
"@invalid_schema": {
|
||||||
"description": "Error message for invalid schema"
|
"description": "Error message for invalid schema"
|
||||||
},
|
},
|
||||||
"@licenses": {
|
|
||||||
"description": "Licenses menu item"
|
|
||||||
},
|
|
||||||
"@no_licenses_found": {
|
|
||||||
"description": "Message when no licenses are found"
|
|
||||||
},
|
|
||||||
"@no_license_text_available": {
|
|
||||||
"description": "Message when no license text is available"
|
|
||||||
},
|
|
||||||
"@error": {
|
|
||||||
"description": "Error label"
|
|
||||||
},
|
|
||||||
"@least_points": {
|
"@least_points": {
|
||||||
"description": "Title for least points ruleset"
|
"description": "Title for least points ruleset"
|
||||||
},
|
},
|
||||||
@@ -305,10 +293,6 @@
|
|||||||
"import_data": "Import data",
|
"import_data": "Import data",
|
||||||
"info": "Info",
|
"info": "Info",
|
||||||
"invalid_schema": "Invalid Schema",
|
"invalid_schema": "Invalid Schema",
|
||||||
"licenses": "Licenses",
|
|
||||||
"no_licenses_found": "No licenses found",
|
|
||||||
"no_license_text_available": "No license text available",
|
|
||||||
"error": "Error",
|
|
||||||
"least_points": "Least Points",
|
"least_points": "Least Points",
|
||||||
"match_in_progress": "Match in progress...",
|
"match_in_progress": "Match in progress...",
|
||||||
"match_name": "Match name",
|
"match_name": "Match name",
|
||||||
|
|||||||
@@ -302,30 +302,6 @@ abstract class AppLocalizations {
|
|||||||
/// **'Invalid Schema'**
|
/// **'Invalid Schema'**
|
||||||
String get invalid_schema;
|
String get invalid_schema;
|
||||||
|
|
||||||
/// Licenses menu item
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Licenses'**
|
|
||||||
String get licenses;
|
|
||||||
|
|
||||||
/// Message when no licenses are found
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'No licenses found'**
|
|
||||||
String get no_licenses_found;
|
|
||||||
|
|
||||||
/// Message when no license text is available
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'No license text available'**
|
|
||||||
String get no_license_text_available;
|
|
||||||
|
|
||||||
/// Error label
|
|
||||||
///
|
|
||||||
/// In en, this message translates to:
|
|
||||||
/// **'Error'**
|
|
||||||
String get error;
|
|
||||||
|
|
||||||
/// Title for least points ruleset
|
/// Title for least points ruleset
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|||||||
@@ -115,18 +115,6 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get invalid_schema => 'Ungültiges Schema';
|
String get invalid_schema => 'Ungültiges Schema';
|
||||||
|
|
||||||
@override
|
|
||||||
String get licenses => 'Lizenzen';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get no_licenses_found => 'Keine Lizenzen gefunden';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get no_license_text_available => 'Kein Lizenztext verfügbar';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get error => 'Fehler';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get least_points => 'Niedrigste Punkte';
|
String get least_points => 'Niedrigste Punkte';
|
||||||
|
|
||||||
|
|||||||
@@ -115,18 +115,6 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get invalid_schema => 'Invalid Schema';
|
String get invalid_schema => 'Invalid Schema';
|
||||||
|
|
||||||
@override
|
|
||||||
String get licenses => 'Licenses';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get no_licenses_found => 'No licenses found';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get no_license_text_available => 'No license text available';
|
|
||||||
|
|
||||||
@override
|
|
||||||
String get error => 'Error';
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get least_points => 'Least Points';
|
String get least_points => 'Least Points';
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/adaptive_page_route.dart';
|
import 'package:game_tracker/core/adaptive_page_route.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:game_tracker/core/custom_theme.dart';
|
||||||
@@ -5,7 +7,7 @@ import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|||||||
import 'package:game_tracker/presentation/views/main_menu/group_view/groups_view.dart';
|
import 'package:game_tracker/presentation/views/main_menu/group_view/groups_view.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/home_view.dart';
|
import 'package:game_tracker/presentation/views/main_menu/home_view.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/match_view/match_view.dart';
|
import 'package:game_tracker/presentation/views/main_menu/match_view/match_view.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/settings_view/settings_view.dart';
|
import 'package:game_tracker/presentation/views/main_menu/settings_view.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/statistics_view.dart';
|
import 'package:game_tracker/presentation/views/main_menu/statistics_view.dart';
|
||||||
import 'package:game_tracker/presentation/widgets/navbar_item.dart';
|
import 'package:game_tracker/presentation/widgets/navbar_item.dart';
|
||||||
|
|
||||||
@@ -71,18 +73,61 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
|
|||||||
backgroundColor: CustomTheme.backgroundColor,
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
body: tabs[currentIndex],
|
body: tabs[currentIndex],
|
||||||
extendBody: true,
|
extendBody: true,
|
||||||
bottomNavigationBar: SafeArea(
|
bottomNavigationBar: SizedBox(
|
||||||
minimum: const EdgeInsets.only(bottom: 30),
|
height: 70 + MediaQuery.of(context).padding.bottom,
|
||||||
child: Container(
|
child: Stack(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 10),
|
children: [
|
||||||
decoration: BoxDecoration(
|
// Dynamisch generierte Blur-Layer für ultra-smooth Übergang
|
||||||
borderRadius: BorderRadius.circular(24),
|
...List.generate(35, (index) {
|
||||||
color: CustomTheme.primaryColor,
|
// Verwende kubische Kurve für noch natürlicheren, weicheren Übergang
|
||||||
|
final progress = index / 34.0; // 0.0 bis 1.0
|
||||||
|
final cubic = progress * progress * progress; // Kubische Kurve
|
||||||
|
final blurStrength = 0.5 + (cubic * 50.0); // Sehr sanft von 0.5 bis 50.5
|
||||||
|
|
||||||
|
// Höhe geht jetzt komplett von 100% bis 0% (ganz nach unten)
|
||||||
|
// Mit extra Dichte am unteren Ende für weicheren Übergang
|
||||||
|
final heightFactor = index < 25
|
||||||
|
? 1.0 - (progress * 0.7) // Erste 25 Layer: 100% bis 30%
|
||||||
|
: 0.3 - ((index - 25) / 34.0); // Letzte 10 Layer: 30% bis 0% (dichter)
|
||||||
|
|
||||||
|
return Positioned(
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
height: (70 + MediaQuery.of(context).padding.bottom) * heightFactor.clamp(0.05, 1.0),
|
||||||
|
child: ClipRect(
|
||||||
|
child: BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(
|
||||||
|
sigmaX: blurStrength,
|
||||||
|
sigmaY: blurStrength,
|
||||||
),
|
),
|
||||||
child: ClipRRect(
|
child: Container(
|
||||||
borderRadius: BorderRadius.circular(24),
|
color: Colors.transparent,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
// Gradient-Overlay
|
||||||
|
Positioned.fill(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.bottomCenter,
|
||||||
|
end: Alignment.topCenter,
|
||||||
|
colors: [
|
||||||
|
CustomTheme.boxColor.withValues(alpha: 1),
|
||||||
|
CustomTheme.boxColor.withValues(alpha: 0.0),
|
||||||
|
],
|
||||||
|
stops: const [0.4, 1],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// Navbar-Inhalt
|
||||||
|
SafeArea(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 60,
|
height: 70,
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
@@ -118,6 +163,7 @@ class _CustomNavigationBarState extends State<CustomNavigationBar>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -105,7 +105,8 @@ class _MatchViewState extends State<MatchView> {
|
|||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: MediaQuery.paddingOf(context).bottom,
|
bottom: MediaQuery.paddingOf(context).bottom,
|
||||||
child: CustomWidthButton(
|
child: SizedBox.shrink()
|
||||||
|
/* CustomWidthButton(
|
||||||
text: loc.create_match,
|
text: loc.create_match,
|
||||||
sizeRelativeToWidth: 0.90,
|
sizeRelativeToWidth: 0.90,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
@@ -118,6 +119,7 @@ class _MatchViewState extends State<MatchView> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
*/
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,17 +1,10 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:game_tracker/core/custom_theme.dart';
|
||||||
import 'package:game_tracker/core/enums.dart';
|
import 'package:game_tracker/core/enums.dart';
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses_view.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/settings_list_tile.dart';
|
import 'package:game_tracker/presentation/widgets/tiles/settings_list_tile.dart';
|
||||||
import 'package:game_tracker/services/data_transfer_service.dart';
|
import 'package:game_tracker/services/data_transfer_service.dart';
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
|
||||||
|
|
||||||
class SettingsView extends StatefulWidget {
|
class SettingsView extends StatefulWidget {
|
||||||
const SettingsView({super.key});
|
const SettingsView({super.key});
|
||||||
@@ -45,7 +38,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 16, bottom: 10),
|
padding: const EdgeInsets.fromLTRB(24, 0, 24, 10),
|
||||||
child: Text(
|
child: Text(
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
loc.menu,
|
loc.menu,
|
||||||
@@ -56,7 +49,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 16, top: 10, bottom: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10),
|
||||||
child: Text(
|
child: Text(
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
loc.settings,
|
loc.settings,
|
||||||
@@ -68,7 +61,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
),
|
),
|
||||||
SettingsListTile(
|
SettingsListTile(
|
||||||
title: loc.export_data,
|
title: loc.export_data,
|
||||||
icon: Icons.upload,
|
icon: Icons.upload_rounded,
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final String json = await DataTransferService.getAppDataAsJson(
|
final String json = await DataTransferService.getAppDataAsJson(
|
||||||
@@ -84,7 +77,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
),
|
),
|
||||||
SettingsListTile(
|
SettingsListTile(
|
||||||
title: loc.import_data,
|
title: loc.import_data,
|
||||||
icon: Icons.download,
|
icon: Icons.download_rounded,
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final result = await DataTransferService.importData(context);
|
final result = await DataTransferService.importData(context);
|
||||||
@@ -94,7 +87,7 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
),
|
),
|
||||||
SettingsListTile(
|
SettingsListTile(
|
||||||
title: loc.delete_all_data,
|
title: loc.delete_all_data,
|
||||||
icon: Icons.delete,
|
icon: Icons.delete_rounded,
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showDialog<bool>(
|
showDialog<bool>(
|
||||||
@@ -126,74 +119,11 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Padding(
|
|
||||||
padding: EdgeInsets.only(left: 16, top: 10, bottom: 10),
|
|
||||||
child: Text(
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
'App',
|
|
||||||
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SettingsListTile(
|
|
||||||
title: loc.licenses,
|
|
||||||
icon: Icons.insert_drive_file,
|
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).push(
|
|
||||||
MaterialPageRoute(builder: (context) => const LicensesView()),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(
|
child: Text(
|
||||||
spacing: 4,
|
|
||||||
children: [
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 12),
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
spacing: 40,
|
|
||||||
children: [
|
|
||||||
GestureDetector(
|
|
||||||
child: const Icon(Icons.language),
|
|
||||||
onTap: () => {
|
|
||||||
launchUrl(Uri.parse('https://liquid-dev.de')),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
child: const FaIcon(FontAwesomeIcons.github),
|
|
||||||
onTap: () => {
|
|
||||||
launchUrl(
|
|
||||||
Uri.parse(
|
|
||||||
'https://github.com/liquiddevelopmentde',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
GestureDetector(
|
|
||||||
child: Icon(
|
|
||||||
Platform.isIOS
|
|
||||||
? CupertinoIcons.mail_solid
|
|
||||||
: Icons.email,
|
|
||||||
),
|
|
||||||
onTap: () =>
|
|
||||||
launchUrl(Uri.parse('mailto:hi@liquid-dev.de')),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'© ${DateFormat('yyyy').format(DateTime.now())} Liquid Development',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.grey.shade600,
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'Version ${_packageInfo.version} (${_packageInfo.buildNumber})',
|
'Version ${_packageInfo.version} (${_packageInfo.buildNumber})',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.grey.shade600,
|
color: Colors.grey.shade600,
|
||||||
@@ -201,8 +131,6 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
|
|
||||||
|
|
||||||
class LicenseDetailView extends StatelessWidget {
|
|
||||||
final Package package;
|
|
||||||
|
|
||||||
const LicenseDetailView({super.key, required this.package});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final loc = AppLocalizations.of(context);
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(title: const Text('Lizenzdetails')),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Center(
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
margin: const EdgeInsetsGeometry.only(right: 15),
|
|
||||||
width: 60,
|
|
||||||
height: 60,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: CustomTheme.primaryColor.withAlpha(40),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
Icons.description,
|
|
||||||
color: CustomTheme.primaryColor,
|
|
||||||
size: 30,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
package.name,
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
style: const TextStyle(
|
|
||||||
height: 0,
|
|
||||||
fontSize: 24,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (package.version != null) ...[
|
|
||||||
Text(
|
|
||||||
'Version ${package.version}',
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Colors.grey.shade300,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
if (package.authors.isNotEmpty) ...[
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
SelectableText(
|
|
||||||
package.authors.join(', '),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Colors.grey.shade500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
if (package.homepage != null &&
|
|
||||||
package.homepage!.isNotEmpty) ...[
|
|
||||||
const SizedBox(height: 4),
|
|
||||||
SelectableText(
|
|
||||||
package.homepage!,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Colors.grey.shade500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
Container(
|
|
||||||
width: double.infinity,
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
|
|
||||||
decoration: CustomTheme.standardBoxDecoration,
|
|
||||||
child: (package.license != null && package.license!.isNotEmpty)
|
|
||||||
? SelectableText(
|
|
||||||
package.license!,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Colors.grey.shade300,
|
|
||||||
height: 1.5,
|
|
||||||
fontFamily: 'monospace',
|
|
||||||
),
|
|
||||||
)
|
|
||||||
: Center(
|
|
||||||
heightFactor: 25,
|
|
||||||
child: Text(
|
|
||||||
loc.no_license_text_available,
|
|
||||||
style: TextStyle(color: Colors.grey.shade500),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,32 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/license_tile.dart';
|
|
||||||
|
|
||||||
class LicensesView extends StatelessWidget {
|
|
||||||
const LicensesView({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final loc = AppLocalizations.of(context);
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(loc.licenses),
|
|
||||||
backgroundColor: CustomTheme.backgroundColor,
|
|
||||||
),
|
|
||||||
backgroundColor: CustomTheme.backgroundColor,
|
|
||||||
body: ListView.builder(
|
|
||||||
itemCount: allDependencies.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final package = allDependencies[index];
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
|
|
||||||
child: LicenseTile(package: package),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:game_tracker/core/custom_theme.dart';
|
||||||
|
|
||||||
/// A navigation bar item widget that represents a single tab in a navigation bar.
|
/// A navigation bar item widget that represents a single tab in a navigation bar.
|
||||||
/// - [index]: The index of the tab.
|
/// - [index]: The index of the tab.
|
||||||
@@ -35,7 +36,45 @@ class NavbarItem extends StatefulWidget {
|
|||||||
State<NavbarItem> createState() => _NavbarItemState();
|
State<NavbarItem> createState() => _NavbarItemState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _NavbarItemState extends State<NavbarItem> {
|
class _NavbarItemState extends State<NavbarItem>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
/// Animation controller for the scale animation
|
||||||
|
late AnimationController _animationController;
|
||||||
|
|
||||||
|
/// Scale animation for the icon when selected
|
||||||
|
late Animation<double> _scaleAnimation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_animationController = AnimationController(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
|
|
||||||
|
_scaleAnimation = Tween<double>(begin: 1.0, end: 1.2).animate(
|
||||||
|
CurvedAnimation(
|
||||||
|
parent: _animationController,
|
||||||
|
curve: Curves.easeInOutBack,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (widget.isSelected) {
|
||||||
|
_animationController.forward();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrigger animation on selection change
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(NavbarItem oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
if (widget.isSelected && !oldWidget.isSelected) {
|
||||||
|
_animationController.forward();
|
||||||
|
} else if (!widget.isSelected && oldWidget.isSelected) {
|
||||||
|
_animationController.reverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Expanded(
|
return Expanded(
|
||||||
@@ -48,19 +87,29 @@ class _NavbarItemState extends State<NavbarItem> {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
ScaleTransition(
|
||||||
|
scale: widget.isSelected
|
||||||
|
? _scaleAnimation
|
||||||
|
: const AlwaysStoppedAnimation(1.0),
|
||||||
|
child: Icon(
|
||||||
widget.icon,
|
widget.icon,
|
||||||
color: widget.isSelected ? Colors.white : Colors.black,
|
color: widget.isSelected
|
||||||
|
? CustomTheme.navBarItemSelectedColor
|
||||||
|
: CustomTheme.navBarItemUnselectedColor,
|
||||||
|
size: 26,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
widget.label,
|
widget.label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: widget.isSelected ? Colors.white : Colors.black,
|
color: widget.isSelected
|
||||||
fontSize: 12,
|
? CustomTheme.navBarItemSelectedColor
|
||||||
|
: CustomTheme.navBarItemUnselectedColor,
|
||||||
|
fontSize: widget.isSelected ? 12 : 11,
|
||||||
fontWeight: widget.isSelected
|
fontWeight: widget.isSelected
|
||||||
? FontWeight.bold
|
? FontWeight.bold
|
||||||
: FontWeight.normal,
|
: FontWeight.w500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -69,4 +118,10 @@ class _NavbarItemState extends State<NavbarItem> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_animationController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,106 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
|
|
||||||
|
|
||||||
class LicenseTile extends StatelessWidget {
|
|
||||||
final Package package;
|
|
||||||
|
|
||||||
const LicenseTile({super.key, required this.package});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
Navigator.of(context).push(
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => LicenseDetailView(package: package),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
margin: const EdgeInsets.only(bottom: 8),
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
decoration: CustomTheme.standardBoxDecoration.copyWith(
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
width: 48,
|
|
||||||
height: 48,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: CustomTheme.primaryColor.withAlpha(40),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
Icons.description,
|
|
||||||
color: CustomTheme.primaryColor,
|
|
||||||
size: 24,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
package.name,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
maxLines: 1,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (package.version != null &&
|
|
||||||
package.version!.isNotEmpty) ...[
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 8,
|
|
||||||
vertical: 2,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: CustomTheme.onBoxColor,
|
|
||||||
borderRadius: BorderRadius.circular(6),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
'v${package.version}',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 11,
|
|
||||||
color: Colors.grey.shade500,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 4),
|
|
||||||
Text(
|
|
||||||
package.description,
|
|
||||||
maxLines: 2,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 13,
|
|
||||||
color: Colors.grey.shade400,
|
|
||||||
height: 1.3,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 12),
|
|
||||||
// Arrow Icon
|
|
||||||
Icon(Icons.chevron_right, color: Colors.grey.shade600, size: 24),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -47,26 +47,13 @@ class SettingsListTile extends StatelessWidget {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
width: 48,
|
|
||||||
height: 48,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: CustomTheme.primaryColor.withAlpha(40),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
icon,
|
|
||||||
size: 28,
|
|
||||||
color: CustomTheme.primaryColor.withGreen(40),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
/* Container(
|
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: CustomTheme.primaryColor,
|
color: CustomTheme.primaryColor,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: Icon(icon, size: 24),
|
child: Icon(icon, size: 24),
|
||||||
),*/
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Text(title, style: const TextStyle(fontSize: 18)),
|
Text(title, style: const TextStyle(fontSize: 18)),
|
||||||
],
|
],
|
||||||
|
|||||||
27
pubspec.yaml
27
pubspec.yaml
@@ -1,7 +1,7 @@
|
|||||||
name: game_tracker
|
name: game_tracker
|
||||||
description: "Game Tracking App for Card Games"
|
description: "Game Tracking App for Card Games"
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
version: 0.0.5+127
|
version: 0.0.1+149
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.8.1
|
sdk: ^3.8.1
|
||||||
@@ -9,32 +9,27 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_localizations:
|
|
||||||
sdk: flutter
|
|
||||||
clock: ^1.1.2
|
|
||||||
cupertino_icons: ^1.0.6
|
|
||||||
drift: ^2.27.0
|
drift: ^2.27.0
|
||||||
drift_flutter: ^0.2.4
|
drift_flutter: ^0.2.4
|
||||||
file_picker: ^10.3.6
|
|
||||||
file_saver: ^0.3.1
|
|
||||||
font_awesome_flutter: ^10.12.0
|
|
||||||
intl: any
|
|
||||||
json_schema: ^5.2.2
|
|
||||||
package_info_plus: ^9.0.0
|
|
||||||
path_provider: ^2.1.5
|
path_provider: ^2.1.5
|
||||||
provider: ^6.1.5
|
provider: ^6.1.5
|
||||||
skeletonizer: ^2.1.0+1
|
skeletonizer: ^2.1.0+1
|
||||||
url_launcher: ^6.3.2
|
|
||||||
uuid: ^4.5.2
|
uuid: ^4.5.2
|
||||||
|
file_picker: ^10.3.6
|
||||||
|
json_schema: ^5.2.2
|
||||||
|
file_saver: ^0.3.1
|
||||||
|
clock: ^1.1.2
|
||||||
|
intl: any
|
||||||
|
flutter_localizations:
|
||||||
|
sdk: flutter
|
||||||
|
package_info_plus: ^9.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
build_runner: ^2.5.4
|
|
||||||
dart_pubspec_licenses: ^3.0.14
|
|
||||||
drift_dev: ^2.27.0
|
|
||||||
flutter_lints: ^5.0.0
|
flutter_lints: ^5.0.0
|
||||||
|
drift_dev: ^2.27.0
|
||||||
|
build_runner: ^2.5.4
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
uses-material-design: true
|
uses-material-design: true
|
||||||
|
|||||||
Reference in New Issue
Block a user