Merge branch 'refs/heads/development' into enhancement/81-readme-vervollstaendigen
@@ -6,23 +6,17 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install jq
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y jq
|
|
||||||
|
|
||||||
- name: Install Flutter (wget)
|
- name: Install Flutter (wget)
|
||||||
run: |
|
run: |
|
||||||
wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
|
wget --show-progress --progress=bar:force:noscroll:giga https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
|
||||||
tar xf flutter_linux_3.38.2-stable.tar.xz
|
tar xf flutter_linux_3.38.2-stable.tar.xz
|
||||||
# Set Git safe directory for Flutter path
|
|
||||||
git config --global --add safe.directory "$(pwd)/flutter"
|
git config --global --add safe.directory "$(pwd)/flutter"
|
||||||
# Set Flutter path
|
echo "$(pwd)/flutter/bin" >> $GITEA_PATH
|
||||||
echo "$(pwd)/flutter/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Get dependencies
|
- name: Get dependencies
|
||||||
run: flutter pub get
|
run: flutter pub get
|
||||||
@@ -32,26 +26,22 @@ jobs:
|
|||||||
|
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
RUNNER_TOOL_CACHE: /toolcache
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y jq
|
|
||||||
|
|
||||||
- name: Install Flutter (wget)
|
- name: Install Flutter (wget)
|
||||||
run: |
|
run: |
|
||||||
wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
|
wget --show-progress --progress=bar:force:noscroll:giga https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
|
||||||
tar xf flutter_linux_3.38.2-stable.tar.xz
|
tar xf flutter_linux_3.38.2-stable.tar.xz
|
||||||
# Set Git safe directory for Flutter path
|
|
||||||
git config --global --add safe.directory "$(pwd)/flutter"
|
git config --global --add safe.directory "$(pwd)/flutter"
|
||||||
# Set Flutter path
|
echo "$(pwd)/flutter/bin" >> $GITEA_PATH
|
||||||
echo "$(pwd)/flutter/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Get dependencies
|
- name: Get dependencies
|
||||||
run: flutter pub get
|
run: flutter pub get
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: flutter test
|
run: flutter test
|
||||||
|
|||||||
@@ -7,44 +7,95 @@ on:
|
|||||||
- "main"
|
- "main"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
format:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: false # Needs bot user
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install Flutter (wget)
|
||||||
run: |
|
run: |
|
||||||
apt-get update
|
wget --show-progress --progress=bar:force:noscroll:giga https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
|
||||||
apt-get install -y jq
|
tar xf flutter_linux_3.38.2-stable.tar.xz
|
||||||
|
git config --global --add safe.directory "$(pwd)/flutter"
|
||||||
|
echo "$(pwd)/flutter/bin" >> $GITEA_PATH
|
||||||
|
|
||||||
|
- name: Get dependencies
|
||||||
|
run: flutter pub get
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: flutter test
|
||||||
|
|
||||||
|
format:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Flutter (wget)
|
- name: Install Flutter (wget)
|
||||||
run: |
|
run: |
|
||||||
wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
|
wget --show-progress --progress=bar:force:noscroll:giga https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.38.2-stable.tar.xz
|
||||||
tar xf flutter_linux_3.38.2-stable.tar.xz
|
tar xf flutter_linux_3.38.2-stable.tar.xz
|
||||||
# Set Git safe directory for Flutter path
|
|
||||||
git config --global --add safe.directory "$(pwd)/flutter"
|
git config --global --add safe.directory "$(pwd)/flutter"
|
||||||
# Set Flutter path
|
echo "$(pwd)/flutter/bin" >> $GITEA_PATH
|
||||||
echo "$(pwd)/flutter/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Get & upgrade dependencies
|
- name: Get dependencies
|
||||||
run: |
|
run: flutter pub get
|
||||||
flutter pub get
|
|
||||||
flutter pub upgrade --major-versions
|
|
||||||
|
|
||||||
- name: Auto-format
|
- name: Check code format
|
||||||
run: |
|
id: check_format
|
||||||
dart format lib
|
continue-on-error: true
|
||||||
dart fix --apply lib
|
run: flutter analyze lib test
|
||||||
|
|
||||||
# Needs credentials, push access and the right files need to be staged
|
- name: Format code
|
||||||
- name: Commit Changes
|
if: steps.check_format.outcome == 'failure'
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
git config --global user.name "Gitea Actions"
|
git fetch origin ${{ gitea.ref_name }}
|
||||||
git config --global user.email "actions@gitea.com"
|
git checkout ${{ gitea.ref_name }}
|
||||||
git status
|
|
||||||
git add lib/
|
dart fix --apply lib
|
||||||
git status
|
dart fix --apply test
|
||||||
git commit -m "Actions: Auto-formatting [skip ci]"
|
|
||||||
git push
|
if [ -n "$(git status --porcelain lib test)" ]; then
|
||||||
|
git config --global user.name "Gitea Actions [bot]"
|
||||||
|
git config --global user.email "actions@yannick-weigert.de"
|
||||||
|
git add lib test
|
||||||
|
git commit -m "Auto-format code [skip ci]"
|
||||||
|
git push origin HEAD:${{ gitea.ref_name }}
|
||||||
|
else
|
||||||
|
echo "No changes to commit"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Verify format
|
||||||
|
run: flutter analyze lib test
|
||||||
|
|
||||||
|
update_version:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: format
|
||||||
|
if: gitea.ref == 'refs/heads/development'
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
token: ${{ secrets.BOT_TOKEN }}
|
||||||
|
ref: ${{ gitea.ref_name }}
|
||||||
|
|
||||||
|
- name: Increment version number
|
||||||
|
uses: https://github.com/stikkyapp/update-pubspec-version@v2
|
||||||
|
with:
|
||||||
|
strategy: 'patch'
|
||||||
|
path: './pubspec.yaml'
|
||||||
|
|
||||||
|
|
||||||
|
- name: Commit version update
|
||||||
|
env:
|
||||||
|
GITEA_TOKEN: ${{ secrets.BOT_TOKEN }}
|
||||||
|
run: |
|
||||||
|
git config --global user.name "Gitea Actions [bot]"
|
||||||
|
git config --global user.email "actions@yannick-weigert.de"
|
||||||
|
git add pubspec.yaml
|
||||||
|
git commit -m "Updated version number [skip ci]"
|
||||||
|
git push origin HEAD:${{ gitea.ref_name }}
|
||||||
@@ -10,4 +10,5 @@ linter:
|
|||||||
prefer_const_declarations: true
|
prefer_const_declarations: true
|
||||||
prefer_const_literals_to_create_immutables: true
|
prefer_const_literals_to_create_immutables: true
|
||||||
unnecessary_const: true
|
unnecessary_const: true
|
||||||
lines_longer_than_80_chars: false
|
lines_longer_than_80_chars: false
|
||||||
|
constant_identifier_names: false
|
||||||
@@ -6,7 +6,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.example.game_tracker"
|
namespace = "de.liquid.tallee"
|
||||||
compileSdk = flutter.compileSdkVersion
|
compileSdk = flutter.compileSdkVersion
|
||||||
ndkVersion = flutter.ndkVersion
|
ndkVersion = flutter.ndkVersion
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId = "com.example.game_tracker"
|
applicationId = "de.liquid.tallee"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||||
minSdk = flutter.minSdkVersion
|
minSdk = flutter.minSdkVersion
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<application
|
<application
|
||||||
android:label="game_tracker"
|
android:label="Tallee"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 17 KiB |
@@ -1,4 +1,4 @@
|
|||||||
package com.example.game_tracker
|
package de.liquid.tallee
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 828 B After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 448 B After Width: | Height: | Size: 884 B |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 656 B After Width: | Height: | Size: 938 B |
|
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 596 B |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 508 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 704 B After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 824 B After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 9.0 KiB |
@@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="app_icon_background">#E6F1E4</color>
|
<color name="launch_background">#ef681f</color>
|
||||||
<color name="launch_background">#0B0B0B</color>
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Referenz unbedingt als @color/launch_background (nicht @colors/...) -->
|
<color name="ic_launcher_background">#EF681F</color>
|
||||||
<color name="ic_launcher_background">@color/app_icon_background</color>
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -152,7 +152,6 @@
|
|||||||
B68CF4A64F0B5E45B43D6900 /* Pods-RunnerTests.release.xcconfig */,
|
B68CF4A64F0B5E45B43D6900 /* Pods-RunnerTests.release.xcconfig */,
|
||||||
E754D1191B3E54E52B6DCC49 /* Pods-RunnerTests.profile.xcconfig */,
|
E754D1191B3E54E52B6DCC49 /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
name = Pods;
|
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -478,7 +477,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.gameTracker;
|
PRODUCT_BUNDLE_IDENTIFIER = de.liquid.tallee;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -661,7 +660,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.gameTracker;
|
PRODUCT_BUNDLE_IDENTIFIER = de.liquid.tallee;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
@@ -684,7 +683,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.gameTracker;
|
PRODUCT_BUNDLE_IDENTIFIER = de.liquid.tallee;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
|||||||
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
@@ -1,14 +1 @@
|
|||||||
{
|
{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"}]}
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "icon_x1024.png",
|
|
||||||
"idiom" : "universal",
|
|
||||||
"platform" : "ios",
|
|
||||||
"size" : "1024x1024"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 8.8 KiB |
@@ -5,9 +5,9 @@
|
|||||||
"color-space" : "srgb",
|
"color-space" : "srgb",
|
||||||
"components" : {
|
"components" : {
|
||||||
"alpha" : "1.000",
|
"alpha" : "1.000",
|
||||||
"blue" : "0.043",
|
"blue" : "0.122",
|
||||||
"green" : "0.043",
|
"green" : "0.408",
|
||||||
"red" : "0.043"
|
"red" : "0.937"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"idiom" : "universal"
|
"idiom" : "universal"
|
||||||
@@ -1,17 +1,8 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"filename" : "icon.png",
|
"filename" : "icon-transparent.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal"
|
||||||
"scale" : "1x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "2x"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idiom" : "universal",
|
|
||||||
"scale" : "3x"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
BIN
ios/Runner/Assets.xcassets/LauncherIcon.imageset/icon-transparent.png
vendored
Normal file
|
After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24412" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24405"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
|
||||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -20,12 +20,19 @@
|
|||||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Tallee" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="m4u-iU-Cmv">
|
||||||
|
<rect key="frame" x="153" y="747" width="87" height="37"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<fontDescription key="fontDescription" name="Futura-Bold" family="Futura" pointSize="28"/>
|
||||||
|
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="LauncherIcon" translatesAutoresizingMaskIntoConstraints="NO" id="ygV-Op-Bu5">
|
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="LauncherIcon" translatesAutoresizingMaskIntoConstraints="NO" id="ygV-Op-Bu5">
|
||||||
<rect key="frame" x="46" y="334" width="301" height="184"/>
|
<rect key="frame" x="46" y="334" width="301" height="184"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
</imageView>
|
</imageView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" name="LauncherBackgroundColor"/>
|
<color key="backgroundColor" name="LauncherColor"/>
|
||||||
</view>
|
</view>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
@@ -36,8 +43,8 @@
|
|||||||
<color key="tintColor" red="0.90196078431372551" green="0.94509803921568625" blue="0.89411764705882346" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="tintColor" red="0.90196078431372551" green="0.94509803921568625" blue="0.89411764705882346" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="LauncherIcon" width="1000" height="1000"/>
|
<image name="LauncherIcon" width="1000" height="1000"/>
|
||||||
<namedColor name="LauncherBackgroundColor">
|
<namedColor name="LauncherColor">
|
||||||
<color red="0.90196078431372551" green="0.94509803921568625" blue="0.89411764705882346" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color red="0.93699997663497925" green="0.40799999237060547" blue="0.12200000137090683" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</namedColor>
|
</namedColor>
|
||||||
</resources>
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
|
<true/>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Game Tracker</string>
|
<string>Tallee</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
@@ -13,7 +15,7 @@
|
|||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>game_tracker</string>
|
<string>tallee</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
@@ -22,13 +24,15 @@
|
|||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
|
<key>LSApplicationQueriesSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>https</string>
|
||||||
|
<string>http</string>
|
||||||
|
</array>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>LSApplicationQueriesSchemes</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<array>
|
<true/>
|
||||||
<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>
|
||||||
@@ -44,9 +48,5 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
|
||||||
<true/>
|
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Returns a platform-adaptive page route based on the current platform.
|
||||||
|
/// - On iOS, it returns a [CupertinoPageRoute].
|
||||||
|
/// - On other platforms, it returns a [MaterialPageRoute].
|
||||||
Route<T> adaptivePageRoute<T>({
|
Route<T> adaptivePageRoute<T>({
|
||||||
required Widget Function(BuildContext) builder,
|
required Widget Function(BuildContext) builder,
|
||||||
bool fullscreenDialog = false,
|
bool fullscreenDialog = false,
|
||||||
|
|||||||
@@ -1,6 +1,22 @@
|
|||||||
|
/// Application-wide constants
|
||||||
class Constants {
|
class Constants {
|
||||||
Constants._(); // Private constructor to prevent instantiation
|
Constants._(); // Private constructor to prevent instantiation
|
||||||
|
|
||||||
/// Minimum duration of all app skeletons
|
/// Minimum duration of all app skeletons
|
||||||
static Duration minimumSkeletonDuration = const Duration(milliseconds: 250);
|
static const Duration MINIMUM_SKELETON_DURATION = Duration(milliseconds: 250);
|
||||||
|
|
||||||
|
/// Maximum length for player names
|
||||||
|
static const int MAX_PLAYER_NAME_LENGTH = 32;
|
||||||
|
|
||||||
|
/// Maximum length for group names
|
||||||
|
static const int MAX_GROUP_NAME_LENGTH = 32;
|
||||||
|
|
||||||
|
/// Maximum length for match names
|
||||||
|
static const int MAX_MATCH_NAME_LENGTH = 32;
|
||||||
|
|
||||||
|
/// Maximum length for game names
|
||||||
|
static const int MAX_GAME_NAME_LENGTH = 32;
|
||||||
|
|
||||||
|
/// Maximum length for team names
|
||||||
|
static const int MAX_TEAM_NAME_LENGTH = 32;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,37 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
/// Theme class that defines colors, border radius, padding, and decorations
|
||||||
class CustomTheme {
|
class CustomTheme {
|
||||||
CustomTheme._(); // Private constructor to prevent instantiation
|
CustomTheme._(); // Private constructor to prevent instantiation
|
||||||
|
|
||||||
// ==================== Colors ====================
|
// ==================== Colors ====================
|
||||||
static Color primaryColor = const Color(0xFF7505E4);
|
|
||||||
static Color secondaryColor = const Color(0xFFAFA2FF);
|
/// Primary color of the app theme
|
||||||
static Color backgroundColor = const Color(0xFF0B0B0B);
|
static const Color primaryColor = Color(0xFFef681f);
|
||||||
static Color boxColor = const Color(0xFF101010);
|
|
||||||
static Color onBoxColor = const Color(0xFF181818);
|
/// Secondary color of the app theme
|
||||||
static Color boxBorder = const Color(0xFF272727);
|
static const Color secondaryColor = Color(0xFFf2a981);
|
||||||
static const Color textColor = Colors.white;
|
|
||||||
|
/// Background color of the app theme
|
||||||
|
static const backgroundColor = Color(0xFF0B0B0B);
|
||||||
|
|
||||||
|
/// Default color for boxes and containers
|
||||||
|
static const Color boxColor = Color(0xFF101010);
|
||||||
|
|
||||||
|
/// Default border color for boxes and containers
|
||||||
|
static const Color boxBorder = Color(0xFF272727);
|
||||||
|
|
||||||
|
/// Color for boxes and containers displayed on boxes
|
||||||
|
static const Color onBoxColor = Color(0xFF181818);
|
||||||
|
|
||||||
|
/// Text color used throughout the app
|
||||||
|
static const Color textColor = Color(0xFFFFFFFF);
|
||||||
|
|
||||||
|
/// Selected color for the [NavbarItem]
|
||||||
|
static Color navBarItemSelectedColor = primaryColor.withGreen(100);
|
||||||
|
|
||||||
|
/// Unselected color for the [NavbarItem]
|
||||||
|
static Color navBarItemUnselectedColor = Colors.grey.shade400;
|
||||||
|
|
||||||
// ==================== Border Radius ====================
|
// ==================== Border Radius ====================
|
||||||
static const double standardBorderRadius = 12.0;
|
static const double standardBorderRadius = 12.0;
|
||||||
@@ -42,18 +63,18 @@ class CustomTheme {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// ==================== App Bar Theme ====================
|
// ==================== App Bar Theme ====================
|
||||||
static AppBarTheme appBarTheme = AppBarTheme(
|
static const AppBarTheme appBarTheme = AppBarTheme(
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
foregroundColor: textColor,
|
foregroundColor: textColor,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
scrolledUnderElevation: 0,
|
scrolledUnderElevation: 0,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
titleTextStyle: const TextStyle(
|
titleTextStyle: TextStyle(
|
||||||
color: textColor,
|
color: textColor,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
iconTheme: const IconThemeData(color: textColor),
|
iconTheme: IconThemeData(color: textColor),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
|
||||||
/// Button types used for styling the [CustomWidthButton]
|
/// Button types used for styling the [CustomWidthButton]
|
||||||
/// - [ButtonType.primary]: Primary button style.
|
/// - [ButtonType.primary]: Primary button style.
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
import 'package:tallee/data/db/database.dart';
|
||||||
import 'package:game_tracker/data/db/tables/group_table.dart';
|
import 'package:tallee/data/db/tables/group_table.dart';
|
||||||
import 'package:game_tracker/data/db/tables/player_group_table.dart';
|
import 'package:tallee/data/db/tables/player_group_table.dart';
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
import 'package:tallee/data/dto/group.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
|
||||||
part 'group_dao.g.dart';
|
part 'group_dao.g.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
import 'package:tallee/data/db/database.dart';
|
||||||
import 'package:game_tracker/data/db/tables/group_match_table.dart';
|
import 'package:tallee/data/db/tables/group_match_table.dart';
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
import 'package:tallee/data/dto/group.dart';
|
||||||
|
|
||||||
part 'group_match_dao.g.dart';
|
part 'group_match_dao.g.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
import 'package:tallee/data/db/database.dart';
|
||||||
import 'package:game_tracker/data/db/tables/match_table.dart';
|
import 'package:tallee/data/db/tables/match_table.dart';
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
import 'package:tallee/data/dto/group.dart';
|
||||||
import 'package:game_tracker/data/dto/match.dart';
|
import 'package:tallee/data/dto/match.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
|
||||||
part 'match_dao.g.dart';
|
part 'match_dao.g.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
import 'package:tallee/data/db/database.dart';
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
import 'package:tallee/data/db/tables/player_table.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
|
||||||
part 'player_dao.g.dart';
|
part 'player_dao.g.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
import 'package:tallee/data/db/database.dart';
|
||||||
import 'package:game_tracker/data/db/tables/player_group_table.dart';
|
import 'package:tallee/data/db/tables/player_group_table.dart';
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
import 'package:tallee/data/db/tables/player_table.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
|
||||||
part 'player_group_dao.g.dart';
|
part 'player_group_dao.g.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
import 'package:tallee/data/db/database.dart';
|
||||||
import 'package:game_tracker/data/db/tables/player_match_table.dart';
|
import 'package:tallee/data/db/tables/player_match_table.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
|
||||||
part 'player_match_dao.g.dart';
|
part 'player_match_dao.g.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:drift_flutter/drift_flutter.dart';
|
import 'package:drift_flutter/drift_flutter.dart';
|
||||||
import 'package:game_tracker/data/dao/group_dao.dart';
|
|
||||||
import 'package:game_tracker/data/dao/group_match_dao.dart';
|
|
||||||
import 'package:game_tracker/data/dao/match_dao.dart';
|
|
||||||
import 'package:game_tracker/data/dao/player_dao.dart';
|
|
||||||
import 'package:game_tracker/data/dao/player_group_dao.dart';
|
|
||||||
import 'package:game_tracker/data/dao/player_match_dao.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/group_match_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/group_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/match_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_group_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_match_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:tallee/data/dao/group_dao.dart';
|
||||||
|
import 'package:tallee/data/dao/group_match_dao.dart';
|
||||||
|
import 'package:tallee/data/dao/match_dao.dart';
|
||||||
|
import 'package:tallee/data/dao/player_dao.dart';
|
||||||
|
import 'package:tallee/data/dao/player_group_dao.dart';
|
||||||
|
import 'package:tallee/data/dao/player_match_dao.dart';
|
||||||
|
import 'package:tallee/data/db/tables/group_match_table.dart';
|
||||||
|
import 'package:tallee/data/db/tables/group_table.dart';
|
||||||
|
import 'package:tallee/data/db/tables/match_table.dart';
|
||||||
|
import 'package:tallee/data/db/tables/player_group_table.dart';
|
||||||
|
import 'package:tallee/data/db/tables/player_match_table.dart';
|
||||||
|
import 'package:tallee/data/db/tables/player_table.dart';
|
||||||
|
|
||||||
part 'database.g.dart';
|
part 'database.g.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -527,6 +527,17 @@ class $MatchTableTable extends MatchTable
|
|||||||
final GeneratedDatabase attachedDatabase;
|
final GeneratedDatabase attachedDatabase;
|
||||||
final String? _alias;
|
final String? _alias;
|
||||||
$MatchTableTable(this.attachedDatabase, [this._alias]);
|
$MatchTableTable(this.attachedDatabase, [this._alias]);
|
||||||
|
static const VerificationMeta _winnerIdMeta = const VerificationMeta(
|
||||||
|
'winnerId',
|
||||||
|
);
|
||||||
|
@override
|
||||||
|
late final GeneratedColumn<String> winnerId = GeneratedColumn<String>(
|
||||||
|
'winner_id',
|
||||||
|
aliasedName,
|
||||||
|
true,
|
||||||
|
type: DriftSqlType.string,
|
||||||
|
requiredDuringInsert: false,
|
||||||
|
);
|
||||||
static const VerificationMeta _idMeta = const VerificationMeta('id');
|
static const VerificationMeta _idMeta = const VerificationMeta('id');
|
||||||
@override
|
@override
|
||||||
late final GeneratedColumn<String> id = GeneratedColumn<String>(
|
late final GeneratedColumn<String> id = GeneratedColumn<String>(
|
||||||
@@ -545,17 +556,6 @@ class $MatchTableTable extends MatchTable
|
|||||||
type: DriftSqlType.string,
|
type: DriftSqlType.string,
|
||||||
requiredDuringInsert: true,
|
requiredDuringInsert: true,
|
||||||
);
|
);
|
||||||
static const VerificationMeta _winnerIdMeta = const VerificationMeta(
|
|
||||||
'winnerId',
|
|
||||||
);
|
|
||||||
@override
|
|
||||||
late final GeneratedColumn<String> winnerId = GeneratedColumn<String>(
|
|
||||||
'winner_id',
|
|
||||||
aliasedName,
|
|
||||||
true,
|
|
||||||
type: DriftSqlType.string,
|
|
||||||
requiredDuringInsert: false,
|
|
||||||
);
|
|
||||||
static const VerificationMeta _createdAtMeta = const VerificationMeta(
|
static const VerificationMeta _createdAtMeta = const VerificationMeta(
|
||||||
'createdAt',
|
'createdAt',
|
||||||
);
|
);
|
||||||
@@ -568,7 +568,7 @@ class $MatchTableTable extends MatchTable
|
|||||||
requiredDuringInsert: true,
|
requiredDuringInsert: true,
|
||||||
);
|
);
|
||||||
@override
|
@override
|
||||||
List<GeneratedColumn> get $columns => [id, name, winnerId, createdAt];
|
List<GeneratedColumn> get $columns => [winnerId, id, name, createdAt];
|
||||||
@override
|
@override
|
||||||
String get aliasedName => _alias ?? actualTableName;
|
String get aliasedName => _alias ?? actualTableName;
|
||||||
@override
|
@override
|
||||||
@@ -581,6 +581,12 @@ class $MatchTableTable extends MatchTable
|
|||||||
}) {
|
}) {
|
||||||
final context = VerificationContext();
|
final context = VerificationContext();
|
||||||
final data = instance.toColumns(true);
|
final data = instance.toColumns(true);
|
||||||
|
if (data.containsKey('winner_id')) {
|
||||||
|
context.handle(
|
||||||
|
_winnerIdMeta,
|
||||||
|
winnerId.isAcceptableOrUnknown(data['winner_id']!, _winnerIdMeta),
|
||||||
|
);
|
||||||
|
}
|
||||||
if (data.containsKey('id')) {
|
if (data.containsKey('id')) {
|
||||||
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
|
context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
|
||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
@@ -594,12 +600,6 @@ class $MatchTableTable extends MatchTable
|
|||||||
} else if (isInserting) {
|
} else if (isInserting) {
|
||||||
context.missing(_nameMeta);
|
context.missing(_nameMeta);
|
||||||
}
|
}
|
||||||
if (data.containsKey('winner_id')) {
|
|
||||||
context.handle(
|
|
||||||
_winnerIdMeta,
|
|
||||||
winnerId.isAcceptableOrUnknown(data['winner_id']!, _winnerIdMeta),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (data.containsKey('created_at')) {
|
if (data.containsKey('created_at')) {
|
||||||
context.handle(
|
context.handle(
|
||||||
_createdAtMeta,
|
_createdAtMeta,
|
||||||
@@ -617,6 +617,10 @@ class $MatchTableTable extends MatchTable
|
|||||||
MatchTableData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
MatchTableData map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||||
return MatchTableData(
|
return MatchTableData(
|
||||||
|
winnerId: attachedDatabase.typeMapping.read(
|
||||||
|
DriftSqlType.string,
|
||||||
|
data['${effectivePrefix}winner_id'],
|
||||||
|
),
|
||||||
id: attachedDatabase.typeMapping.read(
|
id: attachedDatabase.typeMapping.read(
|
||||||
DriftSqlType.string,
|
DriftSqlType.string,
|
||||||
data['${effectivePrefix}id'],
|
data['${effectivePrefix}id'],
|
||||||
@@ -625,10 +629,6 @@ class $MatchTableTable extends MatchTable
|
|||||||
DriftSqlType.string,
|
DriftSqlType.string,
|
||||||
data['${effectivePrefix}name'],
|
data['${effectivePrefix}name'],
|
||||||
)!,
|
)!,
|
||||||
winnerId: attachedDatabase.typeMapping.read(
|
|
||||||
DriftSqlType.string,
|
|
||||||
data['${effectivePrefix}winner_id'],
|
|
||||||
),
|
|
||||||
createdAt: attachedDatabase.typeMapping.read(
|
createdAt: attachedDatabase.typeMapping.read(
|
||||||
DriftSqlType.dateTime,
|
DriftSqlType.dateTime,
|
||||||
data['${effectivePrefix}created_at'],
|
data['${effectivePrefix}created_at'],
|
||||||
@@ -643,35 +643,35 @@ class $MatchTableTable extends MatchTable
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MatchTableData extends DataClass implements Insertable<MatchTableData> {
|
class MatchTableData extends DataClass implements Insertable<MatchTableData> {
|
||||||
|
final String? winnerId;
|
||||||
final String id;
|
final String id;
|
||||||
final String name;
|
final String name;
|
||||||
final String? winnerId;
|
|
||||||
final DateTime createdAt;
|
final DateTime createdAt;
|
||||||
const MatchTableData({
|
const MatchTableData({
|
||||||
|
this.winnerId,
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.name,
|
required this.name,
|
||||||
this.winnerId,
|
|
||||||
required this.createdAt,
|
required this.createdAt,
|
||||||
});
|
});
|
||||||
@override
|
@override
|
||||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||||
final map = <String, Expression>{};
|
final map = <String, Expression>{};
|
||||||
map['id'] = Variable<String>(id);
|
|
||||||
map['name'] = Variable<String>(name);
|
|
||||||
if (!nullToAbsent || winnerId != null) {
|
if (!nullToAbsent || winnerId != null) {
|
||||||
map['winner_id'] = Variable<String>(winnerId);
|
map['winner_id'] = Variable<String>(winnerId);
|
||||||
}
|
}
|
||||||
|
map['id'] = Variable<String>(id);
|
||||||
|
map['name'] = Variable<String>(name);
|
||||||
map['created_at'] = Variable<DateTime>(createdAt);
|
map['created_at'] = Variable<DateTime>(createdAt);
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchTableCompanion toCompanion(bool nullToAbsent) {
|
MatchTableCompanion toCompanion(bool nullToAbsent) {
|
||||||
return MatchTableCompanion(
|
return MatchTableCompanion(
|
||||||
id: Value(id),
|
|
||||||
name: Value(name),
|
|
||||||
winnerId: winnerId == null && nullToAbsent
|
winnerId: winnerId == null && nullToAbsent
|
||||||
? const Value.absent()
|
? const Value.absent()
|
||||||
: Value(winnerId),
|
: Value(winnerId),
|
||||||
|
id: Value(id),
|
||||||
|
name: Value(name),
|
||||||
createdAt: Value(createdAt),
|
createdAt: Value(createdAt),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -682,9 +682,9 @@ class MatchTableData extends DataClass implements Insertable<MatchTableData> {
|
|||||||
}) {
|
}) {
|
||||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||||
return MatchTableData(
|
return MatchTableData(
|
||||||
|
winnerId: serializer.fromJson<String?>(json['winnerId']),
|
||||||
id: serializer.fromJson<String>(json['id']),
|
id: serializer.fromJson<String>(json['id']),
|
||||||
name: serializer.fromJson<String>(json['name']),
|
name: serializer.fromJson<String>(json['name']),
|
||||||
winnerId: serializer.fromJson<String?>(json['winnerId']),
|
|
||||||
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
|
createdAt: serializer.fromJson<DateTime>(json['createdAt']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -692,29 +692,29 @@ class MatchTableData extends DataClass implements Insertable<MatchTableData> {
|
|||||||
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
Map<String, dynamic> toJson({ValueSerializer? serializer}) {
|
||||||
serializer ??= driftRuntimeOptions.defaultSerializer;
|
serializer ??= driftRuntimeOptions.defaultSerializer;
|
||||||
return <String, dynamic>{
|
return <String, dynamic>{
|
||||||
|
'winnerId': serializer.toJson<String?>(winnerId),
|
||||||
'id': serializer.toJson<String>(id),
|
'id': serializer.toJson<String>(id),
|
||||||
'name': serializer.toJson<String>(name),
|
'name': serializer.toJson<String>(name),
|
||||||
'winnerId': serializer.toJson<String?>(winnerId),
|
|
||||||
'createdAt': serializer.toJson<DateTime>(createdAt),
|
'createdAt': serializer.toJson<DateTime>(createdAt),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchTableData copyWith({
|
MatchTableData copyWith({
|
||||||
|
Value<String?> winnerId = const Value.absent(),
|
||||||
String? id,
|
String? id,
|
||||||
String? name,
|
String? name,
|
||||||
Value<String?> winnerId = const Value.absent(),
|
|
||||||
DateTime? createdAt,
|
DateTime? createdAt,
|
||||||
}) => MatchTableData(
|
}) => MatchTableData(
|
||||||
|
winnerId: winnerId.present ? winnerId.value : this.winnerId,
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
winnerId: winnerId.present ? winnerId.value : this.winnerId,
|
|
||||||
createdAt: createdAt ?? this.createdAt,
|
createdAt: createdAt ?? this.createdAt,
|
||||||
);
|
);
|
||||||
MatchTableData copyWithCompanion(MatchTableCompanion data) {
|
MatchTableData copyWithCompanion(MatchTableCompanion data) {
|
||||||
return MatchTableData(
|
return MatchTableData(
|
||||||
|
winnerId: data.winnerId.present ? data.winnerId.value : this.winnerId,
|
||||||
id: data.id.present ? data.id.value : this.id,
|
id: data.id.present ? data.id.value : this.id,
|
||||||
name: data.name.present ? data.name.value : this.name,
|
name: data.name.present ? data.name.value : this.name,
|
||||||
winnerId: data.winnerId.present ? data.winnerId.value : this.winnerId,
|
|
||||||
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -722,75 +722,75 @@ class MatchTableData extends DataClass implements Insertable<MatchTableData> {
|
|||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return (StringBuffer('MatchTableData(')
|
return (StringBuffer('MatchTableData(')
|
||||||
|
..write('winnerId: $winnerId, ')
|
||||||
..write('id: $id, ')
|
..write('id: $id, ')
|
||||||
..write('name: $name, ')
|
..write('name: $name, ')
|
||||||
..write('winnerId: $winnerId, ')
|
|
||||||
..write('createdAt: $createdAt')
|
..write('createdAt: $createdAt')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(id, name, winnerId, createdAt);
|
int get hashCode => Object.hash(winnerId, id, name, createdAt);
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
(other is MatchTableData &&
|
(other is MatchTableData &&
|
||||||
|
other.winnerId == this.winnerId &&
|
||||||
other.id == this.id &&
|
other.id == this.id &&
|
||||||
other.name == this.name &&
|
other.name == this.name &&
|
||||||
other.winnerId == this.winnerId &&
|
|
||||||
other.createdAt == this.createdAt);
|
other.createdAt == this.createdAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MatchTableCompanion extends UpdateCompanion<MatchTableData> {
|
class MatchTableCompanion extends UpdateCompanion<MatchTableData> {
|
||||||
|
final Value<String?> winnerId;
|
||||||
final Value<String> id;
|
final Value<String> id;
|
||||||
final Value<String> name;
|
final Value<String> name;
|
||||||
final Value<String?> winnerId;
|
|
||||||
final Value<DateTime> createdAt;
|
final Value<DateTime> createdAt;
|
||||||
final Value<int> rowid;
|
final Value<int> rowid;
|
||||||
const MatchTableCompanion({
|
const MatchTableCompanion({
|
||||||
|
this.winnerId = const Value.absent(),
|
||||||
this.id = const Value.absent(),
|
this.id = const Value.absent(),
|
||||||
this.name = const Value.absent(),
|
this.name = const Value.absent(),
|
||||||
this.winnerId = const Value.absent(),
|
|
||||||
this.createdAt = const Value.absent(),
|
this.createdAt = const Value.absent(),
|
||||||
this.rowid = const Value.absent(),
|
this.rowid = const Value.absent(),
|
||||||
});
|
});
|
||||||
MatchTableCompanion.insert({
|
MatchTableCompanion.insert({
|
||||||
|
this.winnerId = const Value.absent(),
|
||||||
required String id,
|
required String id,
|
||||||
required String name,
|
required String name,
|
||||||
this.winnerId = const Value.absent(),
|
|
||||||
required DateTime createdAt,
|
required DateTime createdAt,
|
||||||
this.rowid = const Value.absent(),
|
this.rowid = const Value.absent(),
|
||||||
}) : id = Value(id),
|
}) : id = Value(id),
|
||||||
name = Value(name),
|
name = Value(name),
|
||||||
createdAt = Value(createdAt);
|
createdAt = Value(createdAt);
|
||||||
static Insertable<MatchTableData> custom({
|
static Insertable<MatchTableData> custom({
|
||||||
|
Expression<String>? winnerId,
|
||||||
Expression<String>? id,
|
Expression<String>? id,
|
||||||
Expression<String>? name,
|
Expression<String>? name,
|
||||||
Expression<String>? winnerId,
|
|
||||||
Expression<DateTime>? createdAt,
|
Expression<DateTime>? createdAt,
|
||||||
Expression<int>? rowid,
|
Expression<int>? rowid,
|
||||||
}) {
|
}) {
|
||||||
return RawValuesInsertable({
|
return RawValuesInsertable({
|
||||||
|
if (winnerId != null) 'winner_id': winnerId,
|
||||||
if (id != null) 'id': id,
|
if (id != null) 'id': id,
|
||||||
if (name != null) 'name': name,
|
if (name != null) 'name': name,
|
||||||
if (winnerId != null) 'winner_id': winnerId,
|
|
||||||
if (createdAt != null) 'created_at': createdAt,
|
if (createdAt != null) 'created_at': createdAt,
|
||||||
if (rowid != null) 'rowid': rowid,
|
if (rowid != null) 'rowid': rowid,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchTableCompanion copyWith({
|
MatchTableCompanion copyWith({
|
||||||
|
Value<String?>? winnerId,
|
||||||
Value<String>? id,
|
Value<String>? id,
|
||||||
Value<String>? name,
|
Value<String>? name,
|
||||||
Value<String?>? winnerId,
|
|
||||||
Value<DateTime>? createdAt,
|
Value<DateTime>? createdAt,
|
||||||
Value<int>? rowid,
|
Value<int>? rowid,
|
||||||
}) {
|
}) {
|
||||||
return MatchTableCompanion(
|
return MatchTableCompanion(
|
||||||
|
winnerId: winnerId ?? this.winnerId,
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
name: name ?? this.name,
|
name: name ?? this.name,
|
||||||
winnerId: winnerId ?? this.winnerId,
|
|
||||||
createdAt: createdAt ?? this.createdAt,
|
createdAt: createdAt ?? this.createdAt,
|
||||||
rowid: rowid ?? this.rowid,
|
rowid: rowid ?? this.rowid,
|
||||||
);
|
);
|
||||||
@@ -799,15 +799,15 @@ class MatchTableCompanion extends UpdateCompanion<MatchTableData> {
|
|||||||
@override
|
@override
|
||||||
Map<String, Expression> toColumns(bool nullToAbsent) {
|
Map<String, Expression> toColumns(bool nullToAbsent) {
|
||||||
final map = <String, Expression>{};
|
final map = <String, Expression>{};
|
||||||
|
if (winnerId.present) {
|
||||||
|
map['winner_id'] = Variable<String>(winnerId.value);
|
||||||
|
}
|
||||||
if (id.present) {
|
if (id.present) {
|
||||||
map['id'] = Variable<String>(id.value);
|
map['id'] = Variable<String>(id.value);
|
||||||
}
|
}
|
||||||
if (name.present) {
|
if (name.present) {
|
||||||
map['name'] = Variable<String>(name.value);
|
map['name'] = Variable<String>(name.value);
|
||||||
}
|
}
|
||||||
if (winnerId.present) {
|
|
||||||
map['winner_id'] = Variable<String>(winnerId.value);
|
|
||||||
}
|
|
||||||
if (createdAt.present) {
|
if (createdAt.present) {
|
||||||
map['created_at'] = Variable<DateTime>(createdAt.value);
|
map['created_at'] = Variable<DateTime>(createdAt.value);
|
||||||
}
|
}
|
||||||
@@ -820,9 +820,9 @@ class MatchTableCompanion extends UpdateCompanion<MatchTableData> {
|
|||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return (StringBuffer('MatchTableCompanion(')
|
return (StringBuffer('MatchTableCompanion(')
|
||||||
|
..write('winnerId: $winnerId, ')
|
||||||
..write('id: $id, ')
|
..write('id: $id, ')
|
||||||
..write('name: $name, ')
|
..write('name: $name, ')
|
||||||
..write('winnerId: $winnerId, ')
|
|
||||||
..write('createdAt: $createdAt, ')
|
..write('createdAt: $createdAt, ')
|
||||||
..write('rowid: $rowid')
|
..write('rowid: $rowid')
|
||||||
..write(')'))
|
..write(')'))
|
||||||
@@ -2339,17 +2339,17 @@ typedef $$GroupTableTableProcessedTableManager =
|
|||||||
>;
|
>;
|
||||||
typedef $$MatchTableTableCreateCompanionBuilder =
|
typedef $$MatchTableTableCreateCompanionBuilder =
|
||||||
MatchTableCompanion Function({
|
MatchTableCompanion Function({
|
||||||
|
Value<String?> winnerId,
|
||||||
required String id,
|
required String id,
|
||||||
required String name,
|
required String name,
|
||||||
Value<String?> winnerId,
|
|
||||||
required DateTime createdAt,
|
required DateTime createdAt,
|
||||||
Value<int> rowid,
|
Value<int> rowid,
|
||||||
});
|
});
|
||||||
typedef $$MatchTableTableUpdateCompanionBuilder =
|
typedef $$MatchTableTableUpdateCompanionBuilder =
|
||||||
MatchTableCompanion Function({
|
MatchTableCompanion Function({
|
||||||
|
Value<String?> winnerId,
|
||||||
Value<String> id,
|
Value<String> id,
|
||||||
Value<String> name,
|
Value<String> name,
|
||||||
Value<String?> winnerId,
|
|
||||||
Value<DateTime> createdAt,
|
Value<DateTime> createdAt,
|
||||||
Value<int> rowid,
|
Value<int> rowid,
|
||||||
});
|
});
|
||||||
@@ -2414,6 +2414,11 @@ class $$MatchTableTableFilterComposer
|
|||||||
super.$addJoinBuilderToRootComposer,
|
super.$addJoinBuilderToRootComposer,
|
||||||
super.$removeJoinBuilderFromRootComposer,
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
});
|
});
|
||||||
|
ColumnFilters<String> get winnerId => $composableBuilder(
|
||||||
|
column: $table.winnerId,
|
||||||
|
builder: (column) => ColumnFilters(column),
|
||||||
|
);
|
||||||
|
|
||||||
ColumnFilters<String> get id => $composableBuilder(
|
ColumnFilters<String> get id => $composableBuilder(
|
||||||
column: $table.id,
|
column: $table.id,
|
||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
@@ -2424,11 +2429,6 @@ class $$MatchTableTableFilterComposer
|
|||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
ColumnFilters<String> get winnerId => $composableBuilder(
|
|
||||||
column: $table.winnerId,
|
|
||||||
builder: (column) => ColumnFilters(column),
|
|
||||||
);
|
|
||||||
|
|
||||||
ColumnFilters<DateTime> get createdAt => $composableBuilder(
|
ColumnFilters<DateTime> get createdAt => $composableBuilder(
|
||||||
column: $table.createdAt,
|
column: $table.createdAt,
|
||||||
builder: (column) => ColumnFilters(column),
|
builder: (column) => ColumnFilters(column),
|
||||||
@@ -2494,6 +2494,11 @@ class $$MatchTableTableOrderingComposer
|
|||||||
super.$addJoinBuilderToRootComposer,
|
super.$addJoinBuilderToRootComposer,
|
||||||
super.$removeJoinBuilderFromRootComposer,
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
});
|
});
|
||||||
|
ColumnOrderings<String> get winnerId => $composableBuilder(
|
||||||
|
column: $table.winnerId,
|
||||||
|
builder: (column) => ColumnOrderings(column),
|
||||||
|
);
|
||||||
|
|
||||||
ColumnOrderings<String> get id => $composableBuilder(
|
ColumnOrderings<String> get id => $composableBuilder(
|
||||||
column: $table.id,
|
column: $table.id,
|
||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
@@ -2504,11 +2509,6 @@ class $$MatchTableTableOrderingComposer
|
|||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
);
|
);
|
||||||
|
|
||||||
ColumnOrderings<String> get winnerId => $composableBuilder(
|
|
||||||
column: $table.winnerId,
|
|
||||||
builder: (column) => ColumnOrderings(column),
|
|
||||||
);
|
|
||||||
|
|
||||||
ColumnOrderings<DateTime> get createdAt => $composableBuilder(
|
ColumnOrderings<DateTime> get createdAt => $composableBuilder(
|
||||||
column: $table.createdAt,
|
column: $table.createdAt,
|
||||||
builder: (column) => ColumnOrderings(column),
|
builder: (column) => ColumnOrderings(column),
|
||||||
@@ -2524,15 +2524,15 @@ class $$MatchTableTableAnnotationComposer
|
|||||||
super.$addJoinBuilderToRootComposer,
|
super.$addJoinBuilderToRootComposer,
|
||||||
super.$removeJoinBuilderFromRootComposer,
|
super.$removeJoinBuilderFromRootComposer,
|
||||||
});
|
});
|
||||||
|
GeneratedColumn<String> get winnerId =>
|
||||||
|
$composableBuilder(column: $table.winnerId, builder: (column) => column);
|
||||||
|
|
||||||
GeneratedColumn<String> get id =>
|
GeneratedColumn<String> get id =>
|
||||||
$composableBuilder(column: $table.id, builder: (column) => column);
|
$composableBuilder(column: $table.id, builder: (column) => column);
|
||||||
|
|
||||||
GeneratedColumn<String> get name =>
|
GeneratedColumn<String> get name =>
|
||||||
$composableBuilder(column: $table.name, builder: (column) => column);
|
$composableBuilder(column: $table.name, builder: (column) => column);
|
||||||
|
|
||||||
GeneratedColumn<String> get winnerId =>
|
|
||||||
$composableBuilder(column: $table.winnerId, builder: (column) => column);
|
|
||||||
|
|
||||||
GeneratedColumn<DateTime> get createdAt =>
|
GeneratedColumn<DateTime> get createdAt =>
|
||||||
$composableBuilder(column: $table.createdAt, builder: (column) => column);
|
$composableBuilder(column: $table.createdAt, builder: (column) => column);
|
||||||
|
|
||||||
@@ -2618,29 +2618,29 @@ class $$MatchTableTableTableManager
|
|||||||
$$MatchTableTableAnnotationComposer($db: db, $table: table),
|
$$MatchTableTableAnnotationComposer($db: db, $table: table),
|
||||||
updateCompanionCallback:
|
updateCompanionCallback:
|
||||||
({
|
({
|
||||||
|
Value<String?> winnerId = const Value.absent(),
|
||||||
Value<String> id = const Value.absent(),
|
Value<String> id = const Value.absent(),
|
||||||
Value<String> name = const Value.absent(),
|
Value<String> name = const Value.absent(),
|
||||||
Value<String?> winnerId = const Value.absent(),
|
|
||||||
Value<DateTime> createdAt = const Value.absent(),
|
Value<DateTime> createdAt = const Value.absent(),
|
||||||
Value<int> rowid = const Value.absent(),
|
Value<int> rowid = const Value.absent(),
|
||||||
}) => MatchTableCompanion(
|
}) => MatchTableCompanion(
|
||||||
|
winnerId: winnerId,
|
||||||
id: id,
|
id: id,
|
||||||
name: name,
|
name: name,
|
||||||
winnerId: winnerId,
|
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
rowid: rowid,
|
rowid: rowid,
|
||||||
),
|
),
|
||||||
createCompanionCallback:
|
createCompanionCallback:
|
||||||
({
|
({
|
||||||
|
Value<String?> winnerId = const Value.absent(),
|
||||||
required String id,
|
required String id,
|
||||||
required String name,
|
required String name,
|
||||||
Value<String?> winnerId = const Value.absent(),
|
|
||||||
required DateTime createdAt,
|
required DateTime createdAt,
|
||||||
Value<int> rowid = const Value.absent(),
|
Value<int> rowid = const Value.absent(),
|
||||||
}) => MatchTableCompanion.insert(
|
}) => MatchTableCompanion.insert(
|
||||||
|
winnerId: winnerId,
|
||||||
id: id,
|
id: id,
|
||||||
name: name,
|
name: name,
|
||||||
winnerId: winnerId,
|
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
rowid: rowid,
|
rowid: rowid,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/tables/group_table.dart';
|
import 'package:tallee/data/db/tables/group_table.dart';
|
||||||
import 'package:game_tracker/data/db/tables/match_table.dart';
|
import 'package:tallee/data/db/tables/match_table.dart';
|
||||||
|
|
||||||
class GroupMatchTable extends Table {
|
class GroupMatchTable extends Table {
|
||||||
TextColumn get groupId =>
|
TextColumn get groupId =>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/tables/group_table.dart';
|
import 'package:tallee/data/db/tables/group_table.dart';
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
import 'package:tallee/data/db/tables/player_table.dart';
|
||||||
|
|
||||||
class PlayerGroupTable extends Table {
|
class PlayerGroupTable extends Table {
|
||||||
TextColumn get playerId =>
|
TextColumn get playerId =>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:game_tracker/data/db/tables/match_table.dart';
|
import 'package:tallee/data/db/tables/match_table.dart';
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
import 'package:tallee/data/db/tables/player_table.dart';
|
||||||
|
|
||||||
class PlayerMatchTable extends Table {
|
class PlayerMatchTable extends Table {
|
||||||
TextColumn get playerId =>
|
TextColumn get playerId =>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:clock/clock.dart';
|
import 'package:clock/clock.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:tallee/data/dto/player.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class Group {
|
class Group {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'package:clock/clock.dart';
|
import 'package:clock/clock.dart';
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
import 'package:tallee/data/dto/group.dart';
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
import 'package:tallee/data/dto/player.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class Match {
|
class Match {
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
"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",
|
"app_name": "Tallee",
|
||||||
|
"best_player": "Beste:r Spieler:in",
|
||||||
"cancel": "Abbrechen",
|
"cancel": "Abbrechen",
|
||||||
"choose_game": "Spielvorlage wählen",
|
"choose_game": "Spielvorlage wählen",
|
||||||
"choose_group": "Gruppe wählen",
|
"choose_group": "Gruppe wählen",
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
"create_match": "Spiel erstellen",
|
"create_match": "Spiel erstellen",
|
||||||
"create_new_group": "Neue Gruppe erstellen",
|
"create_new_group": "Neue Gruppe erstellen",
|
||||||
"create_new_match": "Neues Spiel erstellen",
|
"create_new_match": "Neues Spiel erstellen",
|
||||||
|
"created_on": "Erstellt am",
|
||||||
"data": "Daten",
|
"data": "Daten",
|
||||||
"data_successfully_deleted": "Daten erfolgreich gelöscht",
|
"data_successfully_deleted": "Daten erfolgreich gelöscht",
|
||||||
"data_successfully_exported": "Daten erfolgreich exportiert",
|
"data_successfully_exported": "Daten erfolgreich exportiert",
|
||||||
@@ -20,6 +22,8 @@
|
|||||||
"days_ago": "vor {count} Tagen",
|
"days_ago": "vor {count} Tagen",
|
||||||
"delete": "Löschen",
|
"delete": "Löschen",
|
||||||
"delete_all_data": "Alle Daten löschen",
|
"delete_all_data": "Alle Daten löschen",
|
||||||
|
"delete_group": "Gruppe löschen",
|
||||||
|
"edit_group": "Gruppe bearbeiten",
|
||||||
"error_creating_group": "Fehler beim Erstellen der Gruppe, bitte erneut versuchen",
|
"error_creating_group": "Fehler beim Erstellen der Gruppe, bitte erneut versuchen",
|
||||||
"error_reading_file": "Fehler beim Lesen der Datei",
|
"error_reading_file": "Fehler beim Lesen der Datei",
|
||||||
"export_canceled": "Export abgebrochen",
|
"export_canceled": "Export abgebrochen",
|
||||||
@@ -29,6 +33,7 @@
|
|||||||
"game_name": "Spielvorlagenname",
|
"game_name": "Spielvorlagenname",
|
||||||
"group": "Gruppe",
|
"group": "Gruppe",
|
||||||
"group_name": "Gruppenname",
|
"group_name": "Gruppenname",
|
||||||
|
"group_profile": "Gruppenprofil",
|
||||||
"groups": "Gruppen",
|
"groups": "Gruppen",
|
||||||
"home": "Startseite",
|
"home": "Startseite",
|
||||||
"import_canceled": "Import abgebrochen",
|
"import_canceled": "Import abgebrochen",
|
||||||
@@ -42,6 +47,7 @@
|
|||||||
"match_in_progress": "Spiel läuft...",
|
"match_in_progress": "Spiel läuft...",
|
||||||
"match_name": "Spieltitel",
|
"match_name": "Spieltitel",
|
||||||
"matches": "Spiele",
|
"matches": "Spiele",
|
||||||
|
"members": "Mitglieder",
|
||||||
"most_points": "Höchste Punkte",
|
"most_points": "Höchste Punkte",
|
||||||
"no_data_available": "Keine Daten verfügbar",
|
"no_data_available": "Keine Daten verfügbar",
|
||||||
"no_groups_created_yet": "Noch keine Gruppen erstellt",
|
"no_groups_created_yet": "Noch keine Gruppen erstellt",
|
||||||
@@ -57,6 +63,7 @@
|
|||||||
"none": "Kein",
|
"none": "Kein",
|
||||||
"none_group": "Keine",
|
"none_group": "Keine",
|
||||||
"not_available": "Nicht verfügbar",
|
"not_available": "Nicht verfügbar",
|
||||||
|
"played_matches": "Gespielte Spiele",
|
||||||
"player_name": "Spieler:innenname",
|
"player_name": "Spieler:innenname",
|
||||||
"players": "Spieler:innen",
|
"players": "Spieler:innen",
|
||||||
"players_count": "{count} Spieler",
|
"players_count": "{count} Spieler",
|
||||||
@@ -79,7 +86,7 @@
|
|||||||
"stats": "Statistiken",
|
"stats": "Statistiken",
|
||||||
"successfully_added_player": "Spieler:in {playerName} erfolgreich hinzugefügt",
|
"successfully_added_player": "Spieler:in {playerName} erfolgreich hinzugefügt",
|
||||||
"there_is_no_group_matching_your_search": "Es gibt keine Gruppe, die deiner Suche entspricht",
|
"there_is_no_group_matching_your_search": "Es gibt keine Gruppe, die deiner Suche entspricht",
|
||||||
"this_cannot_be_undone": "Dies kann nicht rückgängig gemacht werden",
|
"this_cannot_be_undone": "Dies kann nicht rückgängig gemacht werden.",
|
||||||
"today_at": "Heute um",
|
"today_at": "Heute um",
|
||||||
"undo": "Rückgängig",
|
"undo": "Rückgängig",
|
||||||
"unknown_exception": "Unbekannter Fehler (siehe Konsole)",
|
"unknown_exception": "Unbekannter Fehler (siehe Konsole)",
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
"@app_name": {
|
"@app_name": {
|
||||||
"description": "The name of the App"
|
"description": "The name of the App"
|
||||||
},
|
},
|
||||||
|
"@best_player": {
|
||||||
|
"description": "Label for best player statistic"
|
||||||
|
},
|
||||||
"@cancel": {
|
"@cancel": {
|
||||||
"description": "Cancel button text"
|
"description": "Cancel button text"
|
||||||
},
|
},
|
||||||
@@ -39,6 +42,9 @@
|
|||||||
"@create_new_match": {
|
"@create_new_match": {
|
||||||
"description": "Button text to create a new match"
|
"description": "Button text to create a new match"
|
||||||
},
|
},
|
||||||
|
"@created_on": {
|
||||||
|
"description": "Label for creation date"
|
||||||
|
},
|
||||||
"@data": {
|
"@data": {
|
||||||
"description": "Data label"
|
"description": "Data label"
|
||||||
},
|
},
|
||||||
@@ -65,6 +71,12 @@
|
|||||||
"@delete_all_data": {
|
"@delete_all_data": {
|
||||||
"description": "Confirmation dialog for deleting all data"
|
"description": "Confirmation dialog for deleting all data"
|
||||||
},
|
},
|
||||||
|
"@delete_group": {
|
||||||
|
"description": "Button text to delete a group"
|
||||||
|
},
|
||||||
|
"@edit_group": {
|
||||||
|
"description": "Button text to edit a group"
|
||||||
|
},
|
||||||
"@error_creating_group": {
|
"@error_creating_group": {
|
||||||
"description": "Error message when group creation fails"
|
"description": "Error message when group creation fails"
|
||||||
},
|
},
|
||||||
@@ -92,6 +104,9 @@
|
|||||||
"@group_name": {
|
"@group_name": {
|
||||||
"description": "Placeholder for group name input"
|
"description": "Placeholder for group name input"
|
||||||
},
|
},
|
||||||
|
"@group_profile": {
|
||||||
|
"description": "Title for group profile view"
|
||||||
|
},
|
||||||
"@groups": {
|
"@groups": {
|
||||||
"description": "Label for groups"
|
"description": "Label for groups"
|
||||||
},
|
},
|
||||||
@@ -131,6 +146,9 @@
|
|||||||
"@matches": {
|
"@matches": {
|
||||||
"description": "Label for matches"
|
"description": "Label for matches"
|
||||||
},
|
},
|
||||||
|
"@members": {
|
||||||
|
"description": "Label for group members"
|
||||||
|
},
|
||||||
"@most_points": {
|
"@most_points": {
|
||||||
"description": "Title for most points ruleset"
|
"description": "Title for most points ruleset"
|
||||||
},
|
},
|
||||||
@@ -176,6 +194,9 @@
|
|||||||
"@not_available": {
|
"@not_available": {
|
||||||
"description": "Abbreviation for not available"
|
"description": "Abbreviation for not available"
|
||||||
},
|
},
|
||||||
|
"@played_matches": {
|
||||||
|
"description": "Label for played matches statistic"
|
||||||
|
},
|
||||||
"@player_name": {
|
"@player_name": {
|
||||||
"description": "Placeholder for player name input"
|
"description": "Placeholder for player name input"
|
||||||
},
|
},
|
||||||
@@ -280,7 +301,8 @@
|
|||||||
"all_players": "All players",
|
"all_players": "All players",
|
||||||
"all_players_selected": "All players selected",
|
"all_players_selected": "All players selected",
|
||||||
"amount_of_matches": "Amount of Matches",
|
"amount_of_matches": "Amount of Matches",
|
||||||
"app_name": "Game Tracker",
|
"app_name": "Tallee",
|
||||||
|
"best_player": "Best Player",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"choose_game": "Choose Game",
|
"choose_game": "Choose Game",
|
||||||
"choose_group": "Choose Group",
|
"choose_group": "Choose Group",
|
||||||
@@ -289,6 +311,7 @@
|
|||||||
"create_group": "Create Group",
|
"create_group": "Create Group",
|
||||||
"create_match": "Create match",
|
"create_match": "Create match",
|
||||||
"create_new_group": "Create new group",
|
"create_new_group": "Create new group",
|
||||||
|
"created_on": "Created on",
|
||||||
"create_new_match": "Create new match",
|
"create_new_match": "Create new match",
|
||||||
"data": "Data",
|
"data": "Data",
|
||||||
"data_successfully_deleted": "Data successfully deleted",
|
"data_successfully_deleted": "Data successfully deleted",
|
||||||
@@ -297,6 +320,8 @@
|
|||||||
"days_ago": "{count} days ago",
|
"days_ago": "{count} days ago",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"delete_all_data": "Delete all data",
|
"delete_all_data": "Delete all data",
|
||||||
|
"delete_group": "Delete Group",
|
||||||
|
"edit_group": "Edit Group",
|
||||||
"error_creating_group": "Error while creating group, please try again",
|
"error_creating_group": "Error while creating group, please try again",
|
||||||
"error_reading_file": "Error reading file",
|
"error_reading_file": "Error reading file",
|
||||||
"export_canceled": "Export canceled",
|
"export_canceled": "Export canceled",
|
||||||
@@ -306,6 +331,7 @@
|
|||||||
"game_name": "Game Name",
|
"game_name": "Game Name",
|
||||||
"group": "Group",
|
"group": "Group",
|
||||||
"group_name": "Group name",
|
"group_name": "Group name",
|
||||||
|
"group_profile": "Group Profile",
|
||||||
"groups": "Groups",
|
"groups": "Groups",
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"import_canceled": "Import canceled",
|
"import_canceled": "Import canceled",
|
||||||
@@ -319,6 +345,7 @@
|
|||||||
"match_in_progress": "Match in progress...",
|
"match_in_progress": "Match in progress...",
|
||||||
"match_name": "Match name",
|
"match_name": "Match name",
|
||||||
"matches": "Matches",
|
"matches": "Matches",
|
||||||
|
"members": "Members",
|
||||||
"most_points": "Most Points",
|
"most_points": "Most Points",
|
||||||
"no_data_available": "No data available",
|
"no_data_available": "No data available",
|
||||||
"no_groups_created_yet": "No groups created yet",
|
"no_groups_created_yet": "No groups created yet",
|
||||||
@@ -334,6 +361,7 @@
|
|||||||
"none": "None",
|
"none": "None",
|
||||||
"none_group": "None",
|
"none_group": "None",
|
||||||
"not_available": "Not available",
|
"not_available": "Not available",
|
||||||
|
"played_matches": "Played Matches",
|
||||||
"player_name": "Player name",
|
"player_name": "Player name",
|
||||||
"players": "Players",
|
"players": "Players",
|
||||||
"players_count": "{count} Players",
|
"players_count": "{count} Players",
|
||||||
@@ -356,7 +384,7 @@
|
|||||||
"stats": "Stats",
|
"stats": "Stats",
|
||||||
"successfully_added_player": "Successfully added player {playerName}",
|
"successfully_added_player": "Successfully added player {playerName}",
|
||||||
"there_is_no_group_matching_your_search": "There is no group matching your search",
|
"there_is_no_group_matching_your_search": "There is no group matching your search",
|
||||||
"this_cannot_be_undone": "This can't be undone",
|
"this_cannot_be_undone": "This can't be undone.",
|
||||||
"today_at": "Today at",
|
"today_at": "Today at",
|
||||||
"undo": "Undo",
|
"undo": "Undo",
|
||||||
"unknown_exception": "Unknown Exception (see console)",
|
"unknown_exception": "Unknown Exception (see console)",
|
||||||
|
|||||||
@@ -119,9 +119,15 @@ abstract class AppLocalizations {
|
|||||||
/// The name of the App
|
/// The name of the App
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Game Tracker'**
|
/// **'Tallee'**
|
||||||
String get app_name;
|
String get app_name;
|
||||||
|
|
||||||
|
/// Label for best player statistic
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Best Player'**
|
||||||
|
String get best_player;
|
||||||
|
|
||||||
/// Cancel button text
|
/// Cancel button text
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -170,6 +176,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'Create new group'**
|
/// **'Create new group'**
|
||||||
String get create_new_group;
|
String get create_new_group;
|
||||||
|
|
||||||
|
/// Label for creation date
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Created on'**
|
||||||
|
String get created_on;
|
||||||
|
|
||||||
/// Button text to create a new match
|
/// Button text to create a new match
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -218,6 +230,18 @@ abstract class AppLocalizations {
|
|||||||
/// **'Delete all data'**
|
/// **'Delete all data'**
|
||||||
String get delete_all_data;
|
String get delete_all_data;
|
||||||
|
|
||||||
|
/// Button text to delete a group
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Delete Group'**
|
||||||
|
String get delete_group;
|
||||||
|
|
||||||
|
/// Button text to edit a group
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Edit Group'**
|
||||||
|
String get edit_group;
|
||||||
|
|
||||||
/// Error message when group creation fails
|
/// Error message when group creation fails
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -272,6 +296,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'Group name'**
|
/// **'Group name'**
|
||||||
String get group_name;
|
String get group_name;
|
||||||
|
|
||||||
|
/// Title for group profile view
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Group Profile'**
|
||||||
|
String get group_profile;
|
||||||
|
|
||||||
/// Label for groups
|
/// Label for groups
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -350,6 +380,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'Matches'**
|
/// **'Matches'**
|
||||||
String get matches;
|
String get matches;
|
||||||
|
|
||||||
|
/// Label for group members
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Members'**
|
||||||
|
String get members;
|
||||||
|
|
||||||
/// Title for most points ruleset
|
/// Title for most points ruleset
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -440,6 +476,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'Not available'**
|
/// **'Not available'**
|
||||||
String get not_available;
|
String get not_available;
|
||||||
|
|
||||||
|
/// Label for played matches statistic
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Played Matches'**
|
||||||
|
String get played_matches;
|
||||||
|
|
||||||
/// Placeholder for player name input
|
/// Placeholder for player name input
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
@@ -575,7 +617,7 @@ abstract class AppLocalizations {
|
|||||||
/// Warning message for irreversible actions
|
/// Warning message for irreversible actions
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'This can\'t be undone'**
|
/// **'This can\'t be undone.'**
|
||||||
String get this_cannot_be_undone;
|
String get this_cannot_be_undone;
|
||||||
|
|
||||||
/// Date format for today
|
/// Date format for today
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
String get amount_of_matches => 'Anzahl der Spiele';
|
String get amount_of_matches => 'Anzahl der Spiele';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get app_name => 'Game Tracker';
|
String get app_name => 'Tallee';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get best_player => 'Beste:r Spieler:in';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get cancel => 'Abbrechen';
|
String get cancel => 'Abbrechen';
|
||||||
@@ -46,6 +49,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get create_new_group => 'Neue Gruppe erstellen';
|
String get create_new_group => 'Neue Gruppe erstellen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get created_on => 'Erstellt am';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_new_match => 'Neues Spiel erstellen';
|
String get create_new_match => 'Neues Spiel erstellen';
|
||||||
|
|
||||||
@@ -72,6 +78,12 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get delete_all_data => 'Alle Daten löschen';
|
String get delete_all_data => 'Alle Daten löschen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get delete_group => 'Gruppe löschen';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get edit_group => 'Gruppe bearbeiten';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get error_creating_group =>
|
String get error_creating_group =>
|
||||||
'Fehler beim Erstellen der Gruppe, bitte erneut versuchen';
|
'Fehler beim Erstellen der Gruppe, bitte erneut versuchen';
|
||||||
@@ -100,6 +112,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get group_name => 'Gruppenname';
|
String get group_name => 'Gruppenname';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get group_profile => 'Gruppenprofil';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get groups => 'Gruppen';
|
String get groups => 'Gruppen';
|
||||||
|
|
||||||
@@ -139,6 +154,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get matches => 'Spiele';
|
String get matches => 'Spiele';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get members => 'Mitglieder';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get most_points => 'Höchste Punkte';
|
String get most_points => 'Höchste Punkte';
|
||||||
|
|
||||||
@@ -185,6 +203,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get not_available => 'Nicht verfügbar';
|
String get not_available => 'Nicht verfügbar';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get played_matches => 'Gespielte Spiele';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get player_name => 'Spieler:innenname';
|
String get player_name => 'Spieler:innenname';
|
||||||
|
|
||||||
@@ -262,7 +283,7 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get this_cannot_be_undone =>
|
String get this_cannot_be_undone =>
|
||||||
'Dies kann nicht rückgängig gemacht werden';
|
'Dies kann nicht rückgängig gemacht werden.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get today_at => 'Heute um';
|
String get today_at => 'Heute um';
|
||||||
|
|||||||
@@ -18,7 +18,10 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
String get amount_of_matches => 'Amount of Matches';
|
String get amount_of_matches => 'Amount of Matches';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get app_name => 'Game Tracker';
|
String get app_name => 'Tallee';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get best_player => 'Best Player';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get cancel => 'Cancel';
|
String get cancel => 'Cancel';
|
||||||
@@ -46,6 +49,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get create_new_group => 'Create new group';
|
String get create_new_group => 'Create new group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get created_on => 'Created on';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get create_new_match => 'Create new match';
|
String get create_new_match => 'Create new match';
|
||||||
|
|
||||||
@@ -72,6 +78,12 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get delete_all_data => 'Delete all data';
|
String get delete_all_data => 'Delete all data';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get delete_group => 'Delete Group';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get edit_group => 'Edit Group';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get error_creating_group =>
|
String get error_creating_group =>
|
||||||
'Error while creating group, please try again';
|
'Error while creating group, please try again';
|
||||||
@@ -100,6 +112,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get group_name => 'Group name';
|
String get group_name => 'Group name';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get group_profile => 'Group Profile';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get groups => 'Groups';
|
String get groups => 'Groups';
|
||||||
|
|
||||||
@@ -139,6 +154,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get matches => 'Matches';
|
String get matches => 'Matches';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get members => 'Members';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get most_points => 'Most Points';
|
String get most_points => 'Most Points';
|
||||||
|
|
||||||
@@ -185,6 +203,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get not_available => 'Not available';
|
String get not_available => 'Not available';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get played_matches => 'Played Matches';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get player_name => 'Player name';
|
String get player_name => 'Player name';
|
||||||
|
|
||||||
@@ -261,7 +282,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
'There is no group matching your search';
|
'There is no group matching your search';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get this_cannot_be_undone => 'This can\'t be undone';
|
String get this_cannot_be_undone => 'This can\'t be undone.';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get today_at => 'Today at';
|
String get today_at => 'Today at';
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/custom_navigation_bar.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/custom_navigation_bar.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(
|
runApp(
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/adaptive_page_route.dart';
|
import 'package:tallee/core/adaptive_page_route.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/group_view/groups_view.dart';
|
import 'package:tallee/presentation/views/main_menu/group_view/groups_view.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/home_view.dart';
|
import 'package:tallee/presentation/views/main_menu/home_view.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/match_view/match_view.dart';
|
import 'package:tallee/presentation/views/main_menu/match_view/match_view.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/settings_view/settings_view.dart';
|
import 'package:tallee/presentation/views/main_menu/settings_view/settings_view.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/statistics_view.dart';
|
import 'package:tallee/presentation/views/main_menu/statistics_view.dart';
|
||||||
import 'package:game_tracker/presentation/widgets/navbar_item.dart';
|
import 'package:tallee/presentation/widgets/navbar_item.dart';
|
||||||
|
|
||||||
class CustomNavigationBar extends StatefulWidget {
|
class CustomNavigationBar extends StatefulWidget {
|
||||||
|
/// A custom navigation bar widget that provides tabbed navigation
|
||||||
|
/// between different views: Home, Matches, Groups, and Statistics.
|
||||||
const CustomNavigationBar({super.key});
|
const CustomNavigationBar({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -71,53 +75,102 @@ 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(
|
// Dynamically generated blur layers for ultra-smooth transition
|
||||||
borderRadius: BorderRadius.circular(24),
|
...List.generate(34, (index) {
|
||||||
color: CustomTheme.primaryColor,
|
// Use cubic curve for an even more natural, smoother transition
|
||||||
),
|
final progress = index / 34.0; // 0.0 to 1.0
|
||||||
child: ClipRRect(
|
final cubic = progress * progress * progress; // cubic curve
|
||||||
borderRadius: BorderRadius.circular(24),
|
final blurStrength =
|
||||||
child: SizedBox(
|
0.5 + (cubic * 50.0); // Very smooth from 0.5 to 50.5
|
||||||
height: 60,
|
|
||||||
child: Row(
|
// Height goes completely from 100% to 0% (all the way down)
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
// With extra density at the bottom for softer transition
|
||||||
children: <Widget>[
|
final heightFactor = index < 25
|
||||||
NavbarItem(
|
// First 25 layers: 100% to 30%
|
||||||
index: 0,
|
? 1.0 - (progress * 0.7)
|
||||||
isSelected: currentIndex == 0,
|
// Last 10 layers: 30% to 0% (denser)
|
||||||
icon: Icons.home_rounded,
|
: 0.3 - ((index - 25) / 34.0);
|
||||||
label: loc.home,
|
|
||||||
onTabTapped: onTabTapped,
|
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: Container(color: Colors.transparent),
|
||||||
),
|
),
|
||||||
NavbarItem(
|
),
|
||||||
index: 1,
|
);
|
||||||
isSelected: currentIndex == 1,
|
}),
|
||||||
icon: Icons.gamepad_rounded,
|
// Gradient overlay
|
||||||
label: loc.matches,
|
Positioned.fill(
|
||||||
onTabTapped: onTabTapped,
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.bottomCenter,
|
||||||
|
end: Alignment.topCenter,
|
||||||
|
colors: [
|
||||||
|
CustomTheme.boxColor.withValues(alpha: 1),
|
||||||
|
CustomTheme.boxColor.withValues(alpha: 0.5),
|
||||||
|
CustomTheme.boxColor.withValues(alpha: 0.2),
|
||||||
|
CustomTheme.boxColor.withValues(alpha: 0.0),
|
||||||
|
],
|
||||||
|
stops: const [0.0, 0.4, 0.8, 1],
|
||||||
),
|
),
|
||||||
NavbarItem(
|
),
|
||||||
index: 2,
|
|
||||||
isSelected: currentIndex == 2,
|
|
||||||
icon: Icons.group_rounded,
|
|
||||||
label: loc.groups,
|
|
||||||
onTabTapped: onTabTapped,
|
|
||||||
),
|
|
||||||
NavbarItem(
|
|
||||||
index: 3,
|
|
||||||
isSelected: currentIndex == 3,
|
|
||||||
icon: Icons.bar_chart_rounded,
|
|
||||||
label: loc.statistics,
|
|
||||||
onTabTapped: onTabTapped,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
// Navbar content
|
||||||
|
SafeArea(
|
||||||
|
child: SizedBox(
|
||||||
|
height: 70,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: <Widget>[
|
||||||
|
NavbarItem(
|
||||||
|
index: 0,
|
||||||
|
isSelected: currentIndex == 0,
|
||||||
|
icon: Icons.home_rounded,
|
||||||
|
label: loc.home,
|
||||||
|
onTabTapped: onTabTapped,
|
||||||
|
),
|
||||||
|
NavbarItem(
|
||||||
|
index: 1,
|
||||||
|
isSelected: currentIndex == 1,
|
||||||
|
icon: Icons.gamepad_rounded,
|
||||||
|
label: loc.matches,
|
||||||
|
onTabTapped: onTabTapped,
|
||||||
|
),
|
||||||
|
NavbarItem(
|
||||||
|
index: 2,
|
||||||
|
isSelected: currentIndex == 2,
|
||||||
|
icon: Icons.group_rounded,
|
||||||
|
label: loc.groups,
|
||||||
|
onTabTapped: onTabTapped,
|
||||||
|
),
|
||||||
|
NavbarItem(
|
||||||
|
index: 3,
|
||||||
|
isSelected: currentIndex == 3,
|
||||||
|
icon: Icons.bar_chart_rounded,
|
||||||
|
label: loc.statistics,
|
||||||
|
onTabTapped: onTabTapped,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:game_tracker/core/enums.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/player_selection.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/text_input/text_input_field.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/constants.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/core/enums.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/dto/group.dart';
|
||||||
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/player_selection.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/text_input/text_input_field.dart';
|
||||||
|
|
||||||
class CreateGroupView extends StatefulWidget {
|
class CreateGroupView extends StatefulWidget {
|
||||||
|
/// A view that allows the user to create a new group
|
||||||
const CreateGroupView({super.key});
|
const CreateGroupView({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -46,6 +48,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
|||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
return ScaffoldMessenger(
|
return ScaffoldMessenger(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
backgroundColor: CustomTheme.backgroundColor,
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
appBar: AppBar(title: Text(loc.create_new_group)),
|
appBar: AppBar(title: Text(loc.create_new_group)),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
@@ -57,6 +60,7 @@ class _CreateGroupViewState extends State<CreateGroupView> {
|
|||||||
child: TextInputField(
|
child: TextInputField(
|
||||||
controller: _groupNameController,
|
controller: _groupNameController,
|
||||||
hintText: loc.group_name,
|
hintText: loc.group_name,
|
||||||
|
maxLength: Constants.MAX_GROUP_NAME_LENGTH,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
|||||||
@@ -0,0 +1,273 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/dto/group.dart';
|
||||||
|
import 'package:tallee/data/dto/match.dart';
|
||||||
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/app_skeleton.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/colored_icon_container.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/custom_alert_dialog.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/info_tile.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart';
|
||||||
|
|
||||||
|
class GroupProfileView extends StatefulWidget {
|
||||||
|
/// A view that displays the profile of a group
|
||||||
|
/// - [group]: The group to display
|
||||||
|
const GroupProfileView({
|
||||||
|
super.key,
|
||||||
|
required this.group,
|
||||||
|
required this.callback,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The group to display
|
||||||
|
final Group group;
|
||||||
|
|
||||||
|
final VoidCallback callback;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<GroupProfileView> createState() => _GroupProfileViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GroupProfileViewState extends State<GroupProfileView> {
|
||||||
|
late final AppDatabase db;
|
||||||
|
bool isLoading = true;
|
||||||
|
|
||||||
|
/// Total matches played in this group
|
||||||
|
int totalMatches = 0;
|
||||||
|
|
||||||
|
String bestPlayer = '';
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
db = Provider.of<AppDatabase>(context, listen: false);
|
||||||
|
_loadStatistics();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final loc = AppLocalizations.of(context);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(loc.group_profile),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
icon: const Icon(Icons.delete),
|
||||||
|
onPressed: () async {
|
||||||
|
showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => CustomAlertDialog(
|
||||||
|
title: '${loc.delete_group}?',
|
||||||
|
content: loc.this_cannot_be_undone,
|
||||||
|
actions: [
|
||||||
|
AnimatedDialogButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(false),
|
||||||
|
child: Text(
|
||||||
|
loc.cancel,
|
||||||
|
style: const TextStyle(color: CustomTheme.textColor),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AnimatedDialogButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(true),
|
||||||
|
child: Text(
|
||||||
|
loc.delete,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: CustomTheme.secondaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
).then((confirmed) async {
|
||||||
|
if (confirmed! && context.mounted) {
|
||||||
|
await db.groupDao.deleteGroup(groupId: widget.group.id);
|
||||||
|
if (!context.mounted) return;
|
||||||
|
Navigator.pop(context);
|
||||||
|
widget.callback.call();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
ListView(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 12,
|
||||||
|
right: 12,
|
||||||
|
top: 20,
|
||||||
|
bottom: 100,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
const Center(
|
||||||
|
child: ColoredIconContainer(
|
||||||
|
icon: Icons.group,
|
||||||
|
containerSize: 55,
|
||||||
|
iconSize: 38,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Text(
|
||||||
|
widget.group.name,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 28,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: CustomTheme.textColor,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Text(
|
||||||
|
'${loc.created_on} ${DateFormat.yMMMd(Localizations.localeOf(context).toString()).format(widget.group.createdAt)}',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: CustomTheme.textColor,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
InfoTile(
|
||||||
|
title: loc.members,
|
||||||
|
icon: Icons.people,
|
||||||
|
horizontalAlignment: CrossAxisAlignment.start,
|
||||||
|
content: Wrap(
|
||||||
|
alignment: WrapAlignment.start,
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.start,
|
||||||
|
spacing: 12,
|
||||||
|
runSpacing: 8,
|
||||||
|
children: widget.group.members.map((member) {
|
||||||
|
return TextIconTile(
|
||||||
|
text: member.name,
|
||||||
|
iconEnabled: false,
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 15),
|
||||||
|
InfoTile(
|
||||||
|
title: loc.statistics,
|
||||||
|
icon: Icons.bar_chart,
|
||||||
|
content: AppSkeleton(
|
||||||
|
enabled: isLoading,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
_buildStatRow(
|
||||||
|
loc.members,
|
||||||
|
widget.group.members.length.toString(),
|
||||||
|
),
|
||||||
|
_buildStatRow(
|
||||||
|
loc.played_matches,
|
||||||
|
totalMatches.toString(),
|
||||||
|
),
|
||||||
|
_buildStatRow(loc.best_player, bestPlayer),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: MediaQuery.paddingOf(context).bottom,
|
||||||
|
child: MainMenuButton(
|
||||||
|
text: loc.edit_group,
|
||||||
|
icon: Icons.edit,
|
||||||
|
onPressed: () {
|
||||||
|
// TODO: Uncomment when GroupDetailView is implemented
|
||||||
|
/*
|
||||||
|
await Navigator.push(
|
||||||
|
context,
|
||||||
|
adaptivePageRoute(
|
||||||
|
builder: (context) {
|
||||||
|
|
||||||
|
return const GroupDetailView();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);*/
|
||||||
|
print('Edit Group pressed');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds a single statistic row with a label and value
|
||||||
|
/// - [label]: The label of the statistic
|
||||||
|
/// - [value]: The value of the statistic
|
||||||
|
Widget _buildStatRow(String label, String value) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: CustomTheme.textColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
value,
|
||||||
|
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads statistics for this group
|
||||||
|
Future<void> _loadStatistics() async {
|
||||||
|
final matches = await db.matchDao.getAllMatches();
|
||||||
|
final groupMatches = matches
|
||||||
|
.where((match) => match.group?.id == widget.group.id)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
totalMatches = groupMatches.length;
|
||||||
|
bestPlayer = _getBestPlayer(groupMatches);
|
||||||
|
isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines the best player in the group based on match wins
|
||||||
|
String _getBestPlayer(List<Match> matches) {
|
||||||
|
final bestPlayerCounts = <Player, int>{};
|
||||||
|
|
||||||
|
// Count wins for each player
|
||||||
|
for (var match in matches) {
|
||||||
|
if (match.winner != null) {
|
||||||
|
bestPlayerCounts.update(
|
||||||
|
match.winner!,
|
||||||
|
(value) => value + 1,
|
||||||
|
ifAbsent: () => 1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort players by win count
|
||||||
|
final sortedPlayers = bestPlayerCounts.entries.toList()
|
||||||
|
..sort((a, b) => b.value.compareTo(a.value));
|
||||||
|
|
||||||
|
// Get the best player
|
||||||
|
bestPlayer = sortedPlayers.isNotEmpty ? sortedPlayers.first.key.name : '-';
|
||||||
|
|
||||||
|
return bestPlayer;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,21 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/adaptive_page_route.dart';
|
|
||||||
import 'package:game_tracker/core/constants.dart';
|
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/group_view/create_group_view.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/top_centered_message.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/adaptive_page_route.dart';
|
||||||
|
import 'package:tallee/core/constants.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/dto/group.dart';
|
||||||
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/group_view/create_group_view.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/group_view/group_profile_view.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/app_skeleton.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/group_tile.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/top_centered_message.dart';
|
||||||
|
|
||||||
class GroupsView extends StatefulWidget {
|
class GroupsView extends StatefulWidget {
|
||||||
|
/// A view that displays a list of groups
|
||||||
const GroupsView({super.key});
|
const GroupsView({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -73,16 +75,31 @@ class _GroupsViewState extends State<GroupsView> {
|
|||||||
height: MediaQuery.paddingOf(context).bottom - 20,
|
height: MediaQuery.paddingOf(context).bottom - 20,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return GroupTile(group: groups[index]);
|
return GroupTile(
|
||||||
|
group: groups[index],
|
||||||
|
onTap: () async {
|
||||||
|
await Navigator.push(
|
||||||
|
context,
|
||||||
|
adaptivePageRoute(
|
||||||
|
builder: (context) {
|
||||||
|
return GroupProfileView(
|
||||||
|
group: groups[index],
|
||||||
|
callback: loadGroups,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: MediaQuery.paddingOf(context).bottom,
|
bottom: MediaQuery.paddingOf(context).bottom + 20,
|
||||||
child: CustomWidthButton(
|
child: MainMenuButton(
|
||||||
text: loc.create_group,
|
text: loc.create_group,
|
||||||
sizeRelativeToWidth: 0.90,
|
icon: Icons.group_add,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await Navigator.push(
|
await Navigator.push(
|
||||||
context,
|
context,
|
||||||
@@ -104,9 +121,12 @@ class _GroupsViewState extends State<GroupsView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loadGroups() {
|
void loadGroups() {
|
||||||
|
setState(() {
|
||||||
|
isLoading = true;
|
||||||
|
});
|
||||||
Future.wait([
|
Future.wait([
|
||||||
db.groupDao.getAllGroups(),
|
db.groupDao.getAllGroups(),
|
||||||
Future.delayed(Constants.minimumSkeletonDuration),
|
Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
|
||||||
]).then((results) {
|
]).then((results) {
|
||||||
loadedGroups = results[0] as List<Group>;
|
loadedGroups = results[0] as List<Group>;
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/adaptive_page_route.dart';
|
|
||||||
import 'package:game_tracker/core/constants.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
|
||||||
import 'package:game_tracker/data/dto/match.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/buttons/quick_create_button.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/info_tile.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/match_tile.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/quick_info_tile.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/adaptive_page_route.dart';
|
||||||
|
import 'package:tallee/core/constants.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/dto/group.dart';
|
||||||
|
import 'package:tallee/data/dto/match.dart';
|
||||||
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/app_skeleton.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/quick_create_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/info_tile.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/match_tile.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/quick_info_tile.dart';
|
||||||
|
|
||||||
class HomeView extends StatefulWidget {
|
class HomeView extends StatefulWidget {
|
||||||
|
/// The main home view of the application, displaying quick info,
|
||||||
|
/// recent matches, and quick create options.
|
||||||
const HomeView({super.key});
|
const HomeView({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -193,7 +195,7 @@ class _HomeViewState extends State<HomeView> {
|
|||||||
db.matchDao.getMatchCount(),
|
db.matchDao.getMatchCount(),
|
||||||
db.groupDao.getGroupCount(),
|
db.groupDao.getGroupCount(),
|
||||||
db.matchDao.getAllMatches(),
|
db.matchDao.getAllMatches(),
|
||||||
Future.delayed(Constants.minimumSkeletonDuration),
|
Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
|
||||||
]).then((results) {
|
]).then((results) {
|
||||||
matchCount = results[0] as int;
|
matchCount = results[0] as int;
|
||||||
groupCount = results[1] as int;
|
groupCount = results[1] as int;
|
||||||
|
|||||||
@@ -1,20 +1,26 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:game_tracker/core/enums.dart';
|
import 'package:tallee/core/enums.dart';
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart';
|
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/title_description_list_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/title_description_list_tile.dart';
|
||||||
|
|
||||||
class ChooseGameView extends StatefulWidget {
|
class ChooseGameView extends StatefulWidget {
|
||||||
final List<(String, String, Ruleset)> games;
|
/// A view that allows the user to choose a game from a list of available games
|
||||||
final int initialGameIndex;
|
/// - [games]: A list of tuples containing the game name, description and ruleset
|
||||||
|
/// - [initialGameIndex]: The index of the initially selected game
|
||||||
const ChooseGameView({
|
const ChooseGameView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.games,
|
required this.games,
|
||||||
required this.initialGameIndex,
|
required this.initialGameIndex,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// A list of tuples containing the game name, description and ruleset
|
||||||
|
final List<(String, String, Ruleset)> games;
|
||||||
|
|
||||||
|
/// The index of the initially selected game
|
||||||
|
final int initialGameIndex;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ChooseGameView> createState() => _ChooseGameViewState();
|
State<ChooseGameView> createState() => _ChooseGameViewState();
|
||||||
}
|
}
|
||||||
@@ -37,6 +43,7 @@ class _ChooseGameViewState extends State<ChooseGameView> {
|
|||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: CustomTheme.backgroundColor,
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_back_ios),
|
icon: const Icon(Icons.arrow_back_ios),
|
||||||
|
|||||||
@@ -1,21 +1,27 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
import 'package:tallee/data/dto/group.dart';
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart';
|
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/group_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/group_tile.dart';
|
||||||
import 'package:game_tracker/presentation/widgets/top_centered_message.dart';
|
import 'package:tallee/presentation/widgets/top_centered_message.dart';
|
||||||
|
|
||||||
class ChooseGroupView extends StatefulWidget {
|
class ChooseGroupView extends StatefulWidget {
|
||||||
final List<Group> groups;
|
/// A view that allows the user to choose a group from a list of groups.
|
||||||
final String initialGroupId;
|
/// - [groups]: A list of available groups to choose from
|
||||||
|
/// - [initialGroupId]: The ID of the initially selected group
|
||||||
const ChooseGroupView({
|
const ChooseGroupView({
|
||||||
super.key,
|
super.key,
|
||||||
required this.groups,
|
required this.groups,
|
||||||
required this.initialGroupId,
|
required this.initialGroupId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// A list of available groups to choose from
|
||||||
|
final List<Group> groups;
|
||||||
|
|
||||||
|
/// The ID of the initially selected group
|
||||||
|
final String initialGroupId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ChooseGroupView> createState() => _ChooseGroupViewState();
|
State<ChooseGroupView> createState() => _ChooseGroupViewState();
|
||||||
}
|
}
|
||||||
@@ -37,6 +43,7 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
|
|||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: CustomTheme.backgroundColor,
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
icon: const Icon(Icons.arrow_back_ios),
|
icon: const Icon(Icons.arrow_back_ios),
|
||||||
@@ -140,10 +147,11 @@ class _ChooseGroupViewState extends State<ChooseGroupView> {
|
|||||||
filteredGroups.clear();
|
filteredGroups.clear();
|
||||||
filteredGroups.addAll(
|
filteredGroups.addAll(
|
||||||
widget.groups.where(
|
widget.groups.where(
|
||||||
(group) =>
|
(group) =>
|
||||||
group.name.toLowerCase().contains(query.toLowerCase()) ||
|
group.name.toLowerCase().contains(query.toLowerCase()) ||
|
||||||
group.members.any(
|
group.members.any(
|
||||||
(player) => player.name.toLowerCase().contains(query.toLowerCase()),
|
(player) =>
|
||||||
|
player.name.toLowerCase().contains(query.toLowerCase()),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:game_tracker/core/enums.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/title_description_list_tile.dart';
|
|
||||||
|
|
||||||
class ChooseRulesetView extends StatefulWidget {
|
|
||||||
final List<(Ruleset, String)> rulesets;
|
|
||||||
final int initialRulesetIndex;
|
|
||||||
|
|
||||||
const ChooseRulesetView({
|
|
||||||
super.key,
|
|
||||||
required this.rulesets,
|
|
||||||
required this.initialRulesetIndex,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<ChooseRulesetView> createState() => _ChooseRulesetViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ChooseRulesetViewState extends State<ChooseRulesetView> {
|
|
||||||
/// Currently selected ruleset index
|
|
||||||
late int selectedRulesetIndex;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
selectedRulesetIndex = widget.initialRulesetIndex;
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final loc = AppLocalizations.of(context);
|
|
||||||
return DefaultTabController(
|
|
||||||
length: 2,
|
|
||||||
initialIndex: 0,
|
|
||||||
child: Scaffold(
|
|
||||||
backgroundColor: CustomTheme.backgroundColor,
|
|
||||||
appBar: AppBar(
|
|
||||||
leading: IconButton(
|
|
||||||
icon: const Icon(Icons.arrow_back_ios),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop(
|
|
||||||
selectedRulesetIndex == -1
|
|
||||||
? null
|
|
||||||
: widget.rulesets[selectedRulesetIndex].$1,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
title: Text(loc.choose_ruleset),
|
|
||||||
),
|
|
||||||
body: PopScope(
|
|
||||||
// This fixes that the Android Back Gesture didn't return the
|
|
||||||
// selectedRulesetIndex and therefore the selected Ruleset wasn't saved
|
|
||||||
canPop: false,
|
|
||||||
onPopInvokedWithResult: (bool didPop, Object? result) {
|
|
||||||
if (didPop) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Navigator.of(context).pop(
|
|
||||||
selectedRulesetIndex == -1
|
|
||||||
? null
|
|
||||||
: widget.rulesets[selectedRulesetIndex].$1,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: ListView.builder(
|
|
||||||
padding: const EdgeInsets.only(bottom: 85),
|
|
||||||
itemCount: widget.rulesets.length,
|
|
||||||
itemBuilder: (BuildContext context, int index) {
|
|
||||||
return TitleDescriptionListTile(
|
|
||||||
onPressed: () async {
|
|
||||||
setState(() {
|
|
||||||
if (selectedRulesetIndex == index) {
|
|
||||||
selectedRulesetIndex = -1;
|
|
||||||
} else {
|
|
||||||
selectedRulesetIndex = index;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
title: translateRulesetToString(
|
|
||||||
widget.rulesets[index].$1,
|
|
||||||
context,
|
|
||||||
),
|
|
||||||
description: widget.rulesets[index].$2,
|
|
||||||
isHighlighted: selectedRulesetIndex == index,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +1,30 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/adaptive_page_route.dart';
|
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:game_tracker/core/enums.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
|
||||||
import 'package:game_tracker/data/dto/match.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_game_view.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_group_view.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/choose_ruleset_view.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/player_selection.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/text_input/text_input_field.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/choose_tile.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/adaptive_page_route.dart';
|
||||||
|
import 'package:tallee/core/constants.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/core/enums.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/dto/group.dart';
|
||||||
|
import 'package:tallee/data/dto/match.dart';
|
||||||
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/match_view/create_match/choose_game_view.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/match_view/create_match/choose_group_view.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/custom_width_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/player_selection.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/text_input/text_input_field.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/choose_tile.dart';
|
||||||
|
|
||||||
class CreateMatchView extends StatefulWidget {
|
class CreateMatchView extends StatefulWidget {
|
||||||
final VoidCallback? onWinnerChanged;
|
/// A view that allows creating a new match
|
||||||
|
/// [onWinnerChanged]: Optional callback invoked when the winner is changed
|
||||||
const CreateMatchView({super.key, this.onWinnerChanged});
|
const CreateMatchView({super.key, this.onWinnerChanged});
|
||||||
|
|
||||||
|
/// Optional callback invoked when the winner is changed
|
||||||
|
final VoidCallback? onWinnerChanged;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CreateMatchView> createState() => _CreateMatchViewState();
|
State<CreateMatchView> createState() => _CreateMatchViewState();
|
||||||
}
|
}
|
||||||
@@ -53,13 +57,6 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
/// the [ChooseGroupView]
|
/// the [ChooseGroupView]
|
||||||
String selectedGroupId = '';
|
String selectedGroupId = '';
|
||||||
|
|
||||||
/// The currently selected ruleset
|
|
||||||
Ruleset? selectedRuleset;
|
|
||||||
|
|
||||||
/// The index of the currently selected ruleset in [rulesets] to mark it in
|
|
||||||
/// the [ChooseRulesetView]
|
|
||||||
int selectedRulesetIndex = -1;
|
|
||||||
|
|
||||||
/// The index of the currently selected game in [games] to mark it in
|
/// The index of the currently selected game in [games] to mark it in
|
||||||
/// the [ChooseGameView]
|
/// the [ChooseGameView]
|
||||||
int selectedGameIndex = -1;
|
int selectedGameIndex = -1;
|
||||||
@@ -67,9 +64,6 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
/// The currently selected players
|
/// The currently selected players
|
||||||
List<Player>? selectedPlayers;
|
List<Player>? selectedPlayers;
|
||||||
|
|
||||||
/// List of available rulesets with their localized string representations
|
|
||||||
late final List<(Ruleset, String)> _rulesets;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -102,15 +96,8 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
hintText ??= loc.match_name;
|
hintText ??= loc.match_name;
|
||||||
_rulesets = [
|
|
||||||
(Ruleset.singleWinner, loc.ruleset_single_winner),
|
|
||||||
(Ruleset.singleLoser, loc.ruleset_single_loser),
|
|
||||||
(Ruleset.mostPoints, loc.ruleset_most_points),
|
|
||||||
(Ruleset.leastPoints, loc.ruleset_least_points),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace when games are implemented
|
|
||||||
List<(String, String, Ruleset)> games = [
|
List<(String, String, Ruleset)> games = [
|
||||||
('Example Game 1', 'This is a description', Ruleset.leastPoints),
|
('Example Game 1', 'This is a description', Ruleset.leastPoints),
|
||||||
('Example Game 2', '', Ruleset.singleWinner),
|
('Example Game 2', '', Ruleset.singleWinner),
|
||||||
@@ -121,6 +108,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
return ScaffoldMessenger(
|
return ScaffoldMessenger(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
backgroundColor: CustomTheme.backgroundColor,
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
appBar: AppBar(title: Text(loc.create_new_match)),
|
appBar: AppBar(title: Text(loc.create_new_match)),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
@@ -132,6 +120,7 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
child: TextInputField(
|
child: TextInputField(
|
||||||
controller: _matchNameController,
|
controller: _matchNameController,
|
||||||
hintText: hintText ?? '',
|
hintText: hintText ?? '',
|
||||||
|
maxLength: Constants.MAX_MATCH_NAME_LENGTH,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ChooseTile(
|
ChooseTile(
|
||||||
@@ -151,39 +140,12 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
if (selectedGameIndex != -1) {
|
if (selectedGameIndex != -1) {
|
||||||
hintText = games[selectedGameIndex].$1;
|
hintText = games[selectedGameIndex].$1;
|
||||||
selectedRuleset = games[selectedGameIndex].$3;
|
|
||||||
selectedRulesetIndex = _rulesets.indexWhere(
|
|
||||||
(r) => r.$1 == selectedRuleset,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
hintText = loc.match_name;
|
hintText = loc.match_name;
|
||||||
selectedRuleset = null;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ChooseTile(
|
|
||||||
title: loc.ruleset,
|
|
||||||
trailingText: selectedRuleset == null
|
|
||||||
? loc.none
|
|
||||||
: translateRulesetToString(selectedRuleset!, context),
|
|
||||||
onPressed: () async {
|
|
||||||
selectedRuleset = await Navigator.of(context).push(
|
|
||||||
adaptivePageRoute(
|
|
||||||
builder: (context) => ChooseRulesetView(
|
|
||||||
rulesets: _rulesets,
|
|
||||||
initialRulesetIndex: selectedRulesetIndex,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (!mounted) return;
|
|
||||||
selectedRulesetIndex = _rulesets.indexWhere(
|
|
||||||
(r) => r.$1 == selectedRuleset,
|
|
||||||
);
|
|
||||||
selectedGameIndex = -1;
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
ChooseTile(
|
ChooseTile(
|
||||||
title: loc.group,
|
title: loc.group,
|
||||||
trailingText: selectedGroup == null
|
trailingText: selectedGroup == null
|
||||||
@@ -202,7 +164,8 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
if (selectedGroup != null) {
|
if (selectedGroup != null) {
|
||||||
filteredPlayerList = playerList
|
filteredPlayerList = playerList
|
||||||
.where(
|
.where(
|
||||||
(p) => !selectedGroup!.members.any((m) => m.id == p.id),
|
(p) =>
|
||||||
|
!selectedGroup!.members.any((m) => m.id == p.id),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
} else {
|
} else {
|
||||||
@@ -267,7 +230,6 @@ class _CreateMatchViewState extends State<CreateMatchView> {
|
|||||||
/// - Either a group is selected OR at least 2 players are selected
|
/// - Either a group is selected OR at least 2 players are selected
|
||||||
bool _enableCreateGameButton() {
|
bool _enableCreateGameButton() {
|
||||||
return (selectedGroup != null ||
|
return (selectedGroup != null ||
|
||||||
(selectedPlayers != null && selectedPlayers!.length > 1)) &&
|
(selectedPlayers != null && selectedPlayers!.length > 1));
|
||||||
selectedRuleset != null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,24 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/dto/match.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/custom_radio_list_tile.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/dto/match.dart';
|
||||||
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/custom_radio_list_tile.dart';
|
||||||
|
|
||||||
class MatchResultView extends StatefulWidget {
|
class MatchResultView extends StatefulWidget {
|
||||||
|
/// A view that allows selecting and saving the winner of a match
|
||||||
|
/// [match]: The match for which the winner is to be selected
|
||||||
|
/// [onWinnerChanged]: Optional callback invoked when the winner is changed
|
||||||
|
const MatchResultView({super.key, required this.match, this.onWinnerChanged});
|
||||||
|
|
||||||
|
/// The match for which the winner is to be selected
|
||||||
final Match match;
|
final Match match;
|
||||||
|
|
||||||
|
/// Optional callback invoked when the winner is changed
|
||||||
final VoidCallback? onWinnerChanged;
|
final VoidCallback? onWinnerChanged;
|
||||||
|
|
||||||
const MatchResultView({super.key, required this.match, this.onWinnerChanged});
|
|
||||||
@override
|
@override
|
||||||
State<MatchResultView> createState() => _MatchResultViewState();
|
State<MatchResultView> createState() => _MatchResultViewState();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
import 'dart:core' hide Match;
|
import 'dart:core' hide Match;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/adaptive_page_route.dart';
|
import 'package:fluttericon/rpg_awesome_icons.dart';
|
||||||
import 'package:game_tracker/core/constants.dart';
|
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
|
||||||
import 'package:game_tracker/data/dto/match.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/match_view/create_match/create_match_view.dart';
|
|
||||||
import 'package:game_tracker/presentation/views/main_menu/match_view/match_result_view.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/buttons/custom_width_button.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/match_tile.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/top_centered_message.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/adaptive_page_route.dart';
|
||||||
|
import 'package:tallee/core/constants.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/dto/group.dart';
|
||||||
|
import 'package:tallee/data/dto/match.dart';
|
||||||
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/match_view/create_match/create_match_view.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/app_skeleton.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/match_tile.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/top_centered_message.dart';
|
||||||
|
|
||||||
class MatchView extends StatefulWidget {
|
class MatchView extends StatefulWidget {
|
||||||
|
/// A view that displays a list of matches
|
||||||
const MatchView({super.key});
|
const MatchView({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -104,10 +106,10 @@ class _MatchViewState extends State<MatchView> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
bottom: MediaQuery.paddingOf(context).bottom,
|
bottom: MediaQuery.paddingOf(context).bottom + 20,
|
||||||
child: CustomWidthButton(
|
child: MainMenuButton(
|
||||||
text: loc.create_match,
|
text: 'Spiel erstellen',
|
||||||
sizeRelativeToWidth: 0.90,
|
icon: RpgAwesome.clovers_card,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
@@ -128,7 +130,7 @@ class _MatchViewState extends State<MatchView> {
|
|||||||
void loadGames() {
|
void loadGames() {
|
||||||
Future.wait([
|
Future.wait([
|
||||||
db.matchDao.getAllMatches(),
|
db.matchDao.getAllMatches(),
|
||||||
Future.delayed(Constants.minimumSkeletonDuration),
|
Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
|
||||||
]).then((results) {
|
]).then((results) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
|
import 'package:tallee/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/colored_icon_container.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class LicenseDetailView extends StatelessWidget {
|
class LicenseDetailView extends StatelessWidget {
|
||||||
final Package package;
|
/// A detailed view displaying information about a software package license.
|
||||||
|
/// - [package]: The package data to be displayed.
|
||||||
const LicenseDetailView({super.key, required this.package});
|
const LicenseDetailView({super.key, required this.package});
|
||||||
|
|
||||||
|
/// The package data to be displayed.
|
||||||
|
final Package package;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
@@ -26,19 +30,11 @@ class LicenseDetailView extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
const ColoredIconContainer(
|
||||||
margin: const EdgeInsetsGeometry.only(right: 15),
|
icon: Icons.description,
|
||||||
width: 60,
|
margin: EdgeInsetsGeometry.only(right: 15),
|
||||||
height: 60,
|
containerSize: 60,
|
||||||
decoration: BoxDecoration(
|
iconSize: 30,
|
||||||
color: CustomTheme.primaryColor.withAlpha(40),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
Icons.description,
|
|
||||||
color: CustomTheme.primaryColor,
|
|
||||||
size: 30,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -93,7 +89,7 @@ class LicenseDetailView extends StatelessWidget {
|
|||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: CustomTheme.secondaryColor,
|
color: CustomTheme.secondaryColor,
|
||||||
decoration: TextDecoration.underline,
|
decoration: TextDecoration.underline,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// https://pub.dev/packages/dart_pubspec_licenses
|
// https://pub.dev/packages/dart_pubspec_licenses
|
||||||
|
|
||||||
/// This package.
|
/// This package.
|
||||||
const thisPackage = _game_tracker;
|
const thisPackage = _tallee;
|
||||||
|
|
||||||
/// All dependencies including transitive dependencies.
|
/// All dependencies including transitive dependencies.
|
||||||
const allDependencies = <Package>[
|
const allDependencies = <Package>[
|
||||||
@@ -7291,9 +7291,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|||||||
SOFTWARE.''',
|
SOFTWARE.''',
|
||||||
);
|
);
|
||||||
|
|
||||||
/// game_tracker 0.0.5+127
|
/// tallee 0.0.5+127
|
||||||
const _game_tracker = Package(
|
const _tallee = Package(
|
||||||
name: 'game_tracker',
|
name: 'tallee',
|
||||||
description: 'Game Tracking App for Card Games',
|
description: 'Game Tracking App for Card Games',
|
||||||
authors: [],
|
authors: [],
|
||||||
version: '0.0.5+127',
|
version: '0.0.5+127',
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
|
import 'package:tallee/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/license_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/license_tile.dart';
|
||||||
|
|
||||||
class LicensesView extends StatelessWidget {
|
class LicensesView extends StatelessWidget {
|
||||||
|
/// A view that displays a list of open source licenses used in the app
|
||||||
const LicensesView({super.key});
|
const LicensesView({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -3,17 +3,21 @@ import 'dart:io';
|
|||||||
import 'package:flutter/cupertino.dart';
|
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:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:game_tracker/core/enums.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/services/data_transfer_service.dart';
|
|
||||||
import 'package:intl/intl.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:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/core/enums.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/views/main_menu/settings_view/licenses_view.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/custom_alert_dialog.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/settings_list_tile.dart';
|
||||||
|
import 'package:tallee/services/data_transfer_service.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class SettingsView extends StatefulWidget {
|
class SettingsView extends StatefulWidget {
|
||||||
|
/// The settings view of the application, allowing users to manage data
|
||||||
|
/// and view legal information.
|
||||||
const SettingsView({super.key});
|
const SettingsView({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -37,194 +41,228 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
return ScaffoldMessenger(
|
return ScaffoldMessenger(
|
||||||
child: Scaffold(
|
child: Builder(
|
||||||
appBar: AppBar(backgroundColor: CustomTheme.backgroundColor),
|
builder: (scaffoldMessengerContext) {
|
||||||
backgroundColor: CustomTheme.backgroundColor,
|
return Scaffold(
|
||||||
body: SingleChildScrollView(
|
appBar: AppBar(backgroundColor: CustomTheme.backgroundColor),
|
||||||
child: Column(
|
backgroundColor: CustomTheme.backgroundColor,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
body: SingleChildScrollView(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Column(
|
||||||
children: [
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
Padding(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
padding: const EdgeInsets.only(left: 16, bottom: 10),
|
children: [
|
||||||
child: Text(
|
Padding(
|
||||||
textAlign: TextAlign.start,
|
padding: const EdgeInsets.only(left: 16, bottom: 10),
|
||||||
loc.settings,
|
child: Text(
|
||||||
style: const TextStyle(
|
textAlign: TextAlign.start,
|
||||||
fontSize: 28,
|
loc.settings,
|
||||||
fontWeight: FontWeight.bold,
|
style: const TextStyle(
|
||||||
),
|
fontSize: 28,
|
||||||
),
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 16, top: 10, bottom: 10),
|
|
||||||
child: Text(
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
loc.data,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 22,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SettingsListTile(
|
|
||||||
title: loc.export_data,
|
|
||||||
icon: Icons.upload,
|
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
|
||||||
onPressed: () async {
|
|
||||||
final String json =
|
|
||||||
await DataTransferService.getAppDataAsJson(context);
|
|
||||||
final result = await DataTransferService.exportData(
|
|
||||||
json,
|
|
||||||
'game_tracker-data',
|
|
||||||
);
|
|
||||||
if (!context.mounted) return;
|
|
||||||
showExportSnackBar(context: context, result: result);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
SettingsListTile(
|
|
||||||
title: loc.import_data,
|
|
||||||
icon: Icons.download,
|
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
|
||||||
onPressed: () async {
|
|
||||||
final result = await DataTransferService.importData(context);
|
|
||||||
if (!context.mounted) return;
|
|
||||||
showImportSnackBar(context: context, result: result);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
SettingsListTile(
|
|
||||||
title: loc.delete_all_data,
|
|
||||||
icon: Icons.delete,
|
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
|
||||||
onPressed: () {
|
|
||||||
showDialog<bool>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: Text('${loc.delete_all_data}?'),
|
|
||||||
content: Text(loc.this_cannot_be_undone),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(false),
|
|
||||||
child: Text(loc.cancel),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(true),
|
|
||||||
child: Text(loc.delete),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
).then((confirmed) {
|
),
|
||||||
if (confirmed == true && context.mounted) {
|
Padding(
|
||||||
DataTransferService.deleteAllData(context);
|
padding: const EdgeInsets.only(
|
||||||
showSnackbar(
|
left: 16,
|
||||||
context: context,
|
top: 10,
|
||||||
message: AppLocalizations.of(
|
bottom: 10,
|
||||||
context,
|
),
|
||||||
).data_successfully_deleted,
|
child: Text(
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
loc.data,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SettingsListTile(
|
||||||
|
title: loc.export_data,
|
||||||
|
icon: Icons.upload,
|
||||||
|
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
|
onPressed: () async {
|
||||||
|
final String json =
|
||||||
|
await DataTransferService.getAppDataAsJson(
|
||||||
|
scaffoldMessengerContext,
|
||||||
|
);
|
||||||
|
final result = await DataTransferService.exportData(
|
||||||
|
json,
|
||||||
|
'tallee-data',
|
||||||
);
|
);
|
||||||
}
|
if (!scaffoldMessengerContext.mounted) return;
|
||||||
});
|
showExportSnackBar(
|
||||||
},
|
context: scaffoldMessengerContext,
|
||||||
),
|
result: result,
|
||||||
Padding(
|
);
|
||||||
padding: const EdgeInsets.only(left: 16, top: 10, bottom: 10),
|
},
|
||||||
child: Text(
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
loc.legal,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 22,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
),
|
||||||
),
|
SettingsListTile(
|
||||||
),
|
title: loc.import_data,
|
||||||
SettingsListTile(
|
icon: Icons.download,
|
||||||
title: loc.licenses,
|
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
icon: Icons.insert_drive_file,
|
onPressed: () async {
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
final result = await DataTransferService.importData(
|
||||||
onPressed: () {
|
scaffoldMessengerContext,
|
||||||
Navigator.of(context).push(
|
);
|
||||||
MaterialPageRoute(
|
if (!scaffoldMessengerContext.mounted) return;
|
||||||
builder: (context) => const LicensesView(),
|
showImportSnackBar(
|
||||||
),
|
context: scaffoldMessengerContext,
|
||||||
);
|
result: result,
|
||||||
},
|
);
|
||||||
),
|
},
|
||||||
SettingsListTile(
|
),
|
||||||
title: loc.legal_notice,
|
SettingsListTile(
|
||||||
icon: Icons.account_balance_sharp,
|
title: loc.delete_all_data,
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
icon: Icons.delete,
|
||||||
onPressed: null,
|
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
),
|
onPressed: () {
|
||||||
SettingsListTile(
|
showDialog<bool>(
|
||||||
title: loc.privacy_policy,
|
context: context,
|
||||||
icon: Icons.gpp_good_rounded,
|
builder: (context) => CustomAlertDialog(
|
||||||
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
title: '${loc.delete_all_data}?',
|
||||||
onPressed: null,
|
content: loc.this_cannot_be_undone,
|
||||||
),
|
actions: [
|
||||||
Padding(
|
AnimatedDialogButton(
|
||||||
padding: const EdgeInsets.only(top: 30, bottom: 20),
|
onPressed: () => Navigator.of(context).pop(false),
|
||||||
child: Center(
|
child: Text(
|
||||||
child: Column(
|
loc.cancel,
|
||||||
spacing: 4,
|
style: const TextStyle(
|
||||||
children: [
|
color: CustomTheme.textColor,
|
||||||
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'),
|
AnimatedDialogButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(true),
|
||||||
|
child: Text(
|
||||||
|
loc.delete,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: CustomTheme.secondaryColor,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
).then((confirmed) {
|
||||||
Text(
|
if (confirmed == true && context.mounted) {
|
||||||
'© ${DateFormat('yyyy').format(DateTime.now())} Liquid Development',
|
DataTransferService.deleteAllData(context);
|
||||||
style: TextStyle(
|
showSnackbar(
|
||||||
color: Colors.grey.shade600,
|
context: scaffoldMessengerContext,
|
||||||
fontSize: 14,
|
message: AppLocalizations.of(
|
||||||
fontWeight: FontWeight.w600,
|
context,
|
||||||
),
|
).data_successfully_deleted,
|
||||||
),
|
);
|
||||||
Text(
|
}
|
||||||
'Version ${_packageInfo.version} (${_packageInfo.buildNumber})',
|
});
|
||||||
style: TextStyle(
|
},
|
||||||
color: Colors.grey.shade600,
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
left: 16,
|
||||||
|
top: 10,
|
||||||
|
bottom: 10,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
loc.legal,
|
||||||
|
style: const 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(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SettingsListTile(
|
||||||
|
title: loc.legal_notice,
|
||||||
|
icon: Icons.account_balance_sharp,
|
||||||
|
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
|
onPressed: null,
|
||||||
|
),
|
||||||
|
SettingsListTile(
|
||||||
|
title: loc.privacy_policy,
|
||||||
|
icon: Icons.gpp_good_rounded,
|
||||||
|
suffixWidget: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||||
|
onPressed: null,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 30, bottom: 20),
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
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})',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.grey.shade600,
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
);
|
||||||
),
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -285,10 +323,11 @@ class _SettingsViewState extends State<SettingsView> {
|
|||||||
Duration duration = const Duration(seconds: 3),
|
Duration duration = const Duration(seconds: 3),
|
||||||
VoidCallback? action,
|
VoidCallback? action,
|
||||||
}) {
|
}) {
|
||||||
|
if (!context.mounted) return;
|
||||||
|
|
||||||
final loc = AppLocalizations.of(context);
|
final loc = AppLocalizations.of(context);
|
||||||
final messenger = ScaffoldMessenger.of(context);
|
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||||
messenger.hideCurrentSnackBar();
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
messenger.showSnackBar(
|
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(message, style: const TextStyle(color: Colors.white)),
|
content: Text(message, style: const TextStyle(color: Colors.white)),
|
||||||
backgroundColor: CustomTheme.onBoxColor,
|
backgroundColor: CustomTheme.onBoxColor,
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/constants.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/dto/match.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/statistics_tile.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/top_centered_message.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/constants.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/dto/match.dart';
|
||||||
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/app_skeleton.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/statistics_tile.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/top_centered_message.dart';
|
||||||
|
|
||||||
class StatisticsView extends StatefulWidget {
|
class StatisticsView extends StatefulWidget {
|
||||||
|
/// A view that displays player statistics
|
||||||
const StatisticsView({super.key});
|
const StatisticsView({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -105,7 +106,7 @@ class _StatisticsViewState extends State<StatisticsView> {
|
|||||||
Future.wait([
|
Future.wait([
|
||||||
db.matchDao.getAllMatches(),
|
db.matchDao.getAllMatches(),
|
||||||
db.playerDao.getAllPlayers(),
|
db.playerDao.getAllPlayers(),
|
||||||
Future.delayed(Constants.minimumSkeletonDuration),
|
Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
|
||||||
]).then((results) async {
|
]).then((results) async {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
final matches = results[0] as List<Match>;
|
final matches = results[0] as List<Match>;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:skeletonizer/skeletonizer.dart';
|
import 'package:skeletonizer/skeletonizer.dart';
|
||||||
|
|
||||||
/// A widget that provides a skeleton loading effect to its child widget tree.
|
|
||||||
/// - [child]: The widget tree to apply the skeleton effect to.
|
|
||||||
/// - [enabled]: A boolean to enable or disable the skeleton effect.
|
|
||||||
/// - [fixLayoutBuilder]: A boolean to fix the layout builder for AnimatedSwitcher.
|
|
||||||
class AppSkeleton extends StatefulWidget {
|
class AppSkeleton extends StatefulWidget {
|
||||||
|
/// A widget that provides a skeleton loading effect to its child widget tree.
|
||||||
|
/// - [child]: The widget tree to apply the skeleton effect to.
|
||||||
|
/// - [enabled]: A boolean to enable or disable the skeleton effect.
|
||||||
|
/// - [fixLayoutBuilder]: A boolean to fix the layout builder for AnimatedSwitcher.
|
||||||
const AppSkeleton({
|
const AppSkeleton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.child,
|
required this.child,
|
||||||
|
|||||||
50
lib/presentation/widgets/buttons/animated_dialog_button.dart
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
|
class AnimatedDialogButton extends StatefulWidget {
|
||||||
|
/// A custom animated button widget that provides a scaling and opacity effect
|
||||||
|
/// when pressed.
|
||||||
|
/// - [onPressed]: Callback function that is triggered when the button is pressed.
|
||||||
|
/// - [child]: The child widget to be displayed inside the button, typically a text or icon.
|
||||||
|
const AnimatedDialogButton({
|
||||||
|
super.key,
|
||||||
|
required this.onPressed,
|
||||||
|
required this.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Callback function that is triggered when the button is pressed.
|
||||||
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
|
/// The child widget to be displayed inside the button, typically a text or icon.
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AnimatedDialogButton> createState() => _AnimatedDialogButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AnimatedDialogButtonState extends State<AnimatedDialogButton> {
|
||||||
|
bool _isPressed = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTapDown: (_) => setState(() => _isPressed = true),
|
||||||
|
onTapUp: (_) => setState(() => _isPressed = false),
|
||||||
|
onTapCancel: () => setState(() => _isPressed = false),
|
||||||
|
onTap: widget.onPressed,
|
||||||
|
child: AnimatedScale(
|
||||||
|
scale: _isPressed ? 0.95 : 1.0,
|
||||||
|
duration: const Duration(milliseconds: 100),
|
||||||
|
child: AnimatedOpacity(
|
||||||
|
opacity: _isPressed ? 0.6 : 1.0,
|
||||||
|
duration: const Duration(milliseconds: 100),
|
||||||
|
child: Container(
|
||||||
|
decoration: CustomTheme.standardBoxDecoration,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 26, vertical: 6),
|
||||||
|
child: widget.child,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:game_tracker/core/enums.dart';
|
import 'package:tallee/core/enums.dart';
|
||||||
|
|
||||||
/// A custom button widget that is designed to have a width relative to the screen size.
|
|
||||||
/// It supports three types of buttons: primary, secondary, and text buttons.
|
|
||||||
/// - [text]: The text to display on the button.
|
|
||||||
/// - [buttonType]: The type of button to display. Defaults to [ButtonType.primary].
|
|
||||||
/// - [sizeRelativeToWidth]: The size of the button relative to the width of the screen.
|
|
||||||
/// - [onPressed]: The callback to be invoked when the button is pressed.
|
|
||||||
class CustomWidthButton extends StatelessWidget {
|
class CustomWidthButton extends StatelessWidget {
|
||||||
|
/// A custom button widget that is designed to have a width relative to the screen size.
|
||||||
|
/// It supports three types of buttons: primary, secondary, and text buttons.
|
||||||
|
/// - [text]: The text to display on the button.
|
||||||
|
/// - [buttonType]: The type of button to display. Defaults to [ButtonType.primary].
|
||||||
|
/// - [sizeRelativeToWidth]: The size of the button relative to the width of the screen.
|
||||||
|
/// - [onPressed]: The callback to be invoked when the button is pressed.
|
||||||
const CustomWidthButton({
|
const CustomWidthButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.text,
|
required this.text,
|
||||||
|
|||||||
98
lib/presentation/widgets/buttons/main_menu_button.dart
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class MainMenuButton extends StatefulWidget {
|
||||||
|
/// A button for the main menu with an optional icon and a press animation.
|
||||||
|
/// - [text]: The text of the button.
|
||||||
|
/// - [icon]: The icon of the button.
|
||||||
|
/// - [onPressed]: The callback to be invoked when the button is pressed.
|
||||||
|
const MainMenuButton({
|
||||||
|
super.key,
|
||||||
|
required this.text,
|
||||||
|
this.icon,
|
||||||
|
required this.onPressed,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The text of the button.
|
||||||
|
final String text;
|
||||||
|
|
||||||
|
/// The icon of the button.
|
||||||
|
final IconData? icon;
|
||||||
|
|
||||||
|
/// The callback to be invoked when the button is pressed.
|
||||||
|
final void Function() onPressed;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MainMenuButton> createState() => _MainMenuButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MainMenuButtonState extends State<MainMenuButton>
|
||||||
|
with SingleTickerProviderStateMixin {
|
||||||
|
late AnimationController _animationController;
|
||||||
|
late Animation<double> _scaleAnimation;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_animationController = AnimationController(
|
||||||
|
duration: const Duration(milliseconds: 100),
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
|
|
||||||
|
_scaleAnimation = Tween<double>(begin: 1.0, end: 0.95).animate(
|
||||||
|
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ScaleTransition(
|
||||||
|
scale: _scaleAnimation,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTapDown: (_) {
|
||||||
|
_animationController.forward();
|
||||||
|
},
|
||||||
|
onTapUp: (_) async {
|
||||||
|
await _animationController.reverse();
|
||||||
|
if (mounted) {
|
||||||
|
widget.onPressed();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onTapCancel: () {
|
||||||
|
_animationController.reverse();
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(30),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 14),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
if (widget.icon != null) ...[
|
||||||
|
Icon(widget.icon, size: 26, color: Colors.black),
|
||||||
|
const SizedBox(width: 7),
|
||||||
|
],
|
||||||
|
Text(
|
||||||
|
widget.text,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_animationController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
/// A button widget designed for quick creating matches in the [HomeView]
|
|
||||||
/// - [text]: The text to display on the button.
|
|
||||||
/// - [onPressed]: The callback to be invoked when the button is pressed.
|
|
||||||
class QuickCreateButton extends StatefulWidget {
|
class QuickCreateButton extends StatefulWidget {
|
||||||
|
/// A button widget designed for quick creating matches in the [HomeView]
|
||||||
|
/// - [text]: The text to display on the button.
|
||||||
|
/// - [onPressed]: The callback to be invoked when the button is pressed.
|
||||||
const QuickCreateButton({
|
const QuickCreateButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.text,
|
required this.text,
|
||||||
@@ -28,14 +28,18 @@ class _QuickCreateButtonState extends State<QuickCreateButton> {
|
|||||||
onPressed: widget.onPressed,
|
onPressed: widget.onPressed,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
minimumSize: const Size(140, 45),
|
minimumSize: const Size(140, 45),
|
||||||
backgroundColor: CustomTheme.primaryColor,
|
backgroundColor: CustomTheme.primaryColor.withAlpha(200).withBlue(40),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: CustomTheme.standardBorderRadiusAll,
|
borderRadius: CustomTheme.standardBorderRadiusAll,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.text,
|
widget.text,
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
|
style: const TextStyle(
|
||||||
|
color: CustomTheme.textColor,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
57
lib/presentation/widgets/colored_icon_container.dart
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
|
class ColoredIconContainer extends StatelessWidget {
|
||||||
|
/// A customizable container widget that displays an icon with a colored background.
|
||||||
|
/// - [icon]: The icon to be displayed inside the container.
|
||||||
|
/// - [containerSize]: The size of the container (width and height).
|
||||||
|
/// - [iconSize]: The size of the icon inside the container.
|
||||||
|
/// - [margin]: Optional margin around the container.
|
||||||
|
/// - [padding]: Optional padding inside the container.
|
||||||
|
const ColoredIconContainer({
|
||||||
|
super.key,
|
||||||
|
required this.icon,
|
||||||
|
this.containerSize = 44,
|
||||||
|
this.iconSize = 28,
|
||||||
|
this.margin,
|
||||||
|
this.padding,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The icon to be displayed inside the container.
|
||||||
|
final IconData icon;
|
||||||
|
|
||||||
|
/// The size of the container (width and height).
|
||||||
|
final double containerSize;
|
||||||
|
|
||||||
|
/// The size of the icon inside the container.
|
||||||
|
final double iconSize;
|
||||||
|
|
||||||
|
/// Optional margin around the container.
|
||||||
|
final EdgeInsetsGeometry? margin;
|
||||||
|
|
||||||
|
/// Optional padding inside the container.
|
||||||
|
final EdgeInsetsGeometry? padding;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: containerSize,
|
||||||
|
height: containerSize,
|
||||||
|
margin: margin,
|
||||||
|
padding: padding,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: CustomTheme.primaryColor.withAlpha(40),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
icon,
|
||||||
|
size: iconSize,
|
||||||
|
color: CustomTheme.primaryColor.withBlue(40),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
39
lib/presentation/widgets/custom_alert_dialog.dart
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
|
class CustomAlertDialog extends StatelessWidget {
|
||||||
|
/// A custom alert dialog widget that provides a os unspecific AlertDialog,
|
||||||
|
/// with consistent colors, borders, and layout that match the app's custom theme.
|
||||||
|
/// - [title]: The title text displayed at the top of the dialog.
|
||||||
|
/// - [content]: The main content text displayed in the body of the dialog.
|
||||||
|
/// - [actions]: A list of action widgets (typically buttons) displayed at the bottom
|
||||||
|
/// of the dialog. These actions are horizontally spaced around the dialog's width.
|
||||||
|
const CustomAlertDialog({
|
||||||
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
required this.content,
|
||||||
|
required this.actions,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String title;
|
||||||
|
final String content;
|
||||||
|
final List<Widget> actions;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(title, style: const TextStyle(color: CustomTheme.textColor)),
|
||||||
|
content: Text(
|
||||||
|
content,
|
||||||
|
style: const TextStyle(color: CustomTheme.textColor),
|
||||||
|
),
|
||||||
|
actions: actions,
|
||||||
|
backgroundColor: CustomTheme.boxColor,
|
||||||
|
actionsAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: CustomTheme.standardBorderRadiusAll,
|
||||||
|
side: const BorderSide(color: CustomTheme.boxBorder),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
/// A navigation bar item widget that represents a single tab in a navigation bar.
|
|
||||||
/// - [index]: The index of the tab.
|
|
||||||
/// - [isSelected]: A boolean indicating whether the tab is currently selected.
|
|
||||||
/// - [icon]: The icon to display for the tab.
|
|
||||||
/// - [label]: The label to display for the tab.
|
|
||||||
/// - [onTabTapped]: The callback to be invoked when the tab is tapped.
|
|
||||||
class NavbarItem extends StatefulWidget {
|
class NavbarItem extends StatefulWidget {
|
||||||
|
/// A navigation bar item widget that represents a single tab in a navigation bar.
|
||||||
|
/// - [index]: The index of the tab.
|
||||||
|
/// - [isSelected]: A boolean indicating whether the tab is currently selected.
|
||||||
|
/// - [icon]: The icon to display for the tab.
|
||||||
|
/// - [label]: The label to display for the tab.
|
||||||
|
/// - [onTabTapped]: The callback to be invoked when the tab is tapped.
|
||||||
const NavbarItem({
|
const NavbarItem({
|
||||||
super.key,
|
super.key,
|
||||||
required this.index,
|
required this.index,
|
||||||
@@ -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(
|
||||||
widget.icon,
|
scale: widget.isSelected
|
||||||
color: widget.isSelected ? Colors.white : Colors.black,
|
? _scaleAnimation
|
||||||
|
: const AlwaysStoppedAnimation(1.0),
|
||||||
|
child: Icon(
|
||||||
|
widget.icon,
|
||||||
|
color: widget.isSelected
|
||||||
|
? CustomTheme.navBarItemSelectedColor
|
||||||
|
: CustomTheme.navBarItemUnselectedColor,
|
||||||
|
size: 32,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
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,24 +1,24 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/constants.dart';
|
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/app_skeleton.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/text_input/custom_search_bar.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/text_icon_list_tile.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart';
|
|
||||||
import 'package:game_tracker/presentation/widgets/top_centered_message.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tallee/core/constants.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
import 'package:tallee/data/db/database.dart';
|
||||||
|
import 'package:tallee/data/dto/player.dart';
|
||||||
|
import 'package:tallee/l10n/generated/app_localizations.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/app_skeleton.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/text_input/custom_search_bar.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/text_icon_list_tile.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/top_centered_message.dart';
|
||||||
|
|
||||||
/// A widget that allows users to select players from a list,
|
|
||||||
/// with search functionality and the ability to add new players.
|
|
||||||
/// - [availablePlayers]: An optional list of players to choose from. If null, all
|
|
||||||
/// players from the database are used.
|
|
||||||
/// - [initialSelectedPlayers]: An optional list of players that should be pre-selected.
|
|
||||||
/// - [onChanged]: A callback function that is invoked whenever the selection changes,
|
|
||||||
/// providing the updated list of selected players.
|
|
||||||
class PlayerSelection extends StatefulWidget {
|
class PlayerSelection extends StatefulWidget {
|
||||||
|
/// A widget that allows users to select players from a list,
|
||||||
|
/// with search functionality and the ability to add new players.
|
||||||
|
/// - [availablePlayers]: An optional list of players to choose from. If null,
|
||||||
|
/// all players from the database are used.
|
||||||
|
/// - [initialSelectedPlayers]: An optional list of players that should be pre-selected.
|
||||||
|
/// - [onChanged]: A callback function that is invoked whenever the selection
|
||||||
|
/// changes, providing the updated list of selected players.
|
||||||
const PlayerSelection({
|
const PlayerSelection({
|
||||||
super.key,
|
super.key,
|
||||||
this.availablePlayers,
|
this.availablePlayers,
|
||||||
@@ -84,6 +84,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
CustomSearchBar(
|
CustomSearchBar(
|
||||||
|
maxLength: Constants.MAX_PLAYER_NAME_LENGTH,
|
||||||
controller: _searchBarController,
|
controller: _searchBarController,
|
||||||
constraints: const BoxConstraints(maxHeight: 45, minHeight: 45),
|
constraints: const BoxConstraints(maxHeight: 45, minHeight: 45),
|
||||||
hintText: loc.search_for_players,
|
hintText: loc.search_for_players,
|
||||||
@@ -181,6 +182,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
|
|||||||
icon: Icons.info,
|
icon: Icons.info,
|
||||||
title: loc.info,
|
title: loc.info,
|
||||||
message: _getInfoText(context),
|
message: _getInfoText(context),
|
||||||
|
fullscreen: false,
|
||||||
),
|
),
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemCount: suggestedPlayers.length,
|
itemCount: suggestedPlayers.length,
|
||||||
@@ -218,7 +220,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
|
|||||||
void loadPlayerList() {
|
void loadPlayerList() {
|
||||||
_allPlayersFuture = Future.wait([
|
_allPlayersFuture = Future.wait([
|
||||||
db.playerDao.getAllPlayers(),
|
db.playerDao.getAllPlayers(),
|
||||||
Future.delayed(Constants.minimumSkeletonDuration),
|
Future.delayed(Constants.MINIMUM_SKELETON_DURATION),
|
||||||
]).then((results) => results[0] as List<Player>);
|
]).then((results) => results[0] as List<Player>);
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
_allPlayersFuture.then((loadedPlayers) {
|
_allPlayersFuture.then((loadedPlayers) {
|
||||||
@@ -294,6 +296,7 @@ class _PlayerSelectionState extends State<PlayerSelection> {
|
|||||||
/// [message] - The message to display in the snackbar.
|
/// [message] - The message to display in the snackbar.
|
||||||
void showSnackBarMessage(String message) {
|
void showSnackBarMessage(String message) {
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
|
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
backgroundColor: CustomTheme.boxColor,
|
backgroundColor: CustomTheme.boxColor,
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
/// A custom search bar widget that encapsulates a [SearchBar] with additional customization options.
|
|
||||||
/// - [controller]: The controller for the search bar's text input.
|
|
||||||
/// - [hintText]: The hint text displayed in the search bar when it is empty.
|
|
||||||
/// - [trailingButtonShown]: Whether to show the trailing button.
|
|
||||||
/// - [trailingButtonicon]: The icon for the trailing button.
|
|
||||||
/// - [trailingButtonEnabled]: Whether the trailing button is in enabled state.
|
|
||||||
/// - [onTrailingButtonPressed]: The callback invoked when the trailing button is pressed.
|
|
||||||
/// - [onChanged]: The callback invoked when the text in the search bar changes.
|
|
||||||
/// - [constraints]: The constraints for the search bar.
|
|
||||||
class CustomSearchBar extends StatelessWidget {
|
class CustomSearchBar extends StatelessWidget {
|
||||||
|
/// A custom search bar widget that encapsulates a [SearchBar] with additional customization options.
|
||||||
|
/// - [controller]: The controller for the search bar's text input.
|
||||||
|
/// - [hintText]: The hint text displayed in the search bar when it is empty.
|
||||||
|
/// - [trailingButtonShown]: Whether to show the trailing button.
|
||||||
|
/// - [trailingButtonicon]: The icon for the trailing button.
|
||||||
|
/// - [trailingButtonEnabled]: Whether the trailing button is in enabled state.
|
||||||
|
/// - [onTrailingButtonPressed]: The callback invoked when the trailing button is pressed.
|
||||||
|
/// - [onChanged]: The callback invoked when the text in the search bar changes.
|
||||||
|
/// - [constraints]: The constraints for the search bar.
|
||||||
const CustomSearchBar({
|
const CustomSearchBar({
|
||||||
super.key,
|
super.key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
@@ -21,6 +21,7 @@ class CustomSearchBar extends StatelessWidget {
|
|||||||
this.onTrailingButtonPressed,
|
this.onTrailingButtonPressed,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
this.constraints,
|
this.constraints,
|
||||||
|
this.maxLength,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The controller for the search bar's text input.
|
/// The controller for the search bar's text input.
|
||||||
@@ -47,8 +48,21 @@ class CustomSearchBar extends StatelessWidget {
|
|||||||
/// The constraints for the search bar.
|
/// The constraints for the search bar.
|
||||||
final BoxConstraints? constraints;
|
final BoxConstraints? constraints;
|
||||||
|
|
||||||
|
/// Optional parameter for maximum length of the input text.
|
||||||
|
final int? maxLength;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
/// Enforce maximum length on the input text
|
||||||
|
if (maxLength != null) {
|
||||||
|
if (controller.text.length > maxLength!) {
|
||||||
|
controller.text = controller.text.substring(0, maxLength);
|
||||||
|
controller.selection = TextSelection.fromPosition(
|
||||||
|
TextPosition(offset: controller.text.length),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return SearchBar(
|
return SearchBar(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
constraints:
|
constraints:
|
||||||
@@ -73,7 +87,9 @@ class CustomSearchBar extends StatelessWidget {
|
|||||||
const SizedBox(width: 5),
|
const SizedBox(width: 5),
|
||||||
],
|
],
|
||||||
backgroundColor: WidgetStateProperty.all(CustomTheme.boxColor),
|
backgroundColor: WidgetStateProperty.all(CustomTheme.boxColor),
|
||||||
side: WidgetStateProperty.all(BorderSide(color: CustomTheme.boxBorder)),
|
side: WidgetStateProperty.all(
|
||||||
|
const BorderSide(color: CustomTheme.boxBorder),
|
||||||
|
),
|
||||||
shape: WidgetStateProperty.all(
|
shape: WidgetStateProperty.all(
|
||||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,43 +1,53 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
/// A custom text input field widget that encapsulates a [TextField] with specific styling.
|
|
||||||
/// - [controller]: The controller for the text input field.
|
|
||||||
/// - [onChanged]: The callback invoked when the text in the field changes.
|
|
||||||
/// - [hintText]: The hint text displayed in the text input field when it is empty
|
|
||||||
class TextInputField extends StatelessWidget {
|
class TextInputField extends StatelessWidget {
|
||||||
|
/// A custom text input field widget that encapsulates a [TextField] with specific styling.
|
||||||
|
/// - [controller]: The controller for the text input field.
|
||||||
|
/// - [onChanged]: Optional callback invoked when the text in the field changes.
|
||||||
|
/// - [hintText]: The hint text displayed in the text input field when it is empty
|
||||||
|
/// - [maxLength]: Optional parameter for maximum length of the input text.
|
||||||
const TextInputField({
|
const TextInputField({
|
||||||
super.key,
|
super.key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
required this.hintText,
|
required this.hintText,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
|
this.maxLength,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The controller for the text input field.
|
/// The controller for the text input field.
|
||||||
final TextEditingController controller;
|
final TextEditingController controller;
|
||||||
|
|
||||||
/// The callback invoked when the text in the field changes.
|
/// Optional callback invoked when the text in the field changes.
|
||||||
final ValueChanged<String>? onChanged;
|
final ValueChanged<String>? onChanged;
|
||||||
|
|
||||||
/// The hint text displayed in the text input field when it is empty.
|
/// The hint text displayed in the text input field when it is empty.
|
||||||
final String hintText;
|
final String hintText;
|
||||||
|
|
||||||
|
/// Optional parameter for maximum length of the input text.
|
||||||
|
final int? maxLength;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return TextField(
|
return TextField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
|
maxLength: maxLength,
|
||||||
|
maxLengthEnforcement: MaxLengthEnforcement.truncateAfterCompositionEnds,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: CustomTheme.boxColor,
|
fillColor: CustomTheme.boxColor,
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
hintStyle: const TextStyle(fontSize: 18),
|
hintStyle: const TextStyle(fontSize: 18),
|
||||||
enabledBorder: OutlineInputBorder(
|
// Hides the character counter
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
counterText: '',
|
||||||
|
enabledBorder: const OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||||
borderSide: BorderSide(color: CustomTheme.boxBorder),
|
borderSide: BorderSide(color: CustomTheme.boxBorder),
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: const OutlineInputBorder(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||||
borderSide: BorderSide(color: CustomTheme.boxBorder),
|
borderSide: BorderSide(color: CustomTheme.boxBorder),
|
||||||
),
|
),
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
/// A tile widget that allows users to choose an option by tapping on it.
|
|
||||||
/// - [title]: The title text displayed on the tile.
|
|
||||||
/// - [trailingText]: Optional trailing text displayed on the tile.
|
|
||||||
/// - [onPressed]: The callback invoked when the tile is tapped.
|
|
||||||
class ChooseTile extends StatefulWidget {
|
class ChooseTile extends StatefulWidget {
|
||||||
|
/// A tile widget that allows users to choose an option by tapping on it.
|
||||||
|
/// - [title]: The title text displayed on the tile.
|
||||||
|
/// - [trailingText]: Optional trailing text displayed on the tile.
|
||||||
|
/// - [onPressed]: The callback invoked when the tile is tapped.
|
||||||
const ChooseTile({
|
const ChooseTile({
|
||||||
super.key,
|
super.key,
|
||||||
required this.title,
|
required this.title,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
/// A custom radio list tile widget that encapsulates a [Radio] button with additional styling and functionality.
|
|
||||||
/// - [text]: The text to display next to the radio button.
|
|
||||||
/// - [value]: The value associated with the radio button.
|
|
||||||
/// - [onContainerTap]: The callback invoked when the container is tapped.
|
|
||||||
class CustomRadioListTile<T> extends StatelessWidget {
|
class CustomRadioListTile<T> extends StatelessWidget {
|
||||||
|
/// A custom radio list tile widget that encapsulates a [Radio] button with additional styling and functionality.
|
||||||
|
/// - [text]: The text to display next to the radio button.
|
||||||
|
/// - [value]: The value associated with the radio button.
|
||||||
|
/// - [onContainerTap]: The callback invoked when the container is tapped.
|
||||||
const CustomRadioListTile({
|
const CustomRadioListTile({
|
||||||
super.key,
|
super.key,
|
||||||
required this.text,
|
required this.text,
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
import 'package:tallee/data/dto/group.dart';
|
||||||
import 'package:game_tracker/presentation/widgets/tiles/text_icon_tile.dart';
|
import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart';
|
||||||
|
|
||||||
/// A tile widget that displays information about a group, including its name and members.
|
class GroupTile extends StatefulWidget {
|
||||||
/// - [group]: The group data to be displayed.
|
/// A tile widget that displays information about a group, including its name and members.
|
||||||
/// - [isHighlighted]: Whether the tile should be highlighted.
|
/// - [group]: The group data to be displayed.
|
||||||
class GroupTile extends StatelessWidget {
|
/// - [isHighlighted]: Whether the tile should be highlighted.
|
||||||
const GroupTile({super.key, required this.group, this.isHighlighted = false});
|
/// - [onTap]: Callback function to be executed when the tile is tapped.
|
||||||
|
const GroupTile({
|
||||||
|
super.key,
|
||||||
|
required this.group,
|
||||||
|
this.isHighlighted = false,
|
||||||
|
this.onTap,
|
||||||
|
});
|
||||||
|
|
||||||
/// The group data to be displayed.
|
/// The group data to be displayed.
|
||||||
final Group group;
|
final Group group;
|
||||||
@@ -15,61 +21,72 @@ class GroupTile extends StatelessWidget {
|
|||||||
/// Whether the tile should be highlighted.
|
/// Whether the tile should be highlighted.
|
||||||
final bool isHighlighted;
|
final bool isHighlighted;
|
||||||
|
|
||||||
|
/// Callback function to be executed when the tile is tapped.
|
||||||
|
final VoidCallback? onTap;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<GroupTile> createState() => _GroupTileState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GroupTileState extends State<GroupTile> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AnimatedContainer(
|
return GestureDetector(
|
||||||
margin: CustomTheme.standardMargin,
|
onTap: widget.onTap,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
|
child: AnimatedContainer(
|
||||||
decoration: isHighlighted
|
margin: CustomTheme.standardMargin,
|
||||||
? CustomTheme.highlightedBoxDecoration
|
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
|
||||||
: CustomTheme.standardBoxDecoration,
|
decoration: widget.isHighlighted
|
||||||
duration: const Duration(milliseconds: 150),
|
? CustomTheme.highlightedBoxDecoration
|
||||||
child: Column(
|
: CustomTheme.standardBoxDecoration,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
duration: const Duration(milliseconds: 150),
|
||||||
children: [
|
child: Column(
|
||||||
Row(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
children: [
|
||||||
children: [
|
Row(
|
||||||
Flexible(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
child: Text(
|
children: [
|
||||||
group.name,
|
Flexible(
|
||||||
overflow: TextOverflow.ellipsis,
|
child: Text(
|
||||||
style: const TextStyle(
|
widget.group.name,
|
||||||
fontWeight: FontWeight.bold,
|
overflow: TextOverflow.ellipsis,
|
||||||
fontSize: 18,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'${group.members.length}',
|
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.w900,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 3),
|
),
|
||||||
const Icon(Icons.group, size: 22),
|
Row(
|
||||||
],
|
children: [
|
||||||
),
|
Text(
|
||||||
],
|
'${widget.group.members.length}',
|
||||||
),
|
style: const TextStyle(
|
||||||
const SizedBox(height: 5),
|
fontWeight: FontWeight.w900,
|
||||||
Wrap(
|
fontSize: 18,
|
||||||
alignment: WrapAlignment.start,
|
),
|
||||||
crossAxisAlignment: WrapCrossAlignment.start,
|
),
|
||||||
spacing: 12.0,
|
const SizedBox(width: 3),
|
||||||
runSpacing: 8.0,
|
const Icon(Icons.group, size: 22),
|
||||||
children: <Widget>[
|
],
|
||||||
for (var member in [
|
),
|
||||||
...group.members,
|
],
|
||||||
]..sort((a, b) => a.name.compareTo(b.name)))
|
),
|
||||||
TextIconTile(text: member.name, iconEnabled: false),
|
const SizedBox(height: 5),
|
||||||
],
|
Wrap(
|
||||||
),
|
alignment: WrapAlignment.start,
|
||||||
const SizedBox(height: 2.5),
|
crossAxisAlignment: WrapCrossAlignment.start,
|
||||||
],
|
spacing: 12.0,
|
||||||
|
runSpacing: 8.0,
|
||||||
|
children: <Widget>[
|
||||||
|
for (var member in [
|
||||||
|
...widget.group.members,
|
||||||
|
]..sort((a, b) => a.name.compareTo(b.name)))
|
||||||
|
TextIconTile(text: member.name, iconEnabled: false),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 2.5),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
|
|
||||||
/// A tile widget that displays a title with an icon and some content below it.
|
|
||||||
/// - [title]: The title text displayed on the tile.
|
|
||||||
/// - [icon]: The icon displayed next to the title.
|
|
||||||
/// - [content]: The content widget displayed below the title.
|
|
||||||
/// - [padding]: Optional padding for the tile content.
|
|
||||||
/// - [height]: Optional height for the tile.
|
|
||||||
/// - [width]: Optional width for the tile.
|
|
||||||
class InfoTile extends StatefulWidget {
|
class InfoTile extends StatefulWidget {
|
||||||
|
/// A tile widget that displays a title with an icon and some content below it.
|
||||||
|
/// - [title]: The title text displayed on the tile.
|
||||||
|
/// - [icon]: The icon displayed next to the title.
|
||||||
|
/// - [content]: The content widget displayed below the title.
|
||||||
|
/// - [padding]: Optional padding for the tile content.
|
||||||
|
/// - [height]: Optional height for the tile.
|
||||||
|
/// - [width]: Optional width for the tile.
|
||||||
const InfoTile({
|
const InfoTile({
|
||||||
super.key,
|
super.key,
|
||||||
required this.title,
|
required this.title,
|
||||||
@@ -17,6 +17,7 @@ class InfoTile extends StatefulWidget {
|
|||||||
this.padding,
|
this.padding,
|
||||||
this.height,
|
this.height,
|
||||||
this.width,
|
this.width,
|
||||||
|
this.horizontalAlignment = CrossAxisAlignment.center,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// The title text displayed on the tile.
|
/// The title text displayed on the tile.
|
||||||
@@ -37,6 +38,9 @@ class InfoTile extends StatefulWidget {
|
|||||||
/// Optional width for the tile.
|
/// Optional width for the tile.
|
||||||
final double? width;
|
final double? width;
|
||||||
|
|
||||||
|
/// The main axis alignment for the content.
|
||||||
|
final CrossAxisAlignment horizontalAlignment;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<InfoTile> createState() => _InfoTileState();
|
State<InfoTile> createState() => _InfoTileState();
|
||||||
}
|
}
|
||||||
@@ -51,7 +55,7 @@ class _InfoTileState extends State<InfoTile> {
|
|||||||
decoration: CustomTheme.standardBoxDecoration,
|
decoration: CustomTheme.standardBoxDecoration,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: widget.horizontalAlignment,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
import 'package:tallee/core/custom_theme.dart';
|
||||||
import 'package:game_tracker/presentation/views/main_menu/settings_view/licenses/license_detail_view.dart';
|
import 'package:tallee/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';
|
import 'package:tallee/presentation/views/main_menu/settings_view/licenses/oss_licenses.dart';
|
||||||
|
import 'package:tallee/presentation/widgets/colored_icon_container.dart';
|
||||||
|
|
||||||
class LicenseTile extends StatelessWidget {
|
class LicenseTile extends StatelessWidget {
|
||||||
final Package package;
|
/// A tile widget that displays information about a software package license.
|
||||||
|
/// - [package]: The package data to be displayed.
|
||||||
const LicenseTile({super.key, required this.package});
|
const LicenseTile({super.key, required this.package});
|
||||||
|
|
||||||
|
/// The package data to be displayed.
|
||||||
|
final Package package;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
@@ -26,18 +30,10 @@ class LicenseTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
const ColoredIconContainer(
|
||||||
width: 50,
|
icon: Icons.description,
|
||||||
height: 50,
|
containerSize: 50,
|
||||||
decoration: BoxDecoration(
|
iconSize: 32,
|
||||||
color: CustomTheme.primaryColor.withAlpha(40),
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
Icons.description,
|
|
||||||
color: CustomTheme.primaryColor,
|
|
||||||
size: 32,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
const SizedBox(width: 16),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:game_tracker/core/custom_theme.dart';
|
|
||||||
import 'package:skeletonizer/skeletonizer.dart';
|
|
||||||
|
|
||||||
class MatchSummaryTile extends StatefulWidget {
|
|
||||||
final String matchTitle;
|
|
||||||
final String game;
|
|
||||||
final String ruleset;
|
|
||||||
final String players;
|
|
||||||
final String winner;
|
|
||||||
|
|
||||||
const MatchSummaryTile({
|
|
||||||
super.key,
|
|
||||||
required this.matchTitle,
|
|
||||||
required this.game,
|
|
||||||
required this.ruleset,
|
|
||||||
required this.players,
|
|
||||||
required this.winner,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<MatchSummaryTile> createState() => _MatchSummaryTileState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MatchSummaryTileState extends State<MatchSummaryTile> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
widget.matchTitle,
|
|
||||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 5),
|
|
||||||
Text(
|
|
||||||
widget.game,
|
|
||||||
style: const TextStyle(fontSize: 14, color: Colors.grey),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
|
||||||
height: 20,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
color: CustomTheme.primaryColor,
|
|
||||||
),
|
|
||||||
child: Skeleton.ignore(
|
|
||||||
child: Text(
|
|
||||||
widget.ruleset,
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Center(
|
|
||||||
heightFactor: 1.5,
|
|
||||||
child: Text(
|
|
||||||
widget.players,
|
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Center(
|
|
||||||
child: Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
|
||||||
width: 220,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
|
||||||
color: Colors.yellow.shade300,
|
|
||||||
),
|
|
||||||
child: Skeleton.ignore(
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.emoji_events, color: Colors.black, size: 20),
|
|
||||||
Text(
|
|
||||||
widget.winner,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: Colors.black87,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||