Compare commits
8 Commits
v.0.0.1-al
...
d680ce596f
| Author | SHA1 | Date | |
|---|---|---|---|
| d680ce596f | |||
| fc062b2135 | |||
| 20537c88c1 | |||
| 42b15cef87 | |||
| cd0024d791 | |||
| 9544bf36d5 | |||
| 0c760e95ee | |||
| 7561ea73ed |
@@ -1,35 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Erstelle eine Meldung für etwas, das nicht Funktioniert, wie es soll.
|
|
||||||
title: ''
|
|
||||||
labels: 'Task/Bug'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Bug Report
|
|
||||||
|
|
||||||
## Beschreibung
|
|
||||||
[Eine klare und prägnante Beschreibung des Bugs]
|
|
||||||
|
|
||||||
## Schritte zur Reproduktion
|
|
||||||
1. Schritt 1
|
|
||||||
2. Schritt 2
|
|
||||||
3. ...
|
|
||||||
|
|
||||||
## Erwartetes Verhalten
|
|
||||||
[Was hätte passieren sollen]
|
|
||||||
|
|
||||||
## Tatsächliches Verhalten
|
|
||||||
[Was tatsächlich passiert ist]
|
|
||||||
|
|
||||||
## Screenshots/Protokolle
|
|
||||||
[Falls zutreffend, füge Screenshots, Error Logs oder Stack Traces hinzu]
|
|
||||||
|
|
||||||
## Umgebung
|
|
||||||
- Plattform: Android, iOS, Web
|
|
||||||
- OS: [z. B. iOS 18.5, Android 14]
|
|
||||||
- Flutter Version: [z.B. 3.35.6]
|
|
||||||
|
|
||||||
## Verwandte Issues
|
|
||||||
[Verweisen Sie auf ähnliche Issues oder PRs]
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
---
|
|
||||||
name: Enhancement
|
|
||||||
about: Enhancements for current features
|
|
||||||
title: ''
|
|
||||||
labels: 'Task\Enhancement'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Enhancement
|
|
||||||
|
|
||||||
## Aktuelles Verhalten
|
|
||||||
[Beschreibe die bestehende Funktionalität]
|
|
||||||
|
|
||||||
## Einschränkungen/Probleme
|
|
||||||
[Was sind die aktuellen Mängel?]
|
|
||||||
|
|
||||||
## Vorgeschlagene Verbesserung
|
|
||||||
[Wie kann das Problem bzw. die Einschränkung verbessert werden?]
|
|
||||||
|
|
||||||
## Zugehörige Issues
|
|
||||||
[Links zu verwandten oder blockierenden Issues]
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature
|
|
||||||
about: Neues Feature für die App
|
|
||||||
title: ''
|
|
||||||
labels: 'Task\Feature'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Feature
|
|
||||||
|
|
||||||
## Beschreibung
|
|
||||||
[Ausführliche Erläuterung der vorgeschlagenen Funktion]
|
|
||||||
|
|
||||||
## Vorgeschlagene Lösung
|
|
||||||
[Beschreibe, wie die Feature funktionieren soll]
|
|
||||||
|
|
||||||
## Zugehörige Issues
|
|
||||||
[Links zu verwandten oder blockierenden Issues]
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# [PR Titel]
|
|
||||||
|
|
||||||
**Zugehörige Issue(s):**
|
|
||||||
Closes `<issue-no>`
|
|
||||||
|
|
||||||
## Beschreibung
|
|
||||||
*Eine klare und prägnante Übersicht über die vorgenommenen Änderungen. Erläutere nicht nur das was gemacht wurde, sondern auch warum.*
|
|
||||||
|
|
||||||
## Änderungen
|
|
||||||
- [ ] Neue Funktion X hinzugefügt
|
|
||||||
- [ ] Bug in Komponente Y behoben
|
|
||||||
- [ ] Modul Z für bessere Leistung refactored
|
|
||||||
- [ ] Dependencies aktualisiert
|
|
||||||
|
|
||||||
## Zusätzliche Anmerkungen
|
|
||||||
*Gibt es zusätzlichen Kontext, Einschränkungen oder Informationen, die Reviewer wissen sollten?*
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
name: Pull Request Pipeline
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install jq
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y jq
|
|
||||||
|
|
||||||
- name: Install Flutter (wget)
|
|
||||||
run: |
|
|
||||||
wget 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
|
|
||||||
# Set Git safe directory for Flutter path
|
|
||||||
git config --global --add safe.directory "$(pwd)/flutter"
|
|
||||||
# Set Flutter path
|
|
||||||
echo "$(pwd)/flutter/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Get dependencies
|
|
||||||
run: flutter pub get
|
|
||||||
|
|
||||||
- name: Analyze Formatting
|
|
||||||
run: flutter analyze lib test
|
|
||||||
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y jq
|
|
||||||
|
|
||||||
- name: Install Flutter (wget)
|
|
||||||
run: |
|
|
||||||
wget 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
|
|
||||||
# Set Git safe directory for Flutter path
|
|
||||||
git config --global --add safe.directory "$(pwd)/flutter"
|
|
||||||
# Set Flutter path
|
|
||||||
echo "$(pwd)/flutter/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Get dependencies
|
|
||||||
run: flutter pub get
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
run: flutter test
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
name: Push Pipeline
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- "development"
|
|
||||||
- "main"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
format:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: false # Needs bot user
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
apt-get update
|
|
||||||
apt-get install -y jq
|
|
||||||
|
|
||||||
- name: Install Flutter (wget)
|
|
||||||
run: |
|
|
||||||
wget 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
|
|
||||||
# Set Git safe directory for Flutter path
|
|
||||||
git config --global --add safe.directory "$(pwd)/flutter"
|
|
||||||
# Set Flutter path
|
|
||||||
echo "$(pwd)/flutter/bin" >> $GITHUB_PATH
|
|
||||||
|
|
||||||
- name: Get & upgrade dependencies
|
|
||||||
run: |
|
|
||||||
flutter pub get
|
|
||||||
flutter pub upgrade --major-versions
|
|
||||||
|
|
||||||
- name: Auto-format
|
|
||||||
run: |
|
|
||||||
dart format lib
|
|
||||||
dart fix --apply lib
|
|
||||||
|
|
||||||
# Needs credentials, push access and the right files need to be staged
|
|
||||||
- name: Commit Changes
|
|
||||||
run: |
|
|
||||||
git config --global user.name "Gitea Actions"
|
|
||||||
git config --global user.email "actions@gitea.com"
|
|
||||||
git status
|
|
||||||
git add lib/
|
|
||||||
git status
|
|
||||||
git commit -m "Actions: Auto-formatting [skip ci]"
|
|
||||||
git push
|
|
||||||
1
.gitignore
vendored
@@ -195,4 +195,3 @@ app.*.map.json
|
|||||||
/android/app/debug
|
/android/app/debug
|
||||||
/android/app/profile
|
/android/app/profile
|
||||||
/android/app/release
|
/android/app/release
|
||||||
/devtools_options.yaml
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:screenOrientation="portrait"
|
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:taskAffinity=""
|
android:taskAffinity=""
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
@@ -42,5 +41,13 @@
|
|||||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||||
<data android:mimeType="text/plain"/>
|
<data android:mimeType="text/plain"/>
|
||||||
</intent>
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<data android:scheme="mailto" />
|
||||||
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 8.0 KiB |
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Modify this file to customize your launch splash screen -->
|
<!-- Modify this file to customize your launch splash screen -->
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:drawable="@color/launch_background" />
|
<item android:drawable="@android:color/white" />
|
||||||
|
|
||||||
<!-- You can insert your own image assets here -->
|
<!-- You can insert your own image assets here -->
|
||||||
<!-- <item>
|
<!-- <item>
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
|
||||||
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 544 B |
|
Before Width: | Height: | Size: 828 B |
|
Before Width: | Height: | Size: 448 B |
|
Before Width: | Height: | Size: 2.3 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 442 B |
|
Before Width: | Height: | Size: 656 B |
|
Before Width: | Height: | Size: 348 B |
|
Before Width: | Height: | Size: 1.5 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 721 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 508 B |
|
Before Width: | Height: | Size: 3.2 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 704 B |
|
Before Width: | Height: | Size: 4.9 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 824 B |
|
Before Width: | Height: | Size: 6.9 KiB |
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<color name="app_icon_background">#E6F1E4</color>
|
|
||||||
<color name="launch_background">#0B0B0B</color>
|
|
||||||
</resources>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<!-- Referenz unbedingt als @color/launch_background (nicht @colors/...) -->
|
|
||||||
<color name="ic_launcher_background">@color/app_icon_background</color>
|
|
||||||
</resources>
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
<!-- Show a splash screen on the activity. Automatically removed when
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
the Flutter engine draws its first frame -->
|
the Flutter engine draws its first frame -->
|
||||||
<item name="android:windowBackground">@color/launch_background</item>
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
This theme determines the color of the Android Window while your
|
This theme determines the color of the Android Window while your
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
{
|
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"players": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"id",
|
|
||||||
"createdAt",
|
|
||||||
"name"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"groups": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"memberIds": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"id",
|
|
||||||
"name",
|
|
||||||
"createdAt",
|
|
||||||
"memberIds"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"matches": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"createdAt": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"groupId": {
|
|
||||||
"anyOf": [
|
|
||||||
{"type": "string"},
|
|
||||||
{"type": "null"}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"playerIds": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"winnerId": {
|
|
||||||
"anyOf": [
|
|
||||||
{"type": "string"},
|
|
||||||
{"type": "null"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"id",
|
|
||||||
"name",
|
|
||||||
"createdAt",
|
|
||||||
"groupId",
|
|
||||||
"playerIds"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"players",
|
|
||||||
"groups",
|
|
||||||
"matches"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -21,6 +21,6 @@
|
|||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>MinimumOSVersion</key>
|
<key>MinimumOSVersion</key>
|
||||||
<string>13.0</string>
|
<string>12.0</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Uncomment this line to define a global platform for your project
|
# Uncomment this line to define a global platform for your project
|
||||||
# platform :ios, '13.0'
|
# platform :ios, '12.0'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|||||||
@@ -11,11 +11,9 @@
|
|||||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
8AD879B4BA24BC1EB84E1092 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8543AAE6520EA0C0B3AF8FEE /* Pods_RunnerTests.framework */; };
|
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
DDD6907F99188C9B97C6B11F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D622CF241440C10C19C0D397 /* Pods_Runner.framework */; };
|
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -42,18 +40,14 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
13301BC306FBFE16F253F2B9 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
32DDFE3349B038E1CA758D7B /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||||
8543AAE6520EA0C0B3AF8FEE /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
96CDE41BAA7259C918DB326B /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@@ -61,26 +55,13 @@
|
|||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
B194217AD06D15D90AAF9056 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
B68CF4A64F0B5E45B43D6900 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
D622CF241440C10C19C0D397 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
E754D1191B3E54E52B6DCC49 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
6F6FEDCE9772FEF7A6255134 /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
8AD879B4BA24BC1EB84E1092 /* Pods_RunnerTests.framework in Frameworks */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
DDD6907F99188C9B97C6B11F /* Pods_Runner.framework in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -113,8 +94,6 @@
|
|||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
ABF0E17C36D6999806C09130 /* Pods */,
|
|
||||||
F14326E3F17437DD2E32AB7B /* Frameworks */,
|
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -142,29 +121,6 @@
|
|||||||
path = Runner;
|
path = Runner;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
ABF0E17C36D6999806C09130 /* Pods */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
B194217AD06D15D90AAF9056 /* Pods-Runner.debug.xcconfig */,
|
|
||||||
32DDFE3349B038E1CA758D7B /* Pods-Runner.release.xcconfig */,
|
|
||||||
13301BC306FBFE16F253F2B9 /* Pods-Runner.profile.xcconfig */,
|
|
||||||
96CDE41BAA7259C918DB326B /* Pods-RunnerTests.debug.xcconfig */,
|
|
||||||
B68CF4A64F0B5E45B43D6900 /* Pods-RunnerTests.release.xcconfig */,
|
|
||||||
E754D1191B3E54E52B6DCC49 /* Pods-RunnerTests.profile.xcconfig */,
|
|
||||||
);
|
|
||||||
name = Pods;
|
|
||||||
path = Pods;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
F14326E3F17437DD2E32AB7B /* Frameworks */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
D622CF241440C10C19C0D397 /* Pods_Runner.framework */,
|
|
||||||
8543AAE6520EA0C0B3AF8FEE /* Pods_RunnerTests.framework */,
|
|
||||||
);
|
|
||||||
name = Frameworks;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@@ -172,10 +128,8 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
F7D5E29C2C77E2E8925BBB8A /* [CP] Check Pods Manifest.lock */,
|
|
||||||
331C807D294A63A400263BE5 /* Sources */,
|
331C807D294A63A400263BE5 /* Sources */,
|
||||||
331C807F294A63A400263BE5 /* Resources */,
|
331C807F294A63A400263BE5 /* Resources */,
|
||||||
6F6FEDCE9772FEF7A6255134 /* Frameworks */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -191,14 +145,12 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
8947D8DE27F8CB7D5A5F265C /* [CP] Check Pods Manifest.lock */,
|
|
||||||
9740EEB61CF901F6004384FC /* Run Script */,
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
97C146EA1CF9000F007C117D /* Sources */,
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
0CC58B149CD3F41CF94E1C52 /* [CP] Embed Pods Frameworks */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -270,23 +222,6 @@
|
|||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
0CC58B149CD3F41CF94E1C52 /* [CP] Embed Pods Frameworks */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputFileListPaths = (
|
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
|
||||||
);
|
|
||||||
name = "[CP] Embed Pods Frameworks";
|
|
||||||
outputFileListPaths = (
|
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
alwaysOutOfDate = 1;
|
alwaysOutOfDate = 1;
|
||||||
@@ -303,28 +238,6 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||||
};
|
};
|
||||||
8947D8DE27F8CB7D5A5F265C /* [CP] Check Pods Manifest.lock */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputFileListPaths = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
|
||||||
"${PODS_ROOT}/Manifest.lock",
|
|
||||||
);
|
|
||||||
name = "[CP] Check Pods Manifest.lock";
|
|
||||||
outputFileListPaths = (
|
|
||||||
);
|
|
||||||
outputPaths = (
|
|
||||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
alwaysOutOfDate = 1;
|
alwaysOutOfDate = 1;
|
||||||
@@ -340,28 +253,6 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
};
|
};
|
||||||
F7D5E29C2C77E2E8925BBB8A /* [CP] Check Pods Manifest.lock */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputFileListPaths = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
|
||||||
"${PODS_ROOT}/Manifest.lock",
|
|
||||||
);
|
|
||||||
name = "[CP] Check Pods Manifest.lock";
|
|
||||||
outputFileListPaths = (
|
|
||||||
);
|
|
||||||
outputPaths = (
|
|
||||||
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
@@ -455,7 +346,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
@@ -488,7 +379,6 @@
|
|||||||
};
|
};
|
||||||
331C8088294A63A400263BE5 /* Debug */ = {
|
331C8088294A63A400263BE5 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = 96CDE41BAA7259C918DB326B /* Pods-RunnerTests.debug.xcconfig */;
|
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
@@ -506,7 +396,6 @@
|
|||||||
};
|
};
|
||||||
331C8089294A63A400263BE5 /* Release */ = {
|
331C8089294A63A400263BE5 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = B68CF4A64F0B5E45B43D6900 /* Pods-RunnerTests.release.xcconfig */;
|
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
@@ -522,7 +411,6 @@
|
|||||||
};
|
};
|
||||||
331C808A294A63A400263BE5 /* Profile */ = {
|
331C808A294A63A400263BE5 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
baseConfigurationReference = E754D1191B3E54E52B6DCC49 /* Pods-RunnerTests.profile.xcconfig */;
|
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
@@ -585,7 +473,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@@ -636,7 +524,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
|||||||
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
@@ -4,7 +4,4 @@
|
|||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "group:Runner.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
|
||||||
location = "group:Pods/Pods.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|||||||
@@ -1,14 +1,122 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"filename" : "icon_x1024.png",
|
"size" : "20x20",
|
||||||
"idiom" : "universal",
|
"idiom" : "iphone",
|
||||||
"platform" : "ios",
|
"filename" : "Icon-App-20x20@2x.png",
|
||||||
"size" : "1024x1024"
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-20x20@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-29x29@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-29x29@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-29x29@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-40x40@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-40x40@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-60x60@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-60x60@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-20x20@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-20x20@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-29x29@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-29x29@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-40x40@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-40x40@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-76x76@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-76x76@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "83.5x83.5",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "1024x1024",
|
||||||
|
"idiom" : "ios-marketing",
|
||||||
|
"filename" : "Icon-App-1024x1024@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"version" : 1,
|
||||||
"version" : 1
|
"author" : "xcode"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 295 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 450 B |
|
After Width: | Height: | Size: 282 B |
|
After Width: | Height: | Size: 462 B |
|
After Width: | Height: | Size: 704 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 586 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 762 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,23 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"filename" : "icon.png",
|
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
|
"filename" : "LaunchImage.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
|
"filename" : "LaunchImage@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
|
"filename" : "LaunchImage@3x.png",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
"author" : "xcode",
|
"version" : 1,
|
||||||
"version" : 1
|
"author" : "xcode"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BIN
ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
5
ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Launch Screen Assets
|
||||||
|
|
||||||
|
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
|
||||||
|
|
||||||
|
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
"colors" : [
|
|
||||||
{
|
|
||||||
"color" : {
|
|
||||||
"color-space" : "srgb",
|
|
||||||
"components" : {
|
|
||||||
"alpha" : "1.000",
|
|
||||||
"blue" : "0.043",
|
|
||||||
"green" : "0.043",
|
|
||||||
"red" : "0.043"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"idiom" : "universal"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 9.6 KiB |
@@ -1,11 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<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="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||||
<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="12089"/>
|
||||||
<capability name="Named colors" minToolsVersion="9.0"/>
|
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
<!--View Controller-->
|
<!--View Controller-->
|
||||||
@@ -17,27 +14,24 @@
|
|||||||
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
||||||
</layoutGuides>
|
</layoutGuides>
|
||||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||||
<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>
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="LauncherIcon" translatesAutoresizingMaskIntoConstraints="NO" id="ygV-Op-Bu5">
|
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||||
<rect key="frame" x="46" y="334" width="301" height="184"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
|
||||||
</imageView>
|
</imageView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" name="LauncherBackgroundColor"/>
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
||||||
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
||||||
|
</constraints>
|
||||||
</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"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="80.152671755725194" y="264.08450704225356"/>
|
<point key="canvasLocation" x="53" y="375"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
<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="LaunchImage" width="168" height="185"/>
|
||||||
<namedColor name="LauncherBackgroundColor">
|
|
||||||
<color red="0.90196078431372551" green="0.94509803921568625" blue="0.89411764705882346" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
||||||
</namedColor>
|
|
||||||
</resources>
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24412" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||||
<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="10085"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
<!--Flutter View Controller-->
|
<!--Flutter View Controller-->
|
||||||
@@ -16,14 +14,13 @@
|
|||||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||||
</layoutGuides>
|
</layoutGuides>
|
||||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||||
</view>
|
</view>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="141" y="131"/>
|
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
<array>
|
<array>
|
||||||
@@ -43,5 +45,10 @@
|
|||||||
<true/>
|
<true/>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>LSApplicationQueriesSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>https</string>
|
||||||
|
<string>mailto</string>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
arb-dir: lib/l10n/arb
|
|
||||||
template-arb-file: app_en.arb
|
|
||||||
output-localization-file: app_localizations.dart
|
|
||||||
output-dir: lib/l10n/generated
|
|
||||||
nullable-getter: false
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
class Constants {
|
|
||||||
Constants._(); // Private constructor to prevent instantiation
|
|
||||||
|
|
||||||
/// Minimum duration of all app skeletons
|
|
||||||
static Duration minimumSkeletonDuration = const Duration(milliseconds: 250);
|
|
||||||
}
|
|
||||||
@@ -1,59 +1,19 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class CustomTheme {
|
class CustomTheme {
|
||||||
CustomTheme._(); // Private constructor to prevent instantiation
|
static Color primaryColor = const Color(0xFF71C0BB);
|
||||||
|
static Color secondaryColor = const Color(0xFF2A4759);
|
||||||
|
static Color backgroundColor = const Color(0xFF1A1A1A);
|
||||||
|
|
||||||
// ==================== Colors ====================
|
static AppBarTheme appBarTheme = const AppBarTheme(
|
||||||
static Color primaryColor = const Color(0xFF7505E4);
|
backgroundColor: Color(0xFF1A1A1A),
|
||||||
static Color secondaryColor = const Color(0xFFAFA2FF);
|
foregroundColor: Colors.white,
|
||||||
static Color backgroundColor = const Color(0xFF0B0B0B);
|
|
||||||
static Color boxColor = const Color(0xFF101010);
|
|
||||||
static Color onBoxColor = const Color(0xFF181818);
|
|
||||||
static Color boxBorder = const Color(0xFF272727);
|
|
||||||
static const Color textColor = Colors.white;
|
|
||||||
|
|
||||||
// ==================== Border Radius ====================
|
|
||||||
static const double standardBorderRadius = 12.0;
|
|
||||||
static BorderRadius get standardBorderRadiusAll =>
|
|
||||||
BorderRadius.circular(standardBorderRadius);
|
|
||||||
|
|
||||||
// ==================== Padding & Margins ====================
|
|
||||||
static const EdgeInsets standardMargin = EdgeInsets.symmetric(
|
|
||||||
horizontal: 12,
|
|
||||||
vertical: 10,
|
|
||||||
);
|
|
||||||
static const EdgeInsets tileMargin = EdgeInsets.symmetric(
|
|
||||||
horizontal: 12,
|
|
||||||
vertical: 5,
|
|
||||||
);
|
|
||||||
|
|
||||||
// ==================== Decorations ====================
|
|
||||||
static BoxDecoration standardBoxDecoration = BoxDecoration(
|
|
||||||
color: boxColor,
|
|
||||||
border: Border.all(color: boxBorder),
|
|
||||||
borderRadius: standardBorderRadiusAll,
|
|
||||||
);
|
|
||||||
|
|
||||||
static BoxDecoration highlightedBoxDecoration = BoxDecoration(
|
|
||||||
color: boxColor,
|
|
||||||
border: Border.all(color: primaryColor),
|
|
||||||
borderRadius: standardBorderRadiusAll,
|
|
||||||
boxShadow: [BoxShadow(color: primaryColor.withAlpha(120), blurRadius: 12)],
|
|
||||||
);
|
|
||||||
|
|
||||||
// ==================== App Bar Theme ====================
|
|
||||||
static AppBarTheme appBarTheme = AppBarTheme(
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
foregroundColor: textColor,
|
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
scrolledUnderElevation: 0,
|
titleTextStyle: TextStyle(
|
||||||
centerTitle: true,
|
color: Colors.white,
|
||||||
titleTextStyle: const TextStyle(
|
|
||||||
color: textColor,
|
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
),
|
||||||
iconTheme: const IconThemeData(color: textColor),
|
iconTheme: IconThemeData(color: Colors.white),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:game_tracker/l10n/generated/app_localizations.dart';
|
|
||||||
|
|
||||||
/// Button types used for styling the [CustomWidthButton]
|
|
||||||
/// - [ButtonType.primary]: Primary button style.
|
|
||||||
/// - [ButtonType.secondary]: Secondary button style.
|
|
||||||
/// - [ButtonType.tertiary]: Tertiary button style.
|
|
||||||
enum ButtonType { primary, secondary, tertiary }
|
|
||||||
|
|
||||||
/// Result types for import operations in the [SettingsView]
|
|
||||||
/// - [ImportResult.success]: The import operation was successful.
|
|
||||||
/// - [ImportResult.canceled]: The import operation was canceled by the user.
|
|
||||||
/// - [ImportResult.fileReadError]: There was an error reading the selected file.
|
|
||||||
/// - [ImportResult.invalidSchema]: The JSON schema of the imported data is invalid.
|
|
||||||
/// - [ImportResult.formatException]: A format exception occurred during import.
|
|
||||||
/// - [ImportResult.unknownException]: An exception occurred during import.
|
|
||||||
enum ImportResult {
|
|
||||||
success,
|
|
||||||
canceled,
|
|
||||||
fileReadError,
|
|
||||||
invalidSchema,
|
|
||||||
formatException,
|
|
||||||
unknownException,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Result types for export operations in the [SettingsView]
|
|
||||||
/// - [ExportResult.success]: The export operation was successful.
|
|
||||||
/// - [ExportResult.canceled]: The export operation was canceled by the user.
|
|
||||||
/// - [ExportResult.unknownException]: An exception occurred during export.
|
|
||||||
enum ExportResult { success, canceled, unknownException }
|
|
||||||
|
|
||||||
/// Different rulesets available for matches
|
|
||||||
/// - [Ruleset.singleWinner]: The match is won by a single player
|
|
||||||
/// - [Ruleset.singleLoser]: The match is lost by a single player
|
|
||||||
/// - [Ruleset.mostPoints]: The player with the most points wins.
|
|
||||||
/// - [Ruleset.leastPoints]: The player with the fewest points wins.
|
|
||||||
enum Ruleset { singleWinner, singleLoser, mostPoints, leastPoints }
|
|
||||||
|
|
||||||
/// Translates a [Ruleset] enum value to its corresponding localized string.
|
|
||||||
String translateRulesetToString(Ruleset ruleset, BuildContext context) {
|
|
||||||
final loc = AppLocalizations.of(context);
|
|
||||||
switch (ruleset) {
|
|
||||||
case Ruleset.singleWinner:
|
|
||||||
return loc.single_winner;
|
|
||||||
case Ruleset.singleLoser:
|
|
||||||
return loc.single_loser;
|
|
||||||
case Ruleset.mostPoints:
|
|
||||||
return loc.most_points;
|
|
||||||
case Ruleset.leastPoints:
|
|
||||||
return loc.least_points;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,214 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/group_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_group_table.dart';
|
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
|
|
||||||
part 'group_dao.g.dart';
|
|
||||||
|
|
||||||
@DriftAccessor(tables: [GroupTable, PlayerGroupTable])
|
|
||||||
class GroupDao extends DatabaseAccessor<AppDatabase> with _$GroupDaoMixin {
|
|
||||||
GroupDao(super.db);
|
|
||||||
|
|
||||||
/// Retrieves all groups from the database.
|
|
||||||
Future<List<Group>> getAllGroups() async {
|
|
||||||
final query = select(groupTable);
|
|
||||||
final result = await query.get();
|
|
||||||
return Future.wait(
|
|
||||||
result.map((groupData) async {
|
|
||||||
final members = await db.playerGroupDao.getPlayersOfGroup(
|
|
||||||
groupId: groupData.id,
|
|
||||||
);
|
|
||||||
return Group(
|
|
||||||
id: groupData.id,
|
|
||||||
name: groupData.name,
|
|
||||||
members: members,
|
|
||||||
createdAt: groupData.createdAt,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves a [Group] by its [groupId], including its members.
|
|
||||||
Future<Group> getGroupById({required String groupId}) async {
|
|
||||||
final query = select(groupTable)..where((g) => g.id.equals(groupId));
|
|
||||||
final result = await query.getSingle();
|
|
||||||
|
|
||||||
List<Player> members = await db.playerGroupDao.getPlayersOfGroup(
|
|
||||||
groupId: groupId,
|
|
||||||
);
|
|
||||||
|
|
||||||
return Group(
|
|
||||||
id: result.id,
|
|
||||||
name: result.name,
|
|
||||||
members: members,
|
|
||||||
createdAt: result.createdAt,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a new group with the given [id] and [name] to the database.
|
|
||||||
/// This method also adds the group's members to the [PlayerGroupTable].
|
|
||||||
Future<bool> addGroup({required Group group}) async {
|
|
||||||
if (!await groupExists(groupId: group.id)) {
|
|
||||||
await db.transaction(() async {
|
|
||||||
await into(groupTable).insert(
|
|
||||||
GroupTableCompanion.insert(
|
|
||||||
id: group.id,
|
|
||||||
name: group.name,
|
|
||||||
createdAt: group.createdAt,
|
|
||||||
),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
);
|
|
||||||
await Future.wait(
|
|
||||||
group.members.map((player) => db.playerDao.addPlayer(player: player)),
|
|
||||||
);
|
|
||||||
await db.batch(
|
|
||||||
(b) => b.insertAll(
|
|
||||||
db.playerGroupTable,
|
|
||||||
group.members
|
|
||||||
.map(
|
|
||||||
(member) => PlayerGroupTableCompanion.insert(
|
|
||||||
playerId: member.id,
|
|
||||||
groupId: group.id,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds multiple groups to the database.
|
|
||||||
/// Also adds the group's members to the [PlayerGroupTable].
|
|
||||||
Future<void> addGroupsAsList({required List<Group> groups}) async {
|
|
||||||
if (groups.isEmpty) return;
|
|
||||||
await db.transaction(() async {
|
|
||||||
// Deduplicate groups by id - keep first occurrence
|
|
||||||
final Map<String, Group> uniqueGroups = {};
|
|
||||||
for (final g in groups) {
|
|
||||||
uniqueGroups.putIfAbsent(g.id, () => g);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert unique groups in batch
|
|
||||||
// Using insertOrIgnore to avoid triggering cascade deletes on
|
|
||||||
// player_group associations when groups already exist
|
|
||||||
await db.batch(
|
|
||||||
(b) => b.insertAll(
|
|
||||||
groupTable,
|
|
||||||
uniqueGroups.values
|
|
||||||
.map(
|
|
||||||
(group) => GroupTableCompanion.insert(
|
|
||||||
id: group.id,
|
|
||||||
name: group.name,
|
|
||||||
createdAt: group.createdAt,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
mode: InsertMode.insertOrIgnore,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Collect unique players from all groups
|
|
||||||
final uniquePlayers = <String, Player>{};
|
|
||||||
for (final g in uniqueGroups.values) {
|
|
||||||
for (final m in g.members) {
|
|
||||||
uniquePlayers[m.id] = m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uniquePlayers.isNotEmpty) {
|
|
||||||
// Using insertOrIgnore to avoid triggering cascade deletes on
|
|
||||||
// player_group associations when players already exist
|
|
||||||
await db.batch(
|
|
||||||
(b) => b.insertAll(
|
|
||||||
db.playerTable,
|
|
||||||
uniquePlayers.values
|
|
||||||
.map(
|
|
||||||
(p) => PlayerTableCompanion.insert(
|
|
||||||
id: p.id,
|
|
||||||
name: p.name,
|
|
||||||
createdAt: p.createdAt,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
mode: InsertMode.insertOrIgnore,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare all player-group associations in one list (unique pairs)
|
|
||||||
final Set<String> seenPairs = {};
|
|
||||||
final List<PlayerGroupTableCompanion> pgRows = [];
|
|
||||||
for (final g in uniqueGroups.values) {
|
|
||||||
for (final m in g.members) {
|
|
||||||
final key = '${m.id}|${g.id}';
|
|
||||||
if (!seenPairs.contains(key)) {
|
|
||||||
seenPairs.add(key);
|
|
||||||
pgRows.add(
|
|
||||||
PlayerGroupTableCompanion.insert(playerId: m.id, groupId: g.id),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pgRows.isNotEmpty) {
|
|
||||||
await db.batch((b) {
|
|
||||||
for (final pg in pgRows) {
|
|
||||||
b.insert(db.playerGroupTable, pg, mode: InsertMode.insertOrReplace);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes the group with the given [id] from the database.
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> deleteGroup({required String groupId}) async {
|
|
||||||
final query = (delete(groupTable)..where((g) => g.id.equals(groupId)));
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates the name of the group with the given [id] to [newName].
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> updateGroupname({
|
|
||||||
required String groupId,
|
|
||||||
required String newName,
|
|
||||||
}) async {
|
|
||||||
final rowsAffected =
|
|
||||||
await (update(groupTable)..where((g) => g.id.equals(groupId))).write(
|
|
||||||
GroupTableCompanion(name: Value(newName)),
|
|
||||||
);
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the number of groups in the database.
|
|
||||||
Future<int> getGroupCount() async {
|
|
||||||
final count =
|
|
||||||
await (selectOnly(groupTable)..addColumns([groupTable.id.count()]))
|
|
||||||
.map((row) => row.read(groupTable.id.count()))
|
|
||||||
.getSingle();
|
|
||||||
return count ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if a group with the given [groupId] exists in the database.
|
|
||||||
/// Returns `true` if the group exists, `false` otherwise.
|
|
||||||
Future<bool> groupExists({required String groupId}) async {
|
|
||||||
final query = select(groupTable)..where((g) => g.id.equals(groupId));
|
|
||||||
final result = await query.getSingleOrNull();
|
|
||||||
return result != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes all groups from the database.
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> deleteAllGroups() async {
|
|
||||||
final query = delete(groupTable);
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'group_dao.dart';
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
mixin _$GroupDaoMixin on DatabaseAccessor<AppDatabase> {
|
|
||||||
$GroupTableTable get groupTable => attachedDatabase.groupTable;
|
|
||||||
$PlayerTableTable get playerTable => attachedDatabase.playerTable;
|
|
||||||
$PlayerGroupTableTable get playerGroupTable =>
|
|
||||||
attachedDatabase.playerGroupTable;
|
|
||||||
}
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/group_match_table.dart';
|
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
|
||||||
|
|
||||||
part 'group_match_dao.g.dart';
|
|
||||||
|
|
||||||
@DriftAccessor(tables: [GroupMatchTable])
|
|
||||||
class GroupMatchDao extends DatabaseAccessor<AppDatabase>
|
|
||||||
with _$GroupMatchDaoMixin {
|
|
||||||
GroupMatchDao(super.db);
|
|
||||||
|
|
||||||
/// Associates a group with a match by inserting a record into the
|
|
||||||
/// [GroupMatchTable].
|
|
||||||
Future<void> addGroupToMatch({
|
|
||||||
required String matchId,
|
|
||||||
required String groupId,
|
|
||||||
}) async {
|
|
||||||
if (await matchHasGroup(matchId: matchId)) {
|
|
||||||
throw Exception('Match already has a group');
|
|
||||||
}
|
|
||||||
await into(groupMatchTable).insert(
|
|
||||||
GroupMatchTableCompanion.insert(groupId: groupId, matchId: matchId),
|
|
||||||
mode: InsertMode.insertOrIgnore,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the [Group] associated with the given [matchId].
|
|
||||||
/// Returns `null` if no group is found.
|
|
||||||
Future<Group?> getGroupOfMatch({required String matchId}) async {
|
|
||||||
final result = await (select(
|
|
||||||
groupMatchTable,
|
|
||||||
)..where((g) => g.matchId.equals(matchId))).getSingleOrNull();
|
|
||||||
|
|
||||||
if (result == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final group = await db.groupDao.getGroupById(groupId: result.groupId);
|
|
||||||
return group;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if there is a group associated with the given [matchId].
|
|
||||||
/// Returns `true` if there is a group, otherwise `false`.
|
|
||||||
Future<bool> matchHasGroup({required String matchId}) async {
|
|
||||||
final count =
|
|
||||||
await (selectOnly(groupMatchTable)
|
|
||||||
..where(groupMatchTable.matchId.equals(matchId))
|
|
||||||
..addColumns([groupMatchTable.groupId.count()]))
|
|
||||||
.map((row) => row.read(groupMatchTable.groupId.count()))
|
|
||||||
.getSingle();
|
|
||||||
return (count ?? 0) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if a specific group is associated with a specific match.
|
|
||||||
/// Returns `true` if the group is in the match, otherwise `false`.
|
|
||||||
Future<bool> isGroupInMatch({
|
|
||||||
required String matchId,
|
|
||||||
required String groupId,
|
|
||||||
}) async {
|
|
||||||
final count =
|
|
||||||
await (selectOnly(groupMatchTable)
|
|
||||||
..where(
|
|
||||||
groupMatchTable.matchId.equals(matchId) &
|
|
||||||
groupMatchTable.groupId.equals(groupId),
|
|
||||||
)
|
|
||||||
..addColumns([groupMatchTable.groupId.count()]))
|
|
||||||
.map((row) => row.read(groupMatchTable.groupId.count()))
|
|
||||||
.getSingle();
|
|
||||||
return (count ?? 0) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes the association of a group from a match based on [groupId] and
|
|
||||||
/// [matchId].
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> removeGroupFromMatch({
|
|
||||||
required String matchId,
|
|
||||||
required String groupId,
|
|
||||||
}) async {
|
|
||||||
final query = delete(groupMatchTable)
|
|
||||||
..where((g) => g.matchId.equals(matchId) & g.groupId.equals(groupId));
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates the group associated with a match to [newGroupId] based on
|
|
||||||
/// [matchId].
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> updateGroupOfMatch({
|
|
||||||
required String matchId,
|
|
||||||
required String newGroupId,
|
|
||||||
}) async {
|
|
||||||
final updatedRows =
|
|
||||||
await (update(groupMatchTable)..where((g) => g.matchId.equals(matchId)))
|
|
||||||
.write(GroupMatchTableCompanion(groupId: Value(newGroupId)));
|
|
||||||
return updatedRows > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'group_match_dao.dart';
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
mixin _$GroupMatchDaoMixin on DatabaseAccessor<AppDatabase> {
|
|
||||||
$GroupTableTable get groupTable => attachedDatabase.groupTable;
|
|
||||||
$MatchTableTable get matchTable => attachedDatabase.matchTable;
|
|
||||||
$GroupMatchTableTable get groupMatchTable => attachedDatabase.groupMatchTable;
|
|
||||||
}
|
|
||||||
@@ -1,326 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/match_table.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';
|
|
||||||
|
|
||||||
part 'match_dao.g.dart';
|
|
||||||
|
|
||||||
@DriftAccessor(tables: [MatchTable])
|
|
||||||
class MatchDao extends DatabaseAccessor<AppDatabase> with _$MatchDaoMixin {
|
|
||||||
MatchDao(super.db);
|
|
||||||
|
|
||||||
/// Retrieves all matches from the database.
|
|
||||||
Future<List<Match>> getAllMatches() async {
|
|
||||||
final query = select(matchTable);
|
|
||||||
final result = await query.get();
|
|
||||||
|
|
||||||
return Future.wait(
|
|
||||||
result.map((row) async {
|
|
||||||
final group = await db.groupMatchDao.getGroupOfMatch(matchId: row.id);
|
|
||||||
final players = await db.playerMatchDao.getPlayersOfMatch(
|
|
||||||
matchId: row.id,
|
|
||||||
);
|
|
||||||
final winner = row.winnerId != null
|
|
||||||
? await db.playerDao.getPlayerById(playerId: row.winnerId!)
|
|
||||||
: null;
|
|
||||||
return Match(
|
|
||||||
id: row.id,
|
|
||||||
name: row.name,
|
|
||||||
group: group,
|
|
||||||
players: players,
|
|
||||||
createdAt: row.createdAt,
|
|
||||||
winner: winner,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves a [Match] by its [matchId].
|
|
||||||
Future<Match> getMatchById({required String matchId}) async {
|
|
||||||
final query = select(matchTable)..where((g) => g.id.equals(matchId));
|
|
||||||
final result = await query.getSingle();
|
|
||||||
|
|
||||||
List<Player>? players;
|
|
||||||
if (await db.playerMatchDao.matchHasPlayers(matchId: matchId)) {
|
|
||||||
players = await db.playerMatchDao.getPlayersOfMatch(matchId: matchId);
|
|
||||||
}
|
|
||||||
Group? group;
|
|
||||||
if (await db.groupMatchDao.matchHasGroup(matchId: matchId)) {
|
|
||||||
group = await db.groupMatchDao.getGroupOfMatch(matchId: matchId);
|
|
||||||
}
|
|
||||||
Player? winner;
|
|
||||||
if (result.winnerId != null) {
|
|
||||||
winner = await db.playerDao.getPlayerById(playerId: result.winnerId!);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Match(
|
|
||||||
id: result.id,
|
|
||||||
name: result.name,
|
|
||||||
players: players,
|
|
||||||
group: group,
|
|
||||||
winner: winner,
|
|
||||||
createdAt: result.createdAt,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a new [Match] to the database. Also adds players and group
|
|
||||||
/// associations. This method assumes that the players and groups added to
|
|
||||||
/// this match are already present in the database.
|
|
||||||
Future<void> addMatch({required Match match}) async {
|
|
||||||
await db.transaction(() async {
|
|
||||||
await into(matchTable).insert(
|
|
||||||
MatchTableCompanion.insert(
|
|
||||||
id: match.id,
|
|
||||||
name: match.name,
|
|
||||||
winnerId: Value(match.winner?.id),
|
|
||||||
createdAt: match.createdAt,
|
|
||||||
),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (match.players != null) {
|
|
||||||
for (final p in match.players ?? []) {
|
|
||||||
await db.playerMatchDao.addPlayerToMatch(
|
|
||||||
matchId: match.id,
|
|
||||||
playerId: p.id,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match.group != null) {
|
|
||||||
await db.groupMatchDao.addGroupToMatch(
|
|
||||||
matchId: match.id,
|
|
||||||
groupId: match.group!.id,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds multiple [Match]s to the database in a batch operation.
|
|
||||||
/// Also adds associated players and groups if they exist.
|
|
||||||
/// If the [matches] list is empty, the method returns immediately.
|
|
||||||
/// This Method should only be used to import matches from a different device.
|
|
||||||
Future<void> addMatchAsList({required List<Match> matches}) async {
|
|
||||||
if (matches.isEmpty) return;
|
|
||||||
await db.transaction(() async {
|
|
||||||
// Add all matches in batch
|
|
||||||
await db.batch(
|
|
||||||
(b) => b.insertAll(
|
|
||||||
matchTable,
|
|
||||||
matches
|
|
||||||
.map(
|
|
||||||
(match) => MatchTableCompanion.insert(
|
|
||||||
id: match.id,
|
|
||||||
name: match.name,
|
|
||||||
createdAt: match.createdAt,
|
|
||||||
winnerId: Value(match.winner?.id),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add all groups of the matches in batch
|
|
||||||
// Using insertOrIgnore to avoid overwriting existing groups (which would
|
|
||||||
// trigger cascade deletes on player_group associations)
|
|
||||||
await db.batch(
|
|
||||||
(b) => b.insertAll(
|
|
||||||
db.groupTable,
|
|
||||||
matches
|
|
||||||
.where((match) => match.group != null)
|
|
||||||
.map(
|
|
||||||
(matches) => GroupTableCompanion.insert(
|
|
||||||
id: matches.group!.id,
|
|
||||||
name: matches.group!.name,
|
|
||||||
createdAt: matches.group!.createdAt,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
mode: InsertMode.insertOrIgnore,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add all players of the matches in batch (unique)
|
|
||||||
final uniquePlayers = <String, Player>{};
|
|
||||||
for (final match in matches) {
|
|
||||||
if (match.players != null) {
|
|
||||||
for (final p in match.players!) {
|
|
||||||
uniquePlayers[p.id] = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Also include members of groups
|
|
||||||
if (match.group != null) {
|
|
||||||
for (final m in match.group!.members) {
|
|
||||||
uniquePlayers[m.id] = m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uniquePlayers.isNotEmpty) {
|
|
||||||
// Using insertOrIgnore to avoid triggering cascade deletes on
|
|
||||||
// player_group/player_match associations when players already exist
|
|
||||||
await db.batch(
|
|
||||||
(b) => b.insertAll(
|
|
||||||
db.playerTable,
|
|
||||||
uniquePlayers.values
|
|
||||||
.map(
|
|
||||||
(p) => PlayerTableCompanion.insert(
|
|
||||||
id: p.id,
|
|
||||||
name: p.name,
|
|
||||||
createdAt: p.createdAt,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
mode: InsertMode.insertOrIgnore,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add all player-match associations in batch
|
|
||||||
await db.batch((b) {
|
|
||||||
for (final match in matches) {
|
|
||||||
if (match.players != null) {
|
|
||||||
for (final p in match.players ?? []) {
|
|
||||||
b.insert(
|
|
||||||
db.playerMatchTable,
|
|
||||||
PlayerMatchTableCompanion.insert(
|
|
||||||
matchId: match.id,
|
|
||||||
playerId: p.id,
|
|
||||||
),
|
|
||||||
mode: InsertMode.insertOrIgnore,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add all player-group associations in batch
|
|
||||||
await db.batch((b) {
|
|
||||||
for (final match in matches) {
|
|
||||||
if (match.group != null) {
|
|
||||||
for (final m in match.group!.members) {
|
|
||||||
b.insert(
|
|
||||||
db.playerGroupTable,
|
|
||||||
PlayerGroupTableCompanion.insert(
|
|
||||||
playerId: m.id,
|
|
||||||
groupId: match.group!.id,
|
|
||||||
),
|
|
||||||
mode: InsertMode.insertOrIgnore,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add all group-match associations in batch
|
|
||||||
await db.batch((b) {
|
|
||||||
for (final match in matches) {
|
|
||||||
if (match.group != null) {
|
|
||||||
b.insert(
|
|
||||||
db.groupMatchTable,
|
|
||||||
GroupMatchTableCompanion.insert(
|
|
||||||
matchId: match.id,
|
|
||||||
groupId: match.group!.id,
|
|
||||||
),
|
|
||||||
mode: InsertMode.insertOrIgnore,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes the match with the given [matchId] from the database.
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> deleteMatch({required String matchId}) async {
|
|
||||||
final query = delete(matchTable)..where((g) => g.id.equals(matchId));
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the number of matches in the database.
|
|
||||||
Future<int> getMatchCount() async {
|
|
||||||
final count =
|
|
||||||
await (selectOnly(matchTable)..addColumns([matchTable.id.count()]))
|
|
||||||
.map((row) => row.read(matchTable.id.count()))
|
|
||||||
.getSingle();
|
|
||||||
return count ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if a match with the given [matchId] exists in the database.
|
|
||||||
/// Returns `true` if the match exists, otherwise `false`.
|
|
||||||
Future<bool> matchExists({required String matchId}) async {
|
|
||||||
final query = select(matchTable)..where((g) => g.id.equals(matchId));
|
|
||||||
final result = await query.getSingleOrNull();
|
|
||||||
return result != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes all matches from the database.
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> deleteAllMatches() async {
|
|
||||||
final query = delete(matchTable);
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the winner of the match with the given [matchId] to the player with
|
|
||||||
/// the given [winnerId].
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> setWinner({
|
|
||||||
required String matchId,
|
|
||||||
required String winnerId,
|
|
||||||
}) async {
|
|
||||||
final query = update(matchTable)..where((g) => g.id.equals(matchId));
|
|
||||||
final rowsAffected = await query.write(
|
|
||||||
MatchTableCompanion(winnerId: Value(winnerId)),
|
|
||||||
);
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the winner of the match with the given [matchId].
|
|
||||||
/// Returns the [Player] who won the match, or `null` if no winner is set.
|
|
||||||
Future<Player?> getWinner({required String matchId}) async {
|
|
||||||
final query = select(matchTable)..where((g) => g.id.equals(matchId));
|
|
||||||
final result = await query.getSingleOrNull();
|
|
||||||
if (result == null || result.winnerId == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
final winner = await db.playerDao.getPlayerById(playerId: result.winnerId!);
|
|
||||||
return winner;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes the winner of the match with the given [matchId].
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> removeWinner({required String matchId}) async {
|
|
||||||
final query = update(matchTable)..where((g) => g.id.equals(matchId));
|
|
||||||
final rowsAffected = await query.write(
|
|
||||||
const MatchTableCompanion(winnerId: Value(null)),
|
|
||||||
);
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if the match with the given [matchId] has a winner set.
|
|
||||||
/// Returns `true` if a winner is set, otherwise `false`.
|
|
||||||
Future<bool> hasWinner({required String matchId}) async {
|
|
||||||
final query = select(matchTable)
|
|
||||||
..where((g) => g.id.equals(matchId) & g.winnerId.isNotNull());
|
|
||||||
final result = await query.getSingleOrNull();
|
|
||||||
return result != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Changes the title of the match with the given [matchId] to [newName].
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> updateMatchName({
|
|
||||||
required String matchId,
|
|
||||||
required String newName,
|
|
||||||
}) async {
|
|
||||||
final query = update(matchTable)..where((g) => g.id.equals(matchId));
|
|
||||||
final rowsAffected = await query.write(
|
|
||||||
MatchTableCompanion(name: Value(newName)),
|
|
||||||
);
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'match_dao.dart';
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
mixin _$MatchDaoMixin on DatabaseAccessor<AppDatabase> {
|
|
||||||
$MatchTableTable get matchTable => attachedDatabase.matchTable;
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
|
|
||||||
part 'player_dao.g.dart';
|
|
||||||
|
|
||||||
@DriftAccessor(tables: [PlayerTable])
|
|
||||||
class PlayerDao extends DatabaseAccessor<AppDatabase> with _$PlayerDaoMixin {
|
|
||||||
PlayerDao(super.db);
|
|
||||||
|
|
||||||
/// Retrieves all players from the database.
|
|
||||||
Future<List<Player>> getAllPlayers() async {
|
|
||||||
final query = select(playerTable);
|
|
||||||
final result = await query.get();
|
|
||||||
return result
|
|
||||||
.map(
|
|
||||||
(row) => Player(id: row.id, name: row.name, createdAt: row.createdAt),
|
|
||||||
)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves a [Player] by their [id].
|
|
||||||
Future<Player> getPlayerById({required String playerId}) async {
|
|
||||||
final query = select(playerTable)..where((p) => p.id.equals(playerId));
|
|
||||||
final result = await query.getSingle();
|
|
||||||
return Player(
|
|
||||||
id: result.id,
|
|
||||||
name: result.name,
|
|
||||||
createdAt: result.createdAt,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds a new [player] to the database.
|
|
||||||
/// If a player with the same ID already exists, updates their name to
|
|
||||||
/// the new one.
|
|
||||||
Future<bool> addPlayer({required Player player}) async {
|
|
||||||
if (!await playerExists(playerId: player.id)) {
|
|
||||||
await into(playerTable).insert(
|
|
||||||
PlayerTableCompanion.insert(
|
|
||||||
id: player.id,
|
|
||||||
name: player.name,
|
|
||||||
createdAt: player.createdAt,
|
|
||||||
),
|
|
||||||
mode: InsertMode.insertOrReplace,
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds multiple [players] to the database in a batch operation.
|
|
||||||
/// Uses insertOrIgnore to avoid triggering cascade deletes on
|
|
||||||
/// player_group associations when players already exist.
|
|
||||||
Future<bool> addPlayersAsList({required List<Player> players}) async {
|
|
||||||
if (players.isEmpty) return false;
|
|
||||||
|
|
||||||
await db.batch(
|
|
||||||
(b) => b.insertAll(
|
|
||||||
playerTable,
|
|
||||||
players
|
|
||||||
.map(
|
|
||||||
(player) => PlayerTableCompanion.insert(
|
|
||||||
id: player.id,
|
|
||||||
name: player.name,
|
|
||||||
createdAt: player.createdAt,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList(),
|
|
||||||
mode: InsertMode.insertOrIgnore,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes the player with the given [id] from the database.
|
|
||||||
/// Returns `true` if the player was deleted, `false` if the player did not exist.
|
|
||||||
Future<bool> deletePlayer({required String playerId}) async {
|
|
||||||
final query = delete(playerTable)..where((p) => p.id.equals(playerId));
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if a player with the given [id] exists in the database.
|
|
||||||
/// Returns `true` if the player exists, `false` otherwise.
|
|
||||||
Future<bool> playerExists({required String playerId}) async {
|
|
||||||
final query = select(playerTable)..where((p) => p.id.equals(playerId));
|
|
||||||
final result = await query.getSingleOrNull();
|
|
||||||
return result != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates the name of the player with the given [playerId] to [newName].
|
|
||||||
Future<void> updatePlayername({
|
|
||||||
required String playerId,
|
|
||||||
required String newName,
|
|
||||||
}) async {
|
|
||||||
await (update(playerTable)..where((p) => p.id.equals(playerId))).write(
|
|
||||||
PlayerTableCompanion(name: Value(newName)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the total count of players in the database.
|
|
||||||
Future<int> getPlayerCount() async {
|
|
||||||
final count =
|
|
||||||
await (selectOnly(playerTable)..addColumns([playerTable.id.count()]))
|
|
||||||
.map((row) => row.read(playerTable.id.count()))
|
|
||||||
.getSingle();
|
|
||||||
return count ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deletes all players from the database.
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> deleteAllPlayers() async {
|
|
||||||
final query = delete(playerTable);
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'player_dao.dart';
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
mixin _$PlayerDaoMixin on DatabaseAccessor<AppDatabase> {
|
|
||||||
$PlayerTableTable get playerTable => attachedDatabase.playerTable;
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_group_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
|
|
||||||
part 'player_group_dao.g.dart';
|
|
||||||
|
|
||||||
@DriftAccessor(tables: [PlayerGroupTable, PlayerTable])
|
|
||||||
class PlayerGroupDao extends DatabaseAccessor<AppDatabase>
|
|
||||||
with _$PlayerGroupDaoMixin {
|
|
||||||
PlayerGroupDao(super.db);
|
|
||||||
|
|
||||||
/// No need for a groupHasPlayers method since the members attribute is
|
|
||||||
/// not nullable
|
|
||||||
|
|
||||||
/// Adds a [player] to a group with the given [groupId].
|
|
||||||
/// If the player is already in the group, no action is taken.
|
|
||||||
/// If the player does not exist in the player table, they are added.
|
|
||||||
/// Returns `true` if the player was added, otherwise `false`.
|
|
||||||
Future<bool> addPlayerToGroup({
|
|
||||||
required Player player,
|
|
||||||
required String groupId,
|
|
||||||
}) async {
|
|
||||||
if (await isPlayerInGroup(playerId: player.id, groupId: groupId)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!await db.playerDao.playerExists(playerId: player.id)) {
|
|
||||||
db.playerDao.addPlayer(player: player);
|
|
||||||
}
|
|
||||||
|
|
||||||
await into(playerGroupTable).insert(
|
|
||||||
PlayerGroupTableCompanion.insert(playerId: player.id, groupId: groupId),
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves all players belonging to a specific group by [groupId].
|
|
||||||
Future<List<Player>> getPlayersOfGroup({required String groupId}) async {
|
|
||||||
final query = select(playerGroupTable)
|
|
||||||
..where((pG) => pG.groupId.equals(groupId));
|
|
||||||
final result = await query.get();
|
|
||||||
|
|
||||||
List<Player> groupMembers = List.empty(growable: true);
|
|
||||||
|
|
||||||
for (var entry in result) {
|
|
||||||
final player = await db.playerDao.getPlayerById(playerId: entry.playerId);
|
|
||||||
groupMembers.add(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
return groupMembers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes a player from a group based on [playerId] and [groupId].
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> removePlayerFromGroup({
|
|
||||||
required String playerId,
|
|
||||||
required String groupId,
|
|
||||||
}) async {
|
|
||||||
final query = delete(playerGroupTable)
|
|
||||||
..where((p) => p.playerId.equals(playerId) & p.groupId.equals(groupId));
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if a player with [playerId] is in the group with [groupId].
|
|
||||||
/// Returns `true` if the player is in the group, otherwise `false`.
|
|
||||||
Future<bool> isPlayerInGroup({
|
|
||||||
required String playerId,
|
|
||||||
required String groupId,
|
|
||||||
}) async {
|
|
||||||
final query = select(playerGroupTable)
|
|
||||||
..where((p) => p.playerId.equals(playerId) & p.groupId.equals(groupId));
|
|
||||||
final result = await query.getSingleOrNull();
|
|
||||||
return result != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'player_group_dao.dart';
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
mixin _$PlayerGroupDaoMixin on DatabaseAccessor<AppDatabase> {
|
|
||||||
$PlayerTableTable get playerTable => attachedDatabase.playerTable;
|
|
||||||
$GroupTableTable get groupTable => attachedDatabase.groupTable;
|
|
||||||
$PlayerGroupTableTable get playerGroupTable =>
|
|
||||||
attachedDatabase.playerGroupTable;
|
|
||||||
}
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:game_tracker/data/db/database.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_match_table.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
|
|
||||||
part 'player_match_dao.g.dart';
|
|
||||||
|
|
||||||
@DriftAccessor(tables: [PlayerMatchTable])
|
|
||||||
class PlayerMatchDao extends DatabaseAccessor<AppDatabase>
|
|
||||||
with _$PlayerMatchDaoMixin {
|
|
||||||
PlayerMatchDao(super.db);
|
|
||||||
|
|
||||||
/// Associates a player with a match by inserting a record into the
|
|
||||||
/// [PlayerMatchTable].
|
|
||||||
Future<void> addPlayerToMatch({
|
|
||||||
required String matchId,
|
|
||||||
required String playerId,
|
|
||||||
}) async {
|
|
||||||
await into(playerMatchTable).insert(
|
|
||||||
PlayerMatchTableCompanion.insert(playerId: playerId, matchId: matchId),
|
|
||||||
mode: InsertMode.insertOrIgnore,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves a list of [Player]s associated with the given [matchId].
|
|
||||||
/// Returns null if no players are found.
|
|
||||||
Future<List<Player>?> getPlayersOfMatch({required String matchId}) async {
|
|
||||||
final result = await (select(
|
|
||||||
playerMatchTable,
|
|
||||||
)..where((p) => p.matchId.equals(matchId))).get();
|
|
||||||
|
|
||||||
if (result.isEmpty) return null;
|
|
||||||
|
|
||||||
final futures = result.map(
|
|
||||||
(row) => db.playerDao.getPlayerById(playerId: row.playerId),
|
|
||||||
);
|
|
||||||
final players = await Future.wait(futures);
|
|
||||||
return players;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if there are any players associated with the given [matchId].
|
|
||||||
/// Returns `true` if there are players, otherwise `false`.
|
|
||||||
Future<bool> matchHasPlayers({required String matchId}) async {
|
|
||||||
final count =
|
|
||||||
await (selectOnly(playerMatchTable)
|
|
||||||
..where(playerMatchTable.matchId.equals(matchId))
|
|
||||||
..addColumns([playerMatchTable.playerId.count()]))
|
|
||||||
.map((row) => row.read(playerMatchTable.playerId.count()))
|
|
||||||
.getSingle();
|
|
||||||
return (count ?? 0) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if a specific player is associated with a specific match.
|
|
||||||
/// Returns `true` if the player is in the match, otherwise `false`.
|
|
||||||
Future<bool> isPlayerInMatch({
|
|
||||||
required String matchId,
|
|
||||||
required String playerId,
|
|
||||||
}) async {
|
|
||||||
final count =
|
|
||||||
await (selectOnly(playerMatchTable)
|
|
||||||
..where(playerMatchTable.matchId.equals(matchId))
|
|
||||||
..where(playerMatchTable.playerId.equals(playerId))
|
|
||||||
..addColumns([playerMatchTable.playerId.count()]))
|
|
||||||
.map((row) => row.read(playerMatchTable.playerId.count()))
|
|
||||||
.getSingle();
|
|
||||||
return (count ?? 0) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes the association of a player with a match by deleting the record
|
|
||||||
/// from the [PlayerMatchTable].
|
|
||||||
/// Returns `true` if more than 0 rows were affected, otherwise `false`.
|
|
||||||
Future<bool> removePlayerFromMatch({
|
|
||||||
required String matchId,
|
|
||||||
required String playerId,
|
|
||||||
}) async {
|
|
||||||
final query = delete(playerMatchTable)
|
|
||||||
..where((pg) => pg.matchId.equals(matchId))
|
|
||||||
..where((pg) => pg.playerId.equals(playerId));
|
|
||||||
final rowsAffected = await query.go();
|
|
||||||
return rowsAffected > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Updates the players associated with a match based on the provided
|
|
||||||
/// [newPlayer] list. It adds new players and removes players that are no
|
|
||||||
/// longer associated with the match.
|
|
||||||
Future<void> updatePlayersFromMatch({
|
|
||||||
required String matchId,
|
|
||||||
required List<Player> newPlayer,
|
|
||||||
}) async {
|
|
||||||
final currentPlayers = await getPlayersOfMatch(matchId: matchId);
|
|
||||||
// Create sets of player IDs for easy comparison
|
|
||||||
final currentPlayerIds = currentPlayers?.map((p) => p.id).toSet() ?? {};
|
|
||||||
final newPlayerIdsSet = newPlayer.map((p) => p.id).toSet();
|
|
||||||
|
|
||||||
// Determine players to add and remove
|
|
||||||
final playersToAdd = newPlayerIdsSet.difference(currentPlayerIds);
|
|
||||||
final playersToRemove = currentPlayerIds.difference(newPlayerIdsSet);
|
|
||||||
|
|
||||||
db.transaction(() async {
|
|
||||||
// Remove old players
|
|
||||||
if (playersToRemove.isNotEmpty) {
|
|
||||||
await (delete(playerMatchTable)..where(
|
|
||||||
(pg) =>
|
|
||||||
pg.matchId.equals(matchId) &
|
|
||||||
pg.playerId.isIn(playersToRemove.toList()),
|
|
||||||
))
|
|
||||||
.go();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add new players
|
|
||||||
if (playersToAdd.isNotEmpty) {
|
|
||||||
final inserts = playersToAdd
|
|
||||||
.map(
|
|
||||||
(id) => PlayerMatchTableCompanion.insert(
|
|
||||||
playerId: id,
|
|
||||||
matchId: matchId,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.toList();
|
|
||||||
await Future.wait(
|
|
||||||
inserts.map(
|
|
||||||
(c) => into(
|
|
||||||
playerMatchTable,
|
|
||||||
).insert(c, mode: InsertMode.insertOrIgnore),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'player_match_dao.dart';
|
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
|
||||||
mixin _$PlayerMatchDaoMixin on DatabaseAccessor<AppDatabase> {
|
|
||||||
$PlayerTableTable get playerTable => attachedDatabase.playerTable;
|
|
||||||
$MatchTableTable get matchTable => attachedDatabase.matchTable;
|
|
||||||
$PlayerMatchTableTable get playerMatchTable =>
|
|
||||||
attachedDatabase.playerMatchTable;
|
|
||||||
}
|
|
||||||
46
lib/data/database.dart
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import 'package:drift/drift.dart';
|
||||||
|
import 'package:drift_flutter/drift_flutter.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
|
part 'database.g.dart';
|
||||||
|
|
||||||
|
class User extends Table {
|
||||||
|
TextColumn get id => text()();
|
||||||
|
TextColumn get name => text()();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<Column<Object>> get primaryKey => {id};
|
||||||
|
}
|
||||||
|
|
||||||
|
class Group extends Table {
|
||||||
|
TextColumn get id => text()();
|
||||||
|
TextColumn get name => text()();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<Column<Object>> get primaryKey => {id};
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserGroup extends Table {
|
||||||
|
TextColumn get userId => text().references(User, #id)();
|
||||||
|
TextColumn get groupId => text().references(Group, #id)();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Set<Column<Object>> get primaryKey => {userId, groupId};
|
||||||
|
}
|
||||||
|
|
||||||
|
@DriftDatabase(tables: [User, Group, UserGroup])
|
||||||
|
class AppDatabase extends _$AppDatabase {
|
||||||
|
AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get schemaVersion => 1;
|
||||||
|
|
||||||
|
static QueryExecutor _openConnection() {
|
||||||
|
return driftDatabase(
|
||||||
|
name: 'gametracker_db',
|
||||||
|
native: const DriftNativeOptions(
|
||||||
|
databaseDirectory: getApplicationSupportDirectory,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
1455
lib/data/database.g.dart
Normal file
@@ -1,60 +0,0 @@
|
|||||||
import 'package:drift/drift.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';
|
|
||||||
|
|
||||||
part 'database.g.dart';
|
|
||||||
|
|
||||||
@DriftDatabase(
|
|
||||||
tables: [
|
|
||||||
PlayerTable,
|
|
||||||
GroupTable,
|
|
||||||
MatchTable,
|
|
||||||
PlayerGroupTable,
|
|
||||||
PlayerMatchTable,
|
|
||||||
GroupMatchTable,
|
|
||||||
],
|
|
||||||
daos: [
|
|
||||||
PlayerDao,
|
|
||||||
GroupDao,
|
|
||||||
MatchDao,
|
|
||||||
PlayerGroupDao,
|
|
||||||
PlayerMatchDao,
|
|
||||||
GroupMatchDao,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
class AppDatabase extends _$AppDatabase {
|
|
||||||
AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get schemaVersion => 1;
|
|
||||||
|
|
||||||
@override
|
|
||||||
MigrationStrategy get migration {
|
|
||||||
return MigrationStrategy(
|
|
||||||
beforeOpen: (details) async {
|
|
||||||
await customStatement('PRAGMA foreign_keys = ON');
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static QueryExecutor _openConnection() {
|
|
||||||
return driftDatabase(
|
|
||||||
name: 'gametracker_db',
|
|
||||||
native: const DriftNativeOptions(
|
|
||||||
databaseDirectory: getApplicationSupportDirectory,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/group_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/match_table.dart';
|
|
||||||
|
|
||||||
class GroupMatchTable extends Table {
|
|
||||||
TextColumn get groupId =>
|
|
||||||
text().references(GroupTable, #id, onDelete: KeyAction.cascade)();
|
|
||||||
TextColumn get matchId =>
|
|
||||||
text().references(MatchTable, #id, onDelete: KeyAction.cascade)();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Set<Column<Object>> get primaryKey => {groupId, matchId};
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
|
|
||||||
class GroupTable extends Table {
|
|
||||||
TextColumn get id => text()();
|
|
||||||
TextColumn get name => text()();
|
|
||||||
DateTimeColumn get createdAt => dateTime()();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Set<Column<Object>> get primaryKey => {id};
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
|
|
||||||
class MatchTable extends Table {
|
|
||||||
TextColumn get id => text()();
|
|
||||||
TextColumn get name => text()();
|
|
||||||
late final winnerId = text().nullable()();
|
|
||||||
DateTimeColumn get createdAt => dateTime()();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Set<Column<Object>> get primaryKey => {id};
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/group_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
|
||||||
|
|
||||||
class PlayerGroupTable extends Table {
|
|
||||||
TextColumn get playerId =>
|
|
||||||
text().references(PlayerTable, #id, onDelete: KeyAction.cascade)();
|
|
||||||
TextColumn get groupId =>
|
|
||||||
text().references(GroupTable, #id, onDelete: KeyAction.cascade)();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Set<Column<Object>> get primaryKey => {playerId, groupId};
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/match_table.dart';
|
|
||||||
import 'package:game_tracker/data/db/tables/player_table.dart';
|
|
||||||
|
|
||||||
class PlayerMatchTable extends Table {
|
|
||||||
TextColumn get playerId =>
|
|
||||||
text().references(PlayerTable, #id, onDelete: KeyAction.cascade)();
|
|
||||||
TextColumn get matchId =>
|
|
||||||
text().references(MatchTable, #id, onDelete: KeyAction.cascade)();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Set<Column<Object>> get primaryKey => {playerId, matchId};
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import 'package:drift/drift.dart';
|
|
||||||
|
|
||||||
class PlayerTable extends Table {
|
|
||||||
TextColumn get id => text()();
|
|
||||||
TextColumn get name => text()();
|
|
||||||
DateTimeColumn get createdAt => dateTime()();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Set<Column<Object>> get primaryKey => {id};
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
import 'package:clock/clock.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
class Group {
|
|
||||||
final String id;
|
|
||||||
final DateTime createdAt;
|
|
||||||
final String name;
|
|
||||||
final List<Player> members;
|
|
||||||
|
|
||||||
Group({
|
|
||||||
String? id,
|
|
||||||
DateTime? createdAt,
|
|
||||||
required this.name,
|
|
||||||
required this.members,
|
|
||||||
}) : id = id ?? const Uuid().v4(),
|
|
||||||
createdAt = createdAt ?? clock.now();
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'Group{id: $id, name: $name,members: $members}';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a Group instance from a JSON object.
|
|
||||||
Group.fromJson(Map<String, dynamic> json)
|
|
||||||
: id = json['id'],
|
|
||||||
createdAt = DateTime.parse(json['createdAt']),
|
|
||||||
name = json['name'],
|
|
||||||
members = (json['members'] as List)
|
|
||||||
.map((memberJson) => Player.fromJson(memberJson))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
/// Converts the Group instance to a JSON object.
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
'id': id,
|
|
||||||
'createdAt': createdAt.toIso8601String(),
|
|
||||||
'name': name,
|
|
||||||
'members': members.map((member) => member.toJson()).toList(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import 'package:clock/clock.dart';
|
|
||||||
import 'package:game_tracker/data/dto/group.dart';
|
|
||||||
import 'package:game_tracker/data/dto/player.dart';
|
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
class Match {
|
|
||||||
final String id;
|
|
||||||
final DateTime createdAt;
|
|
||||||
final String name;
|
|
||||||
final List<Player>? players;
|
|
||||||
final Group? group;
|
|
||||||
final Player? winner;
|
|
||||||
|
|
||||||
Match({
|
|
||||||
String? id,
|
|
||||||
DateTime? createdAt,
|
|
||||||
required this.name,
|
|
||||||
this.players,
|
|
||||||
this.group,
|
|
||||||
this.winner,
|
|
||||||
}) : id = id ?? const Uuid().v4(),
|
|
||||||
createdAt = createdAt ?? clock.now();
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'Match{\n\tid: $id,\n\tname: $name,\n\tplayers: $players,\n\tgroup: $group,\n\twinner: $winner\n}';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a Match instance from a JSON object.
|
|
||||||
Match.fromJson(Map<String, dynamic> json)
|
|
||||||
: id = json['id'],
|
|
||||||
name = json['name'],
|
|
||||||
createdAt = DateTime.parse(json['createdAt']),
|
|
||||||
players = json['players'] != null
|
|
||||||
? (json['players'] as List)
|
|
||||||
.map((playerJson) => Player.fromJson(playerJson))
|
|
||||||
.toList()
|
|
||||||
: null,
|
|
||||||
group = json['group'] != null ? Group.fromJson(json['group']) : null,
|
|
||||||
winner = json['winner'] != null ? Player.fromJson(json['winner']) : null;
|
|
||||||
|
|
||||||
/// Converts the Match instance to a JSON object.
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
'id': id,
|
|
||||||
'createdAt': createdAt.toIso8601String(),
|
|
||||||
'name': name,
|
|
||||||
'players': players?.map((player) => player.toJson()).toList(),
|
|
||||||
'group': group?.toJson(),
|
|
||||||
'winner': winner?.toJson(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
import 'package:clock/clock.dart';
|
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
class Player {
|
|
||||||
final String id;
|
|
||||||
final DateTime createdAt;
|
|
||||||
final String name;
|
|
||||||
|
|
||||||
Player({String? id, DateTime? createdAt, required this.name})
|
|
||||||
: id = id ?? const Uuid().v4(),
|
|
||||||
createdAt = createdAt ?? clock.now();
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'Player{id: $id,name: $name}';
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a Player instance from a JSON object.
|
|
||||||
Player.fromJson(Map<String, dynamic> json)
|
|
||||||
: id = json['id'],
|
|
||||||
createdAt = DateTime.parse(json['createdAt']),
|
|
||||||
name = json['name'];
|
|
||||||
|
|
||||||
/// Converts the Player instance to a JSON object.
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
'id': id,
|
|
||||||
'createdAt': createdAt.toIso8601String(),
|
|
||||||
'name': name,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
28
lib/data/methods/group.dart
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import 'package:game_tracker/data/database.dart';
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
|
||||||
|
extension GroupMethods on AppDatabase {
|
||||||
|
Future<List<GroupData>> getAllGroups() async {
|
||||||
|
return await select(group).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<GroupData> getGroupById(String id) async {
|
||||||
|
return await (select(group)..where((g) => g.id.equals(id))).getSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addGroup(String id, String name) async {
|
||||||
|
await into(group).insert(
|
||||||
|
GroupCompanion.insert(id: id, name: name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteGroup(String id) async {
|
||||||
|
await (delete(group)..where((g) => g.id.equals(id))).go();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateGroupname(String id, String newName) async {
|
||||||
|
await (update(group)..where((g) => g.id.equals(id))).write(
|
||||||
|
GroupCompanion(name: Value(newName)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
lib/data/methods/user.dart
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import 'package:game_tracker/data/database.dart';
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
|
||||||
|
extension UserMethods on AppDatabase {
|
||||||
|
Future<List<UserData>> getAllUsers() async {
|
||||||
|
return await select(user).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<UserData> getUserById(String id) async {
|
||||||
|
return await (select(user)..where((u) => u.id.equals(id))).getSingle();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addUser(String id, String name) async {
|
||||||
|
await into(user).insert(
|
||||||
|
UserCompanion.insert(id: id, name: name),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> deleteUser(String id) async {
|
||||||
|
await (delete(user)..where((u) => u.id.equals(id))).go();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateUsername(String id, String newName) async {
|
||||||
|
await (update(user)..where((u) => u.id.equals(id))).write(
|
||||||
|
UserCompanion(name: Value(newName)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
lib/data/methods/user_group.dart
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import 'package:game_tracker/data/database.dart';
|
||||||
|
import 'package:drift/drift.dart';
|
||||||
|
|
||||||
|
extension UserGroupMethods on AppDatabase {
|
||||||
|
Future<List<UserGroupData>> getAllUsersAndGroups() async {
|
||||||
|
return await select(userGroup).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<UserGroupData>> getUsersGroups(String userId) async {
|
||||||
|
return await (select(userGroup)..where((uG) => uG.userId.equals(userId))).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<UserGroupData>> getGroupsUsers(String groupId) async {
|
||||||
|
return await (select(userGroup)..where((uG) => uG.groupId.equals(groupId))).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addUserToGroup(String userId, String groupId) async {
|
||||||
|
await into(userGroup).insert(
|
||||||
|
UserGroupCompanion.insert(userId: userId, groupId: groupId),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> removeUserFromGroup(String userId, String groupId) async {
|
||||||
|
await (delete(userGroup)..where((uG) => uG.userId.equals(userId) & uG.groupId.equals(groupId))).go();
|
||||||
|
}
|
||||||
|
}
|
||||||