feat(app): add Flutter scaffold with config, logging, routing and l10n
Refs #31 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
48
app/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.build/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
.swiftpm/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
**/ios/Flutter/.last_build_id
|
||||
.dart_tool/
|
||||
.flutter-plugins-dependencies
|
||||
.pub-cache/
|
||||
.pub/
|
||||
/build/
|
||||
/coverage/
|
||||
|
||||
# Symbolication related
|
||||
app.*.symbols
|
||||
|
||||
# Obfuscation related
|
||||
app.*.map.json
|
||||
|
||||
# Android Studio will place build artifacts here
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
|
||||
# Widget Preview related
|
||||
.widget_preview/
|
||||
36
app/.metadata
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: "c197ca5199e9ee5661e865596c9c07294dfab51c"
|
||||
channel: "stable"
|
||||
|
||||
project_type: app
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: c197ca5199e9ee5661e865596c9c07294dfab51c
|
||||
base_revision: c197ca5199e9ee5661e865596c9c07294dfab51c
|
||||
- platform: android
|
||||
create_revision: c197ca5199e9ee5661e865596c9c07294dfab51c
|
||||
base_revision: c197ca5199e9ee5661e865596c9c07294dfab51c
|
||||
- platform: ios
|
||||
create_revision: c197ca5199e9ee5661e865596c9c07294dfab51c
|
||||
base_revision: c197ca5199e9ee5661e865596c9c07294dfab51c
|
||||
- platform: web
|
||||
create_revision: c197ca5199e9ee5661e865596c9c07294dfab51c
|
||||
base_revision: c197ca5199e9ee5661e865596c9c07294dfab51c
|
||||
|
||||
# User provided section
|
||||
|
||||
# List of Local paths (relative to this file) that should be
|
||||
# ignored by the migrate tool.
|
||||
#
|
||||
# Files that are not part of the templates will be ignored by default.
|
||||
unmanaged_files:
|
||||
- 'lib/main.dart'
|
||||
- 'ios/Runner.xcodeproj/project.pbxproj'
|
||||
42
app/README.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Shuffle – Flutter-App
|
||||
|
||||
Brettspiel-App für iOS, Android und Web (eine Codebasis). Architektur und Konventionen: `../CLAUDE.md`, `../docs/adr/`.
|
||||
|
||||
## Struktur
|
||||
|
||||
```
|
||||
lib/
|
||||
core/ config, logging, error, result, supabase, routing, l10n, theme
|
||||
features/ <feature>/{data,domain,presentation}
|
||||
l10n/ app_de.arb, app_en.arb (+ generierte AppLocalizations)
|
||||
test/ Spiegel von lib/
|
||||
env/ *.example.json (echte Umgebungsdateien sind git-ignoriert)
|
||||
```
|
||||
|
||||
## Starten
|
||||
|
||||
```bash
|
||||
cd app
|
||||
flutter pub get
|
||||
cp env/dev.example.json env/dev.json # Werte anpassen
|
||||
dart run build_runner build --delete-conflicting-outputs
|
||||
flutter run -d chrome --dart-define-from-file=env/dev.json
|
||||
```
|
||||
|
||||
Pflichtwerte: `SUPABASE_URL`, `SUPABASE_ANON_KEY` (der Start bricht ohne sie ab).
|
||||
Optional mit Platzhalter: `SITE_URL`, `LEGAL_PRIVACY_URL`, `LEGAL_TERMS_URL`, `TERMS_VERSION`, `APP_ENV`.
|
||||
|
||||
## Platzhalter-Identität (vor dem Store-Release festlegen)
|
||||
|
||||
| Was | Wo ändern |
|
||||
|---|---|
|
||||
| Bundle-/Application-ID `work.cshomelabs.shuffle` | `android/app/build.gradle.kts` (`namespace`, `applicationId`), Kotlin-Package unter `android/app/src/main/kotlin/`, `ios/Runner.xcodeproj/project.pbxproj` (`PRODUCT_BUNDLE_IDENTIFIER`) |
|
||||
| App-Name „Shuffle“ | `android/app/src/main/AndroidManifest.xml`, `ios/Runner/Info.plist`, `web/index.html`, `web/manifest.json`, l10n-Schlüssel `appTitle` |
|
||||
| Web-Domain, Rechtstexte, Version der Rechtstexte | `env/*.json` (`SITE_URL`, `LEGAL_*`, `TERMS_VERSION`) |
|
||||
|
||||
Die Bundle-ID lässt sich nach der ersten Store-Veröffentlichung nicht mehr ändern.
|
||||
|
||||
## Hinweise
|
||||
|
||||
- Generierte Dateien (`*.g.dart`, `lib/l10n/app_localizations*.dart`) werden mit eingecheckt; nach Änderungen an `@riverpod`-Code oder ARB-Dateien neu erzeugen (`build_runner`, `flutter gen-l10n`).
|
||||
- Web-URLs ohne `#` (`usePathUrlStrategy`): der Webserver braucht eine SPA-Rewrite-Regel (alle Pfade auf `index.html`).
|
||||
37
app/analysis_options.yaml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
analyzer:
|
||||
exclude:
|
||||
- build/**
|
||||
- android/**
|
||||
- ios/**
|
||||
- web/**
|
||||
- "**/*.g.dart"
|
||||
- "**/*.freezed.dart"
|
||||
- lib/l10n/app_localizations*.dart
|
||||
language:
|
||||
strict-casts: true
|
||||
strict-inference: true
|
||||
strict-raw-types: true
|
||||
errors:
|
||||
missing_required_param: error
|
||||
missing_return: error
|
||||
todo: ignore
|
||||
|
||||
linter:
|
||||
rules:
|
||||
avoid_print: true
|
||||
always_declare_return_types: true
|
||||
prefer_single_quotes: true
|
||||
prefer_const_constructors: true
|
||||
prefer_const_declarations: true
|
||||
prefer_final_locals: true
|
||||
prefer_final_in_for_each: true
|
||||
unawaited_futures: true
|
||||
require_trailing_commas: true
|
||||
sort_pub_dependencies: false
|
||||
directives_ordering: true
|
||||
avoid_dynamic_calls: true
|
||||
use_super_parameters: true
|
||||
cancel_subscriptions: true
|
||||
close_sinks: true
|
||||
14
app/android/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
gradle-wrapper.jar
|
||||
/.gradle
|
||||
/captures/
|
||||
/gradlew
|
||||
/gradlew.bat
|
||||
/local.properties
|
||||
GeneratedPluginRegistrant.java
|
||||
.cxx/
|
||||
|
||||
# Remember to never publicly share your keystore.
|
||||
# See https://flutter.dev/to/reference-keystore
|
||||
key.properties
|
||||
**/*.keystore
|
||||
**/*.jks
|
||||
49
app/android/app/build.gradle.kts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
plugins {
|
||||
id("com.android.application")
|
||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||
id("dev.flutter.flutter-gradle-plugin")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "work.cshomelabs.shuffle"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId = "work.cshomelabs.shuffle"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||
minSdk = flutter.minSdkVersion
|
||||
targetSdk = flutter.targetSdkVersion
|
||||
// Uses the version code from pubspec.yaml. When using split APKs, 1000 * ABI_VERSION
|
||||
// is added automatically by Flutter. (https://developer.android.com/studio/build/configure-apk-splits#configure-APK-versions)
|
||||
// You can force using the value of versionCode by specifying the `-P force-version-code-ignoring-abi=true`
|
||||
// flag during build.
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
// TODO: Add your own signing config for the release build.
|
||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||
signingConfig = signingConfigs.getByName("debug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source = "../.."
|
||||
}
|
||||
7
app/android/app/src/debug/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
45
app/android/app/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application
|
||||
android:label="Shuffle"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity=""
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
to determine the Window background behind the Flutter UI. -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
android:resource="@style/NormalTheme"
|
||||
/>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
</application>
|
||||
<!-- Required to query activities that can process text, see:
|
||||
https://developer.android.com/training/package-visibility and
|
||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||
|
||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package work.cshomelabs.shuffle
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity : FlutterActivity()
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="?android:colorBackground" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
12
app/android/app/src/main/res/drawable/launch_background.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Modify this file to customize your launch splash screen -->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@android:color/white" />
|
||||
|
||||
<!-- You can insert your own image assets here -->
|
||||
<!-- <item>
|
||||
<bitmap
|
||||
android:gravity="center"
|
||||
android:src="@mipmap/launch_image" />
|
||||
</item> -->
|
||||
</layer-list>
|
||||
BIN
app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 544 B |
BIN
app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 442 B |
BIN
app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 721 B |
BIN
app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1 KiB |
BIN
app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
18
app/android/app/src/main/res/values-night/styles.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
18
app/android/app/src/main/res/values/styles.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
7
app/android/app/src/profile/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- The INTERNET permission is required for development. Specifically,
|
||||
the Flutter tool needs it to communicate with the running application
|
||||
to allow setting breakpoints, to provide hot reload, etc.
|
||||
-->
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
</manifest>
|
||||
24
app/android/build.gradle.kts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
val newBuildDir: Directory =
|
||||
rootProject.layout.buildDirectory
|
||||
.dir("../../build")
|
||||
.get()
|
||||
rootProject.layout.buildDirectory.value(newBuildDir)
|
||||
|
||||
subprojects {
|
||||
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
||||
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
||||
}
|
||||
subprojects {
|
||||
project.evaluationDependsOn(":app")
|
||||
}
|
||||
|
||||
tasks.register<Delete>("clean") {
|
||||
delete(rootProject.layout.buildDirectory)
|
||||
}
|
||||
6
app/android/gradle.properties
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
# This newDsl flag was added by the Flutter template
|
||||
android.newDsl=false
|
||||
# This builtInKotlin flag was added by the Flutter template
|
||||
android.builtInKotlin=false
|
||||
5
app/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-all.zip
|
||||
26
app/android/settings.gradle.kts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
pluginManagement {
|
||||
val flutterSdkPath =
|
||||
run {
|
||||
val properties = java.util.Properties()
|
||||
file("local.properties").inputStream().use { properties.load(it) }
|
||||
val flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
|
||||
flutterSdkPath
|
||||
}
|
||||
|
||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "9.1.0" apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.4.0" apply false
|
||||
}
|
||||
|
||||
include(":app")
|
||||
9
app/env/ci.example.json
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"APP_ENV": "ci",
|
||||
"SUPABASE_URL": "http://localhost:54321",
|
||||
"SUPABASE_ANON_KEY": "public-anon-key-placeholder",
|
||||
"SITE_URL": "http://localhost:3000",
|
||||
"LEGAL_PRIVACY_URL": "https://shuffle.cshomelabs.work/legal/privacy",
|
||||
"LEGAL_TERMS_URL": "https://shuffle.cshomelabs.work/legal/terms",
|
||||
"TERMS_VERSION": "2026-11-draft"
|
||||
}
|
||||
9
app/env/dev.example.json
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"APP_ENV": "dev",
|
||||
"SUPABASE_URL": "http://localhost:54321",
|
||||
"SUPABASE_ANON_KEY": "public-anon-key-placeholder",
|
||||
"SITE_URL": "http://localhost:3000",
|
||||
"LEGAL_PRIVACY_URL": "https://shuffle.cshomelabs.work/legal/privacy",
|
||||
"LEGAL_TERMS_URL": "https://shuffle.cshomelabs.work/legal/terms",
|
||||
"TERMS_VERSION": "2026-11-draft"
|
||||
}
|
||||
34
app/ios/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
**/dgph
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.moved-aside
|
||||
*.pbxuser
|
||||
*.perspectivev3
|
||||
**/*sync/
|
||||
.sconsign.dblite
|
||||
.tags*
|
||||
**/.vagrant/
|
||||
**/DerivedData/
|
||||
Icon?
|
||||
**/Pods/
|
||||
**/.symlinks/
|
||||
profile
|
||||
xcuserdata
|
||||
**/.generated/
|
||||
Flutter/App.framework
|
||||
Flutter/Flutter.framework
|
||||
Flutter/Flutter.podspec
|
||||
Flutter/Generated.xcconfig
|
||||
Flutter/ephemeral/
|
||||
Flutter/app.flx
|
||||
Flutter/app.zip
|
||||
Flutter/flutter_assets/
|
||||
Flutter/flutter_export_environment.sh
|
||||
ServiceDefinitions.json
|
||||
Runner/GeneratedPluginRegistrant.*
|
||||
|
||||
# Exceptions to above rules.
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.pbxuser
|
||||
!default.perspectivev3
|
||||
24
app/ios/Flutter/AppFrameworkInfo.plist
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>App</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>io.flutter.flutter.app</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>App</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
1
app/ios/Flutter/Debug.xcconfig
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include "Generated.xcconfig"
|
||||
1
app/ios/Flutter/Release.xcconfig
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include "Generated.xcconfig"
|
||||
650
app/ios/Runner.xcodeproj/project.pbxproj
Normal file
|
|
@ -0,0 +1,650 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; };
|
||||
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
||||
remoteInfo = Runner;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
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>"; };
|
||||
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; };
|
||||
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>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.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>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; 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>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */,
|
||||
);
|
||||
path = RunnerTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||
);
|
||||
name = Flutter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146E51CF9000F007C117D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146EF1CF9000F007C117D /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
97C147021CF9000F007C117D /* Info.plist */,
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */,
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||
);
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
331C8080294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
331C807D294A63A400263BE5 /* Sources */,
|
||||
331C807F294A63A400263BE5 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */,
|
||||
);
|
||||
name = RunnerTests;
|
||||
productName = RunnerTests;
|
||||
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Runner;
|
||||
packageProductDependencies = (
|
||||
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
|
||||
);
|
||||
productName = Runner;
|
||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1510;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
331C8080294A63A400263BE5 = {
|
||||
CreatedOnToolsVersion = 14.0;
|
||||
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||
};
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 1100;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 97C146E51CF9000F007C117D;
|
||||
packageReferences = (
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
|
||||
);
|
||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
331C807F294A63A400263BE5 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run Script";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
331C807D294A63A400263BE5 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C146FB1CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C147001CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = KSX6GJY9C5;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = work.cshomelabs.shuffle;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
331C8088294A63A400263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = work.cshomelabs.shuffle.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
331C8089294A63A400263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = work.cshomelabs.shuffle.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
331C808A294A63A400263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = work.cshomelabs.shuffle.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
97C147031CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147041CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
97C147061CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = KSX6GJY9C5;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = work.cshomelabs.shuffle;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147071CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = KSX6GJY9C5;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = work.cshomelabs.shuffle;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
331C8088294A63A400263BE5 /* Debug */,
|
||||
331C8089294A63A400263BE5 /* Release */,
|
||||
331C808A294A63A400263BE5 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
97C147031CF9000F007C117D /* Debug */,
|
||||
97C147041CF9000F007C117D /* Release */,
|
||||
249021D3217E4FDB00AE95B9 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
97C147061CF9000F007C117D /* Debug */,
|
||||
97C147071CF9000F007C117D /* Release */,
|
||||
249021D4217E4FDB00AE95B9 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCLocalSwiftPackageReference section */
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
|
||||
isa = XCLocalSwiftPackageReference;
|
||||
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
||||
};
|
||||
/* End XCLocalSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = FlutterGeneratedPluginSwiftPackage;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
}
|
||||
7
app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
119
app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1510"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<PreActions>
|
||||
<ExecutionAction
|
||||
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||
<ActionContent
|
||||
title = "Run Prepare Flutter Framework Script"
|
||||
scriptText = "/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare ">
|
||||
<EnvironmentBuildable>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</EnvironmentBuildable>
|
||||
</ActionContent>
|
||||
</ExecutionAction>
|
||||
</PreActions>
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "331C8080294A63A400263BE5"
|
||||
BuildableName = "RunnerTests.xctest"
|
||||
BlueprintName = "RunnerTests"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
enableGPUValidationMode = "1"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Profile"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
7
app/ios/Runner.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
16
app/ios/Runner/AppDelegate.swift
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import Flutter
|
||||
import UIKit
|
||||
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
|
||||
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
|
||||
}
|
||||
}
|
||||
122
app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"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" : {
|
||||
"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 |
23
app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "LaunchImage@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
BIN
app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 68 B |
5
app/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.
|
||||
37
app/ios/Runner/Base.lproj/LaunchScreen.storyboard
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="EHf-IW-A2E">
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||
</imageView>
|
||||
</subviews>
|
||||
<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>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="LaunchImage" width="168" height="185"/>
|
||||
</resources>
|
||||
</document>
|
||||
26
app/ios/Runner/Base.lproj/Main.storyboard
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<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">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Flutter View Controller-->
|
||||
<scene sceneID="tne-QT-ifu">
|
||||
<objects>
|
||||
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
70
app/ios/Runner/Info.plist
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Shuffle</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>Shuffle</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
<false/>
|
||||
<key>UISceneConfigurations</key>
|
||||
<dict>
|
||||
<key>UIWindowSceneSessionRoleApplication</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UISceneClassName</key>
|
||||
<string>UIWindowScene</string>
|
||||
<key>UISceneConfigurationName</key>
|
||||
<string>flutter</string>
|
||||
<key>UISceneDelegateClassName</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
||||
<key>UISceneStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>Main</string>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
1
app/ios/Runner/Runner-Bridging-Header.h
Normal file
|
|
@ -0,0 +1 @@
|
|||
#import "GeneratedPluginRegistrant.h"
|
||||
6
app/ios/Runner/SceneDelegate.swift
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import Flutter
|
||||
import UIKit
|
||||
|
||||
class SceneDelegate: FlutterSceneDelegate {
|
||||
|
||||
}
|
||||
12
app/ios/RunnerTests/RunnerTests.swift
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import Flutter
|
||||
import UIKit
|
||||
import XCTest
|
||||
|
||||
class RunnerTests: XCTestCase {
|
||||
|
||||
func testExample() {
|
||||
// If you add code to the Runner application, consider adding tests here.
|
||||
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||
}
|
||||
|
||||
}
|
||||
5
app/l10n.yaml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
arb-dir: lib/l10n
|
||||
template-arb-file: app_en.arb
|
||||
output-localization-file: app_localizations.dart
|
||||
output-class: AppLocalizations
|
||||
nullable-getter: false
|
||||
29
app/lib/app.dart
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:shuffle/core/l10n/app_locale.dart';
|
||||
import 'package:shuffle/core/routing/app_router.dart';
|
||||
import 'package:shuffle/core/theme/app_theme.dart';
|
||||
import 'package:shuffle/l10n/app_localizations.dart';
|
||||
|
||||
class ShuffleApp extends ConsumerWidget {
|
||||
const ShuffleApp({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return MaterialApp.router(
|
||||
onGenerateTitle: (context) => AppLocalizations.of(context).appTitle,
|
||||
theme: AppTheme.light(),
|
||||
routerConfig: ref.watch(appRouterProvider),
|
||||
locale: ref.watch(appLocaleProvider),
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
localeResolutionCallback: (locale, supported) => resolveAppLocale(locale),
|
||||
);
|
||||
}
|
||||
}
|
||||
103
app/lib/core/config/app_config.dart
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/// Laufzeitkonfiguration der App.
|
||||
///
|
||||
/// Die Werte kommen zur Build-Zeit aus `--dart-define-from-file=env/<stage>.json`
|
||||
/// (siehe `app/env/*.example.json`). Secrets gehören nicht ins Repo.
|
||||
class AppConfig {
|
||||
const AppConfig({
|
||||
required this.environment,
|
||||
required this.supabaseUrl,
|
||||
required this.supabaseAnonKey,
|
||||
required this.siteUrl,
|
||||
required this.legalPrivacyUrl,
|
||||
required this.legalTermsUrl,
|
||||
required this.termsVersion,
|
||||
});
|
||||
|
||||
/// Liest die Konfiguration aus den `--dart-define`-Werten.
|
||||
///
|
||||
/// `String.fromEnvironment` muss mit konstanten Namen aufgerufen werden;
|
||||
/// deshalb steht jeder Schlüssel hier einzeln.
|
||||
factory AppConfig.fromEnvironment() => const AppConfig(
|
||||
environment: String.fromEnvironment(
|
||||
keyAppEnv,
|
||||
defaultValue: defaultEnvironment,
|
||||
),
|
||||
supabaseUrl: String.fromEnvironment(keySupabaseUrl),
|
||||
supabaseAnonKey: String.fromEnvironment(keySupabaseAnonKey),
|
||||
siteUrl: String.fromEnvironment(keySiteUrl, defaultValue: defaultSiteUrl),
|
||||
legalPrivacyUrl: String.fromEnvironment(
|
||||
keyLegalPrivacyUrl,
|
||||
defaultValue: defaultLegalPrivacyUrl,
|
||||
),
|
||||
legalTermsUrl: String.fromEnvironment(
|
||||
keyLegalTermsUrl,
|
||||
defaultValue: defaultLegalTermsUrl,
|
||||
),
|
||||
termsVersion: String.fromEnvironment(
|
||||
keyTermsVersion,
|
||||
defaultValue: defaultTermsVersion,
|
||||
),
|
||||
);
|
||||
|
||||
/// Baut die Konfiguration aus einer Map (Tests, Tooling). Fehlende
|
||||
/// optionale Werte erhalten dieselben Platzhalter wie [fromEnvironment].
|
||||
factory AppConfig.fromMap(Map<String, String> values) => AppConfig(
|
||||
environment: values[keyAppEnv] ?? defaultEnvironment,
|
||||
supabaseUrl: values[keySupabaseUrl] ?? '',
|
||||
supabaseAnonKey: values[keySupabaseAnonKey] ?? '',
|
||||
siteUrl: values[keySiteUrl] ?? defaultSiteUrl,
|
||||
legalPrivacyUrl: values[keyLegalPrivacyUrl] ?? defaultLegalPrivacyUrl,
|
||||
legalTermsUrl: values[keyLegalTermsUrl] ?? defaultLegalTermsUrl,
|
||||
termsVersion: values[keyTermsVersion] ?? defaultTermsVersion,
|
||||
);
|
||||
|
||||
static const keyAppEnv = 'APP_ENV';
|
||||
static const keySupabaseUrl = 'SUPABASE_URL';
|
||||
static const keySupabaseAnonKey = 'SUPABASE_ANON_KEY';
|
||||
static const keySiteUrl = 'SITE_URL';
|
||||
static const keyLegalPrivacyUrl = 'LEGAL_PRIVACY_URL';
|
||||
static const keyLegalTermsUrl = 'LEGAL_TERMS_URL';
|
||||
static const keyTermsVersion = 'TERMS_VERSION';
|
||||
|
||||
// Platzhalter (Spec #1 § 5.1), bis Chris die echten Werte festlegt.
|
||||
static const defaultEnvironment = 'dev';
|
||||
static const defaultSiteUrl = 'https://shuffle.cshomelabs.work';
|
||||
static const defaultLegalPrivacyUrl =
|
||||
'https://shuffle.cshomelabs.work/legal/privacy';
|
||||
static const defaultLegalTermsUrl =
|
||||
'https://shuffle.cshomelabs.work/legal/terms';
|
||||
static const defaultTermsVersion = '2026-11-draft';
|
||||
|
||||
/// Name der Stage (`dev`, `ci`, `staging`, `prod`).
|
||||
final String environment;
|
||||
final String supabaseUrl;
|
||||
final String supabaseAnonKey;
|
||||
|
||||
/// Öffentliche Basis-URL der Web-App (Ziel der Mail-Links).
|
||||
final String siteUrl;
|
||||
final String legalPrivacyUrl;
|
||||
final String legalTermsUrl;
|
||||
|
||||
/// Version der Rechtstexte, die bei der Registrierung gespeichert wird.
|
||||
final String termsVersion;
|
||||
|
||||
/// Namen der Pflichtwerte, die fehlen oder leer sind.
|
||||
List<String> get missingKeys => [
|
||||
if (supabaseUrl.isEmpty) keySupabaseUrl,
|
||||
if (supabaseAnonKey.isEmpty) keySupabaseAnonKey,
|
||||
];
|
||||
|
||||
bool get isValid => missingKeys.isEmpty;
|
||||
|
||||
/// Wirft einen [StateError], wenn Pflichtwerte fehlen.
|
||||
void validate() {
|
||||
final missing = missingKeys;
|
||||
if (missing.isNotEmpty) {
|
||||
throw StateError(
|
||||
'Missing app configuration: ${missing.join(', ')}. '
|
||||
'Start the app with --dart-define-from-file=env/<stage>.json '
|
||||
'(see app/env/dev.example.json).',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
8
app/lib/core/config/app_config_provider.dart
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:shuffle/core/config/app_config.dart';
|
||||
|
||||
part 'app_config_provider.g.dart';
|
||||
|
||||
/// Konfiguration aus `--dart-define-from-file`. In Tests überschreiben.
|
||||
@Riverpod(keepAlive: true)
|
||||
AppConfig appConfig(Ref ref) => AppConfig.fromEnvironment();
|
||||
55
app/lib/core/config/app_config_provider.g.dart
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'app_config_provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Konfiguration aus `--dart-define-from-file`. In Tests überschreiben.
|
||||
|
||||
@ProviderFor(appConfig)
|
||||
final appConfigProvider = AppConfigProvider._();
|
||||
|
||||
/// Konfiguration aus `--dart-define-from-file`. In Tests überschreiben.
|
||||
|
||||
final class AppConfigProvider
|
||||
extends $FunctionalProvider<AppConfig, AppConfig, AppConfig>
|
||||
with $Provider<AppConfig> {
|
||||
/// Konfiguration aus `--dart-define-from-file`. In Tests überschreiben.
|
||||
AppConfigProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'appConfigProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$appConfigHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<AppConfig> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
AppConfig create(Ref ref) {
|
||||
return appConfig(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(AppConfig value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<AppConfig>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$appConfigHash() => r'87f9d20a2d92252672162b2ce97547b7b2479239';
|
||||
24
app/lib/core/error/global_error_handler.dart
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:shuffle/core/logging/app_logger.dart';
|
||||
|
||||
/// Leitet nicht abgefangene Framework- und Plattformfehler an den Logger.
|
||||
void installGlobalErrorHandlers({AppLogger? logger}) {
|
||||
final log = logger ?? AppLogger('GlobalError');
|
||||
|
||||
FlutterError.onError = (details) {
|
||||
log.error(
|
||||
'Flutter framework error',
|
||||
error: details.exception,
|
||||
stackTrace: details.stack,
|
||||
);
|
||||
// Im Debug-Modus zusätzlich die Standardausgabe der Konsole.
|
||||
if (kDebugMode) {
|
||||
FlutterError.presentError(details);
|
||||
}
|
||||
};
|
||||
|
||||
PlatformDispatcher.instance.onError = (error, stackTrace) {
|
||||
log.error('Uncaught platform error', error: error, stackTrace: stackTrace);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
51
app/lib/core/l10n/app_locale.dart
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:shuffle/l10n/app_localizations.dart';
|
||||
|
||||
part 'app_locale.g.dart';
|
||||
|
||||
/// Fallback-Sprache, wenn die Gerätesprache nicht unterstützt wird
|
||||
/// (QUE-05 Kriterium 4).
|
||||
const fallbackLocale = Locale('en');
|
||||
|
||||
/// Bildet eine Gerätesprache auf eine unterstützte Sprache ab (de/en, sonst en).
|
||||
///
|
||||
/// Wird auch als `localeResolutionCallback` genutzt: gen-l10n sortiert die
|
||||
/// unterstützten Sprachen alphabetisch, Flutter würde sonst auf Deutsch fallen.
|
||||
Locale resolveAppLocale(Locale? deviceLocale) {
|
||||
if (deviceLocale == null) {
|
||||
return fallbackLocale;
|
||||
}
|
||||
for (final supported in AppLocalizations.supportedLocales) {
|
||||
if (supported.languageCode == deviceLocale.languageCode) {
|
||||
return Locale(supported.languageCode);
|
||||
}
|
||||
}
|
||||
return fallbackLocale;
|
||||
}
|
||||
|
||||
/// Aktive Oberflächensprache: Gerätesprache (de/en), sonst Englisch.
|
||||
///
|
||||
/// Folgt Änderungen der Gerätesprache. Eine manuelle Wahl folgt mit KTO-11.
|
||||
@Riverpod(keepAlive: true)
|
||||
class AppLocale extends _$AppLocale {
|
||||
@override
|
||||
Locale build() {
|
||||
final binding = WidgetsBinding.instance;
|
||||
final observer = _LocaleObserver(
|
||||
(locales) => state = resolveAppLocale(locales?.firstOrNull),
|
||||
);
|
||||
binding.addObserver(observer);
|
||||
ref.onDispose(() => binding.removeObserver(observer));
|
||||
return resolveAppLocale(binding.platformDispatcher.locales.firstOrNull);
|
||||
}
|
||||
}
|
||||
|
||||
class _LocaleObserver with WidgetsBindingObserver {
|
||||
_LocaleObserver(this._onChanged);
|
||||
|
||||
final void Function(List<Locale>? locales) _onChanged;
|
||||
|
||||
@override
|
||||
void didChangeLocales(List<Locale>? locales) => _onChanged(locales);
|
||||
}
|
||||
74
app/lib/core/l10n/app_locale.g.dart
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'app_locale.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Aktive Oberflächensprache: Gerätesprache (de/en), sonst Englisch.
|
||||
///
|
||||
/// Folgt Änderungen der Gerätesprache. Eine manuelle Wahl folgt mit KTO-11.
|
||||
|
||||
@ProviderFor(AppLocale)
|
||||
final appLocaleProvider = AppLocaleProvider._();
|
||||
|
||||
/// Aktive Oberflächensprache: Gerätesprache (de/en), sonst Englisch.
|
||||
///
|
||||
/// Folgt Änderungen der Gerätesprache. Eine manuelle Wahl folgt mit KTO-11.
|
||||
final class AppLocaleProvider extends $NotifierProvider<AppLocale, Locale> {
|
||||
/// Aktive Oberflächensprache: Gerätesprache (de/en), sonst Englisch.
|
||||
///
|
||||
/// Folgt Änderungen der Gerätesprache. Eine manuelle Wahl folgt mit KTO-11.
|
||||
AppLocaleProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'appLocaleProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$appLocaleHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
AppLocale create() => AppLocale();
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(Locale value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<Locale>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$appLocaleHash() => r'69f10aec719d677951a31d0551fe3bc440e4fbcd';
|
||||
|
||||
/// Aktive Oberflächensprache: Gerätesprache (de/en), sonst Englisch.
|
||||
///
|
||||
/// Folgt Änderungen der Gerätesprache. Eine manuelle Wahl folgt mit KTO-11.
|
||||
|
||||
abstract class _$AppLocale extends $Notifier<Locale> {
|
||||
Locale build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
WhenComplete runBuild() {
|
||||
final ref = this.ref as $Ref<Locale, Locale>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<Locale, Locale>,
|
||||
Locale,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
return element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
8
app/lib/core/l10n/l10n.dart
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
import 'package:shuffle/l10n/app_localizations.dart';
|
||||
|
||||
export 'package:shuffle/l10n/app_localizations.dart';
|
||||
|
||||
extension AppLocalizationsContext on BuildContext {
|
||||
AppLocalizations get l10n => AppLocalizations.of(this);
|
||||
}
|
||||
41
app/lib/core/logging/app_logger.dart
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import 'dart:developer' as developer;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
/// Zentrales Logger-Utility (Wrapper um `package:logging`).
|
||||
///
|
||||
/// Regeln: kein `print`, keine personenbezogenen Daten (E-Mail, Namen,
|
||||
/// Passwörter, Tokens) in Nachrichten oder Fehlerobjekten.
|
||||
class AppLogger {
|
||||
AppLogger(String name) : _logger = Logger(name);
|
||||
|
||||
final Logger _logger;
|
||||
|
||||
void debug(String message) => _logger.fine(message);
|
||||
|
||||
void info(String message) => _logger.info(message);
|
||||
|
||||
void warning(String message, {Object? error, StackTrace? stackTrace}) =>
|
||||
_logger.warning(message, error, stackTrace);
|
||||
|
||||
void error(String message, {Object? error, StackTrace? stackTrace}) =>
|
||||
_logger.severe(message, error, stackTrace);
|
||||
|
||||
/// Richtet die Ausgabe einmalig ein. Release: ab INFO, sonst alles.
|
||||
static void configure({Level? level}) {
|
||||
Logger.root.level = level ?? (kReleaseMode ? Level.INFO : Level.ALL);
|
||||
Logger.root.onRecord.listen(_write);
|
||||
}
|
||||
|
||||
static void _write(LogRecord record) {
|
||||
developer.log(
|
||||
record.message,
|
||||
time: record.time,
|
||||
level: record.level.value,
|
||||
name: record.loggerName,
|
||||
error: record.error,
|
||||
stackTrace: record.stackTrace,
|
||||
);
|
||||
}
|
||||
}
|
||||
40
app/lib/core/result/result.dart
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/// Einfaches Ergebnis-Typ für erwartbare Fehler (kein zusätzliches Paket).
|
||||
sealed class Result<T, E> {
|
||||
const Result();
|
||||
|
||||
const factory Result.success(T value) = Success<T, E>;
|
||||
const factory Result.failure(E error) = Failure<T, E>;
|
||||
|
||||
bool get isSuccess => this is Success<T, E>;
|
||||
bool get isFailure => this is Failure<T, E>;
|
||||
|
||||
/// Wert bei Erfolg, sonst `null`.
|
||||
T? get valueOrNull => switch (this) {
|
||||
Success<T, E>(:final value) => value,
|
||||
Failure<T, E>() => null,
|
||||
};
|
||||
|
||||
/// Fehler bei Misserfolg, sonst `null`.
|
||||
E? get errorOrNull => switch (this) {
|
||||
Success<T, E>() => null,
|
||||
Failure<T, E>(:final error) => error,
|
||||
};
|
||||
|
||||
R when<R>({
|
||||
required R Function(T value) success,
|
||||
required R Function(E error) failure,
|
||||
}) => switch (this) {
|
||||
Success<T, E>(:final value) => success(value),
|
||||
Failure<T, E>(:final error) => failure(error),
|
||||
};
|
||||
}
|
||||
|
||||
final class Success<T, E> extends Result<T, E> {
|
||||
const Success(this.value);
|
||||
final T value;
|
||||
}
|
||||
|
||||
final class Failure<T, E> extends Result<T, E> {
|
||||
const Failure(this.error);
|
||||
final E error;
|
||||
}
|
||||
28
app/lib/core/routing/app_router.dart
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:shuffle/core/routing/app_routes.dart';
|
||||
import 'package:shuffle/core/routing/not_found_screen.dart';
|
||||
import 'package:shuffle/core/routing/redirect_source.dart';
|
||||
import 'package:shuffle/features/home/presentation/home_screen.dart';
|
||||
|
||||
part 'app_router.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
GoRouter appRouter(Ref ref) {
|
||||
final source = ref.watch(redirectSourceProvider);
|
||||
|
||||
final router = GoRouter(
|
||||
initialLocation: AppRoutes.home,
|
||||
refreshListenable: source.changes,
|
||||
redirect: (context, state) => source.redirect(state),
|
||||
errorBuilder: (context, state) => const NotFoundScreen(),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: AppRoutes.home,
|
||||
builder: (context, state) => const HomeScreen(),
|
||||
),
|
||||
],
|
||||
);
|
||||
ref.onDispose(router.dispose);
|
||||
return router;
|
||||
}
|
||||
51
app/lib/core/routing/app_router.g.dart
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'app_router.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(appRouter)
|
||||
final appRouterProvider = AppRouterProvider._();
|
||||
|
||||
final class AppRouterProvider
|
||||
extends $FunctionalProvider<GoRouter, GoRouter, GoRouter>
|
||||
with $Provider<GoRouter> {
|
||||
AppRouterProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'appRouterProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$appRouterHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<GoRouter> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
GoRouter create(Ref ref) {
|
||||
return appRouter(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(GoRouter value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<GoRouter>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$appRouterHash() => r'c3ba8cecc011ab4327ceb2284a58118355176803';
|
||||
4
app/lib/core/routing/app_routes.dart
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
/// Pfade der App. Weitere Routen kommen mit den Features.
|
||||
abstract final class AppRoutes {
|
||||
static const home = '/';
|
||||
}
|
||||
35
app/lib/core/routing/not_found_screen.dart
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:shuffle/core/l10n/l10n.dart';
|
||||
import 'package:shuffle/core/routing/app_routes.dart';
|
||||
|
||||
/// 404-Seite für unbekannte Pfade.
|
||||
class NotFoundScreen extends StatelessWidget {
|
||||
const NotFoundScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
return Scaffold(
|
||||
key: const Key('not_found_screen'),
|
||||
appBar: AppBar(title: Text(l10n.notFoundTitle)),
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(l10n.notFoundMessage, textAlign: TextAlign.center),
|
||||
const SizedBox(height: 16),
|
||||
FilledButton(
|
||||
key: const Key('not_found_home_button'),
|
||||
onPressed: () => context.go(AppRoutes.home),
|
||||
child: Text(l10n.notFoundBackHome),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
33
app/lib/core/routing/redirect_source.dart
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'redirect_source.g.dart';
|
||||
|
||||
/// Austauschbare Quelle für Redirect-Entscheidungen des Routers.
|
||||
///
|
||||
/// Das Fundament liefert [NoRedirectSource]. Die Auth-Story (#1) überschreibt
|
||||
/// [redirectSource] mit einer Implementierung, die den Anmeldestatus kennt.
|
||||
abstract interface class RedirectSource {
|
||||
/// Löst eine Neubewertung der Redirects aus (z. B. Anmeldestatus ändert sich).
|
||||
Listenable get changes;
|
||||
|
||||
/// Zielpfad für den Redirect oder `null`, wenn die Route bleibt.
|
||||
String? redirect(GoRouterState state);
|
||||
}
|
||||
|
||||
/// Standard: kein Redirect, keine Änderungen.
|
||||
class NoRedirectSource implements RedirectSource {
|
||||
const NoRedirectSource();
|
||||
|
||||
@override
|
||||
Listenable get changes => _never;
|
||||
|
||||
@override
|
||||
String? redirect(GoRouterState state) => null;
|
||||
|
||||
static final _never = ValueNotifier<int>(0);
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
RedirectSource redirectSource(Ref ref) => const NoRedirectSource();
|
||||
51
app/lib/core/routing/redirect_source.g.dart
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'redirect_source.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
|
||||
@ProviderFor(redirectSource)
|
||||
final redirectSourceProvider = RedirectSourceProvider._();
|
||||
|
||||
final class RedirectSourceProvider
|
||||
extends $FunctionalProvider<RedirectSource, RedirectSource, RedirectSource>
|
||||
with $Provider<RedirectSource> {
|
||||
RedirectSourceProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'redirectSourceProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$redirectSourceHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<RedirectSource> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
RedirectSource create(Ref ref) {
|
||||
return redirectSource(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(RedirectSource value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<RedirectSource>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$redirectSourceHash() => r'c568056f573be8b72071c02e497ace86ebf04dc8';
|
||||
12
app/lib/core/routing/url_strategy.dart
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_web_plugins/url_strategy.dart';
|
||||
|
||||
/// Web: saubere Pfade ohne `#`. Auf Mobilgeräten ohne Wirkung.
|
||||
///
|
||||
/// Der Webserver braucht dafür eine SPA-Rewrite-Regel (alle Pfade auf
|
||||
/// `index.html`).
|
||||
void configurePathUrlStrategy() {
|
||||
if (kIsWeb) {
|
||||
usePathUrlStrategy();
|
||||
}
|
||||
}
|
||||
9
app/lib/core/supabase/supabase_client_provider.dart
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
part 'supabase_client_provider.g.dart';
|
||||
|
||||
/// Der initialisierte Supabase-Client (`Supabase.initialize` läuft in `main`).
|
||||
/// In Tests mit einem Mock überschreiben.
|
||||
@Riverpod(keepAlive: true)
|
||||
SupabaseClient supabaseClient(Ref ref) => Supabase.instance.client;
|
||||
58
app/lib/core/supabase/supabase_client_provider.g.dart
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'supabase_client_provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Der initialisierte Supabase-Client (`Supabase.initialize` läuft in `main`).
|
||||
/// In Tests mit einem Mock überschreiben.
|
||||
|
||||
@ProviderFor(supabaseClient)
|
||||
final supabaseClientProvider = SupabaseClientProvider._();
|
||||
|
||||
/// Der initialisierte Supabase-Client (`Supabase.initialize` läuft in `main`).
|
||||
/// In Tests mit einem Mock überschreiben.
|
||||
|
||||
final class SupabaseClientProvider
|
||||
extends $FunctionalProvider<SupabaseClient, SupabaseClient, SupabaseClient>
|
||||
with $Provider<SupabaseClient> {
|
||||
/// Der initialisierte Supabase-Client (`Supabase.initialize` läuft in `main`).
|
||||
/// In Tests mit einem Mock überschreiben.
|
||||
SupabaseClientProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'supabaseClientProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$supabaseClientHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
$ProviderElement<SupabaseClient> $createElement($ProviderPointer pointer) =>
|
||||
$ProviderElement(pointer);
|
||||
|
||||
@override
|
||||
SupabaseClient create(Ref ref) {
|
||||
return supabaseClient(ref);
|
||||
}
|
||||
|
||||
/// {@macro riverpod.override_with_value}
|
||||
Override overrideWithValue(SupabaseClient value) {
|
||||
return $ProviderOverride(
|
||||
origin: this,
|
||||
providerOverride: $SyncValueProvider<SupabaseClient>(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$supabaseClientHash() => r'3db2a4c212c7f24cea9810e376225aa1a6cab012';
|
||||
10
app/lib/core/theme/app_theme.dart
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Minimales Platzhalter-Theme. Wird vom Design-System (F6, ui-designer)
|
||||
/// ersetzt; `ShuffleApp` greift nur auf [AppTheme.light] zu.
|
||||
abstract final class AppTheme {
|
||||
static ThemeData light() => ThemeData(
|
||||
useMaterial3: true,
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
|
||||
);
|
||||
}
|
||||
26
app/lib/features/home/presentation/home_screen.dart
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:shuffle/core/l10n/l10n.dart';
|
||||
|
||||
/// Platzhalter-Startseite. Wird durch die Katalogsuche bzw. QUE-09 ersetzt.
|
||||
class HomeScreen extends StatelessWidget {
|
||||
const HomeScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = context.l10n;
|
||||
return Scaffold(
|
||||
key: const Key('home_screen'),
|
||||
appBar: AppBar(title: Text(l10n.appTitle)),
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Text(
|
||||
l10n.homePlaceholderMessage,
|
||||
key: const Key('home_placeholder_message'),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
8
app/lib/l10n/app_de.arb
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"@@locale": "de",
|
||||
"appTitle": "Shuffle",
|
||||
"homePlaceholderMessage": "Willkommen bei Shuffle. Der Brettspielkatalog folgt in Kürze.",
|
||||
"notFoundTitle": "Seite nicht gefunden",
|
||||
"notFoundMessage": "Diese Seite existiert nicht oder wurde verschoben.",
|
||||
"notFoundBackHome": "Zurück zum Start"
|
||||
}
|
||||
23
app/lib/l10n/app_en.arb
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"@@locale": "en",
|
||||
"appTitle": "Shuffle",
|
||||
"@appTitle": {
|
||||
"description": "Name of the app"
|
||||
},
|
||||
"homePlaceholderMessage": "Welcome to Shuffle. The board game catalog is coming soon.",
|
||||
"@homePlaceholderMessage": {
|
||||
"description": "Placeholder text on the start page until real content exists"
|
||||
},
|
||||
"notFoundTitle": "Page not found",
|
||||
"@notFoundTitle": {
|
||||
"description": "Title of the 404 page"
|
||||
},
|
||||
"notFoundMessage": "This page does not exist or has been moved.",
|
||||
"@notFoundMessage": {
|
||||
"description": "Explanation on the 404 page"
|
||||
},
|
||||
"notFoundBackHome": "Back to start",
|
||||
"@notFoundBackHome": {
|
||||
"description": "Button on the 404 page that navigates to the start page"
|
||||
}
|
||||
}
|
||||
164
app/lib/l10n/app_localizations.dart
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
|
||||
import 'app_localizations_de.dart';
|
||||
import 'app_localizations_en.dart';
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
/// Callers can lookup localized strings with an instance of AppLocalizations
|
||||
/// returned by `AppLocalizations.of(context)`.
|
||||
///
|
||||
/// Applications need to include `AppLocalizations.delegate()` in their app's
|
||||
/// `localizationDelegates` list, and the locales they support in the app's
|
||||
/// `supportedLocales` list. For example:
|
||||
///
|
||||
/// ```dart
|
||||
/// import 'l10n/app_localizations.dart';
|
||||
///
|
||||
/// return MaterialApp(
|
||||
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
/// supportedLocales: AppLocalizations.supportedLocales,
|
||||
/// home: MyApplicationHome(),
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// ## Update pubspec.yaml
|
||||
///
|
||||
/// Please make sure to update your pubspec.yaml to include the following
|
||||
/// packages:
|
||||
///
|
||||
/// ```yaml
|
||||
/// dependencies:
|
||||
/// # Internationalization support.
|
||||
/// flutter_localizations:
|
||||
/// sdk: flutter
|
||||
/// intl: any # Use the pinned version from flutter_localizations
|
||||
///
|
||||
/// # Rest of dependencies
|
||||
/// ```
|
||||
///
|
||||
/// ## iOS Applications
|
||||
///
|
||||
/// iOS applications define key application metadata, including supported
|
||||
/// locales, in an Info.plist file that is built into the application bundle.
|
||||
/// To configure the locales supported by your app, you’ll need to edit this
|
||||
/// file.
|
||||
///
|
||||
/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file.
|
||||
/// Then, in the Project Navigator, open the Info.plist file under the Runner
|
||||
/// project’s Runner folder.
|
||||
///
|
||||
/// Next, select the Information Property List item, select Add Item from the
|
||||
/// Editor menu, then select Localizations from the pop-up menu.
|
||||
///
|
||||
/// Select and expand the newly-created Localizations item then, for each
|
||||
/// locale your application supports, add a new item and select the locale
|
||||
/// you wish to add from the pop-up menu in the Value field. This list should
|
||||
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
|
||||
/// property.
|
||||
abstract class AppLocalizations {
|
||||
AppLocalizations(String locale)
|
||||
: localeName = intl.Intl.canonicalizedLocale(locale.toString());
|
||||
|
||||
final String localeName;
|
||||
|
||||
static AppLocalizations of(BuildContext context) {
|
||||
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
|
||||
}
|
||||
|
||||
static const LocalizationsDelegate<AppLocalizations> delegate =
|
||||
_AppLocalizationsDelegate();
|
||||
|
||||
/// A list of this localizations delegate along with the default localizations
|
||||
/// delegates.
|
||||
///
|
||||
/// Returns a list of localizations delegates containing this delegate along with
|
||||
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
|
||||
/// and GlobalWidgetsLocalizations.delegate.
|
||||
///
|
||||
/// Additional delegates can be added by appending to this list in
|
||||
/// MaterialApp. This list does not have to be used at all if a custom list
|
||||
/// of delegates is preferred or required.
|
||||
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates =
|
||||
<LocalizationsDelegate<dynamic>>[
|
||||
delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
];
|
||||
|
||||
/// A list of this localizations delegate's supported locales.
|
||||
static const List<Locale> supportedLocales = <Locale>[
|
||||
Locale('de'),
|
||||
Locale('en'),
|
||||
];
|
||||
|
||||
/// Name of the app
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Shuffle'**
|
||||
String get appTitle;
|
||||
|
||||
/// Placeholder text on the start page until real content exists
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Welcome to Shuffle. The board game catalog is coming soon.'**
|
||||
String get homePlaceholderMessage;
|
||||
|
||||
/// Title of the 404 page
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Page not found'**
|
||||
String get notFoundTitle;
|
||||
|
||||
/// Explanation on the 404 page
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'This page does not exist or has been moved.'**
|
||||
String get notFoundMessage;
|
||||
|
||||
/// Button on the 404 page that navigates to the start page
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Back to start'**
|
||||
String get notFoundBackHome;
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
extends LocalizationsDelegate<AppLocalizations> {
|
||||
const _AppLocalizationsDelegate();
|
||||
|
||||
@override
|
||||
Future<AppLocalizations> load(Locale locale) {
|
||||
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
|
||||
}
|
||||
|
||||
@override
|
||||
bool isSupported(Locale locale) =>
|
||||
<String>['de', 'en'].contains(locale.languageCode);
|
||||
|
||||
@override
|
||||
bool shouldReload(_AppLocalizationsDelegate old) => false;
|
||||
}
|
||||
|
||||
AppLocalizations lookupAppLocalizations(Locale locale) {
|
||||
// Lookup logic when only language code is specified.
|
||||
switch (locale.languageCode) {
|
||||
case 'de':
|
||||
return AppLocalizationsDe();
|
||||
case 'en':
|
||||
return AppLocalizationsEn();
|
||||
}
|
||||
|
||||
throw FlutterError(
|
||||
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
|
||||
'an issue with the localizations generation tool. Please file an issue '
|
||||
'on GitHub with a reproducible sample app and the gen-l10n configuration '
|
||||
'that was used.',
|
||||
);
|
||||
}
|
||||
28
app/lib/l10n/app_localizations_de.dart
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// ignore: unused_import
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
|
||||
import 'app_localizations.dart';
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
/// The translations for German (`de`).
|
||||
class AppLocalizationsDe extends AppLocalizations {
|
||||
AppLocalizationsDe([String locale = 'de']) : super(locale);
|
||||
|
||||
@override
|
||||
String get appTitle => 'Shuffle';
|
||||
|
||||
@override
|
||||
String get homePlaceholderMessage =>
|
||||
'Willkommen bei Shuffle. Der Brettspielkatalog folgt in Kürze.';
|
||||
|
||||
@override
|
||||
String get notFoundTitle => 'Seite nicht gefunden';
|
||||
|
||||
@override
|
||||
String get notFoundMessage =>
|
||||
'Diese Seite existiert nicht oder wurde verschoben.';
|
||||
|
||||
@override
|
||||
String get notFoundBackHome => 'Zurück zum Start';
|
||||
}
|
||||
27
app/lib/l10n/app_localizations_en.dart
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// ignore: unused_import
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
|
||||
import 'app_localizations.dart';
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
|
||||
/// The translations for English (`en`).
|
||||
class AppLocalizationsEn extends AppLocalizations {
|
||||
AppLocalizationsEn([String locale = 'en']) : super(locale);
|
||||
|
||||
@override
|
||||
String get appTitle => 'Shuffle';
|
||||
|
||||
@override
|
||||
String get homePlaceholderMessage =>
|
||||
'Welcome to Shuffle. The board game catalog is coming soon.';
|
||||
|
||||
@override
|
||||
String get notFoundTitle => 'Page not found';
|
||||
|
||||
@override
|
||||
String get notFoundMessage => 'This page does not exist or has been moved.';
|
||||
|
||||
@override
|
||||
String get notFoundBackHome => 'Back to start';
|
||||
}
|
||||
23
app/lib/main.dart
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:shuffle/app.dart';
|
||||
import 'package:shuffle/core/config/app_config.dart';
|
||||
import 'package:shuffle/core/error/global_error_handler.dart';
|
||||
import 'package:shuffle/core/logging/app_logger.dart';
|
||||
import 'package:shuffle/core/routing/url_strategy.dart';
|
||||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
Future<void> main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
AppLogger.configure();
|
||||
installGlobalErrorHandlers();
|
||||
configurePathUrlStrategy();
|
||||
|
||||
final config = AppConfig.fromEnvironment()..validate();
|
||||
await Supabase.initialize(
|
||||
url: config.supabaseUrl,
|
||||
publishableKey: config.supabaseAnonKey,
|
||||
);
|
||||
|
||||
runApp(const ProviderScope(child: ShuffleApp()));
|
||||
}
|
||||
999
app/pubspec.lock
Normal file
|
|
@ -0,0 +1,999 @@
|
|||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: "1c5591cc6f252d5f440d96ab87c03e43504be552a3fa49d7cb7563f04c51fb0a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "111.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: "6c39bd5486a310e56217bed7cb1691377959f31be4227e41750107db7e6dd55c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.7.0"
|
||||
analyzer_buffer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer_buffer
|
||||
sha256: f890a2e708e38fbf4238ad2f9fd3d506538acdddb0cd8eb2c3e8c7bd17784b57
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.4"
|
||||
app_links:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: app_links
|
||||
sha256: "08ba88bf19d9edea33130cb71c8ced2cb982b4e00b82efef4a434d1357bc69c3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.2"
|
||||
app_links_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: app_links_linux
|
||||
sha256: "9ccb5802085a1e57bb07b6256fd1d61a78c7ec104944d4965e62938b4fefd9cb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
app_links_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: app_links_platform_interface
|
||||
sha256: "7546f09a6e93f4a2df2fe2bd40a5c6c64310ac461b036d82b43033be7a59f809"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
app_links_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: app_links_web
|
||||
sha256: "382d32c6f486f15b1d7f5d6a37a70a481a4fc08382eef419d373169921a3e765"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.7.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.13.1"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
build:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
sha256: "8a5c5761af8e31748bba3c82f68925ace40f3225c3eea25be9beb57eca7cd7a8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.11"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
sha256: d466ed2dc9c6cd1d169948879b84ee061eb5e22c64a7c6089879c6296d272a8d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: "39ab65f7c60c19af64b9ef96e6a5d3ab48355f7dddfd98a9079d55a8cb6628fc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.7"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: "6feadd32d90a68253c1f7b4fcff76adb4b41ad32a53f8bad835dc65f01ac9dc5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.16.2"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_collection
|
||||
sha256: "44922ecebd8e3d0cef743dadd3b54df4e87e2a4c52a29465a1872aa9e192caa8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.2"
|
||||
built_value:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: f87ea98192116f7093cb214551ce1929caae0681fdba282b3d8b4462adee7bb7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.13.0"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: checked_yaml
|
||||
sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.4"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
sha256: e51d50bca3217c9a9fa2b41a30e4a38971133f5f9ec7a3d57bae095007f1d28e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.3"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: code_builder
|
||||
sha256: "811709c1badd02fc054039a13f66e0db1961865f9a314175f68c3eaeebec786f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.13.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.19.1"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.2"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
sha256: e3626ae6270383c9e3a549f34c9e4cd26c09ae6a9adaab2bf4737a00340efdc4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.8"
|
||||
cupertino_ui:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cupertino_ui
|
||||
sha256: e003b87afde18cb396ec15928c7894063d64af04462c68df9a1404c461316dd2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.5"
|
||||
dart_jsonwebtoken:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_jsonwebtoken
|
||||
sha256: ad84e60181696513d04d5f2078e0bbc20365b911f46f647797317414bdc88fbe
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.1"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: a0e4f65339b31eb6a9e6a12e14b4682a48d46fbc54a82f4a702396fbdbac63a7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.14"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.1"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.0.0"
|
||||
flutter_localizations:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_riverpod:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_riverpod
|
||||
sha256: "2b7f9d2a3c730ac1a98221b420cef966b990fca7ab546ede324642ca57a533e3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.3"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
freezed:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: freezed
|
||||
sha256: cb910646cb09265d49077b63b600ef1f5a718c1d6031836432237ddeabae1b12
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.3"
|
||||
freezed_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: freezed_annotation
|
||||
sha256: "7294967ff0a6d98638e7acb774aac3af2550777accd8149c90af5b014e6d44d8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
functions_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: functions_client
|
||||
sha256: "931e822688d2e97867b2300e2fdbb08c9db73f8653fc83efc7a259d2e0cca769"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.7.1"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
sha256: "218aeb56050c714f62a3182775320dfa04602b55074873e24e31bbd39bda96fb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
go_router:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: go_router
|
||||
sha256: f1c2d3c2b0b2096b435d7af033dd4e586fa31f51d988c5985e64495cd926d872
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "18.1.2"
|
||||
gotrue:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: gotrue
|
||||
sha256: cca816226824160e40d149816fd89740cc64dda1eaa3d9161e334330b18bba89
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.27.3"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: graphs
|
||||
sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
http:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.6.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_multi_server
|
||||
sha256: "361668bdd71f0ae2dc6d17b75a593520f3c414af6534f9eed1aa72049dd71d18"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.3"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.2"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
sha256: "1ca20c894b1717686a2319b8548763d812bc0aabdac580420a44c5178c57a867"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.20.3"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: io
|
||||
sha256: "2635216ca6a737e60de577ffa1a48a0bec76ca8a62917cfc1bb88c14c570646f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
jni:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: jni
|
||||
sha256: d8df6dab6847855512fe44dd9032b0bbe34dda7bf7597e41d30750879779813f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
jni_util:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: jni_util
|
||||
sha256: "1ba86da04a5f2bf18fde2edb235587e70c5b0fc5bd4ba955f46b00942c3fc35f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
json_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: json_annotation
|
||||
sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.12.0"
|
||||
json_serializable:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: json_serializable
|
||||
sha256: cc7822761b40be9237bcaae62b755ffe5453ceff96a0001f1f5f2439251c66f1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.15.2"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "11.0.2"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.10"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_testing
|
||||
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: lints
|
||||
sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.0"
|
||||
listen:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: listen
|
||||
sha256: "47501a08016a43fcad79252439d723f50f14f88fa7bfd8a177e0a417e5c9e1f2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
logging:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: logging
|
||||
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.20"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.13.0"
|
||||
material_ui:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_ui
|
||||
sha256: feb289df1e5f9ed9522f9fe3d909432a7f7bc76943f16abad09f80a16cd25196
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: c82594181e3312f3d0695fc95aaaf7758d75b8d4ae2bbecf223b9fd5109a059d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.3"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: bd47de35f07e27267e69c8c8b22edf9473bfee170a60d60fcc93730c5144b7f6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
mockito:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mockito
|
||||
sha256: "6c1970612452260366064d4df80fdb3eece1ec5e52610ae34a0e51f2f3d8e64f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.8.1"
|
||||
mocktail:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: mocktail
|
||||
sha256: "5e1bf53cc7baa8062a33b84424deb61513858ea05c601b8509e683815b5914aa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: ffcf4cf3d6c0b74ac43708d9f56625506e8a68aa935abe9d267a7330f320eb5d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
passkeys_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: passkeys_platform_interface
|
||||
sha256: "5fca044a6f1a3c5abff645ca5a5417b613c130d1c4e08513ba9182c7f4834619"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.10.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: "58c2005f147315b11e9b4a7bc889cd5203e250cba8e3f012dae259b4972b5c16"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.2"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "484838772624c3a4b94f1e44a3e19897fee738f2d5c4ce448443b0417f7c9dda"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: a36d119c13416516a7b5913fbe8af8531e11633d784c550b2125f76c758524ec
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
pointycastle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pointycastle
|
||||
sha256: "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pool
|
||||
sha256: "4177f68c237ea2128d1bee66ac17b2ce05ba3dbaafcbdd54c5d40a39d0b6b11c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.3"
|
||||
postgrest:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: postgrest
|
||||
sha256: b7f957273ba6a1c26cefa987ac524f4138e9ab7542fbb9e6abdfddacb9895a21
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.9.1"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "261236774e8b1d69cfc6b9eabbc96c40f25e7a2d6b171f3385d4f65d5734fb24"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: "9ac81c01ffd6a9cf9b2713288834fbaaf6aebde05ffdf02d380e68b8e06f27d8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.7.0"
|
||||
realtime_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: realtime_client
|
||||
sha256: "2ef680d83ba2c0f76019d16194ca7067fa2458b2d4091b52323a9ca4a964fd40"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.13.2"
|
||||
riverpod:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: riverpod
|
||||
sha256: "484dfc873ea4c4f4240e5635444fa066f87b07862b7279ebd004a2b71fba4b7a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.3"
|
||||
riverpod_analyzer_utils:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: riverpod_analyzer_utils
|
||||
sha256: bb13cb3985815840cc103eda1027158358c5fdc00f308fc6f76574d0594107af
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0-dev.12"
|
||||
riverpod_annotation:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: riverpod_annotation
|
||||
sha256: "322e56ad198928ef26ba240f85421bfff2493bd65665c887b1299e6386b6206d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.7"
|
||||
riverpod_generator:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: riverpod_generator
|
||||
sha256: c94dcb8b60ff4805d2bb8cacca969c48237bcb563e2ab0b5afb50204470c7636
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.9"
|
||||
shared_preferences:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences
|
||||
sha256: "1e85e0dccf5b4a016077fea7dfbb4a7cb39c759ac1596fcf60c06deadb7da91f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.6"
|
||||
shared_preferences_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_android
|
||||
sha256: "33b38b07d9ac7d16aff0426c61418752fd3e7a8c7dc8be786c875d6ce673b002"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.4"
|
||||
shared_preferences_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_foundation
|
||||
sha256: "2ec3934efa51e46117f23031cc141b8fc878e8525b94ec1ea4f7f586cf1b47ea"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.5.7"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_platform_interface
|
||||
sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.2"
|
||||
shared_preferences_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_web
|
||||
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.3"
|
||||
shared_preferences_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_windows
|
||||
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
sha256: e75e9cf311d7fd712048038cc17c25199c38536c20330d53e7db058b543d5a48
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.3"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
sha256: "833ea7d15b5be79949d3d6c077da0267a0bd93c16897b36a771395a91e63086e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.3.1"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
sha256: "279126bce72de3f2b7d4756408a4157988cf6bb4815be551bf55851aa00e9984"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.2"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: "277654b3034d17ac6f9f1cb5595db011b1d5d41e8806866db28e0abaa101c490"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.12.2"
|
||||
state_notifier:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: state_notifier
|
||||
sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
storage_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: storage_client
|
||||
sha256: b951281b8e2b293460f0e6cc4e866f2546681390f0e37d24fbbd7b4a0deb27a3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.8.1"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_transform
|
||||
sha256: a00e5f18bffc764f923e7dec1038527f7fe7a1791361a7117f0358193f13d53a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.1"
|
||||
supabase:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: supabase
|
||||
sha256: "123fe08792b24e5e7c4b9a01145de8e95ebaa9183cd5f3c9d48dd2ff890f28a6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.16.5"
|
||||
supabase_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: supabase_common
|
||||
sha256: a7961a44953cf8d9da049381fc3377516348255042fbb12b9d4f8540816f2fe9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2"
|
||||
supabase_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: supabase_flutter
|
||||
sha256: "48bbde226e68bdb293020859a1bfa42d0f3bd2239992fba0ec4f9194cbb842e6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.18.3"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.2"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "2a122cbe059f8b610d3a5415f42e255b6c17b1f21eee1d960f31080237fb4f11"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.12"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
url_launcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher
|
||||
sha256: e8cc955c97e06df9879140a1fe301f3d493f01b7c62dec7f46834be31d7e9fda
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.3"
|
||||
url_launcher_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_android
|
||||
sha256: "611e87fb320b70d1dd721dc46af89c98aceccea9b31fde49e084591414e0c610"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.3.33"
|
||||
url_launcher_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_ios
|
||||
sha256: "8faa1aab294f1ab4040b43660c887b0418d5fa4f0cffef76a484e6aa1092eb4a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.4.2"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
sha256: "10f86fef4c2c43563fa6c211ff9cf757adf4d3ab762c56bd430664a947d70cd0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.3"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
sha256: "5e835a3b869c2d70325349c81c5a45c28e20791265b67b2669da6b08c5cd5201"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.6"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_platform_interface
|
||||
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
url_launcher_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_web
|
||||
sha256: "85c81589622fbc87c1c683aaea164d3604a7777495a79d91e39ffcdec39ddb34"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.3"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
sha256: "6c5ad3f22cd4c38e089b81963b3cd7bb83b111b2df5dce008bb066162f42e429"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.6"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
sha256: "9b129329f58692f6e6578329498a8fe9fbe98f090beb764ffbb8ee2eadd01dcd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.6.0"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
sha256: fa49e1674cb84acb900141714e6c6e1f9ae099827c24d141430ff6819db4e1bc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.4"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "89b11d62e1040ee681af3b4f1c97a803ecbf010c6e8b9c5896ee5b08c3bf7b78"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "15.4.0"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: e119e82ac4795c7925103b7cf3768191f33941b99e7ccffbd6c645201d9f606b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket
|
||||
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
sha256: f67cdd8e07d3c6329146aaef1ba043542b3134c12489f553ca9a7435d1068aea
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
yet_another_json_isolate:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yet_another_json_isolate
|
||||
sha256: eaa26beb5990b25a49d942374fd5a0c5aa67a837e03b14b4c26134aaa1ed01a9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
sdks:
|
||||
dart: ">=3.13.7 <4.0.0"
|
||||
flutter: ">=3.47.0"
|
||||
39
app/pubspec.yaml
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
name: shuffle
|
||||
description: "Shuffle – Brettspiel-App für iOS, Android und Web."
|
||||
publish_to: 'none'
|
||||
|
||||
version: 0.1.0+1
|
||||
|
||||
environment:
|
||||
sdk: ^3.13.7
|
||||
|
||||
# Versionen gepinnt laut Spec #1 § 5.7 (Fundament-Issue #31).
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
flutter_web_plugins:
|
||||
sdk: flutter
|
||||
flutter_riverpod: 3.4.3
|
||||
riverpod_annotation: 4.0.7
|
||||
go_router: 18.1.2
|
||||
supabase_flutter: 2.18.3
|
||||
freezed_annotation: 3.1.0
|
||||
json_annotation: 4.12.0
|
||||
logging: 1.3.0
|
||||
intl: 0.20.3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
flutter_lints: 6.0.0
|
||||
build_runner: 2.16.2
|
||||
riverpod_generator: 4.0.9
|
||||
freezed: 4.0.3
|
||||
json_serializable: 6.15.2
|
||||
mocktail: 1.0.5
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
generate: true
|
||||
33
app/test/app_test.dart
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:shuffle/app.dart';
|
||||
|
||||
Future<void> _pumpApp(WidgetTester tester) async {
|
||||
await tester.pumpWidget(const ProviderScope(child: ShuffleApp()));
|
||||
await tester.pumpAndSettle();
|
||||
}
|
||||
|
||||
void main() {
|
||||
tearDown(() {
|
||||
TestWidgetsFlutterBinding.instance.platformDispatcher
|
||||
.clearLocalesTestValue();
|
||||
});
|
||||
|
||||
testWidgets('app starts on the placeholder home page (English fallback)', (
|
||||
tester,
|
||||
) async {
|
||||
tester.platformDispatcher.localesTestValue = [const Locale('fr')];
|
||||
await _pumpApp(tester);
|
||||
|
||||
expect(find.byKey(const Key('home_screen')), findsOneWidget);
|
||||
expect(find.textContaining('Welcome to Shuffle'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('app shows German texts on a German device', (tester) async {
|
||||
tester.platformDispatcher.localesTestValue = [const Locale('de', 'DE')];
|
||||
await _pumpApp(tester);
|
||||
|
||||
expect(find.textContaining('Willkommen bei Shuffle'), findsOneWidget);
|
||||
});
|
||||
}
|
||||
65
app/test/core/config/app_config_test.dart
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:shuffle/core/config/app_config.dart';
|
||||
|
||||
void main() {
|
||||
group('AppConfig', () {
|
||||
test('fromMap reads all values', () {
|
||||
final config = AppConfig.fromMap(const {
|
||||
'APP_ENV': 'ci',
|
||||
'SUPABASE_URL': 'http://localhost:54321',
|
||||
'SUPABASE_ANON_KEY': 'anon',
|
||||
'SITE_URL': 'http://localhost:3000',
|
||||
'LEGAL_PRIVACY_URL': 'https://example.org/privacy',
|
||||
'LEGAL_TERMS_URL': 'https://example.org/terms',
|
||||
'TERMS_VERSION': 'v1',
|
||||
});
|
||||
|
||||
expect(config.environment, 'ci');
|
||||
expect(config.supabaseUrl, 'http://localhost:54321');
|
||||
expect(config.supabaseAnonKey, 'anon');
|
||||
expect(config.siteUrl, 'http://localhost:3000');
|
||||
expect(config.legalPrivacyUrl, 'https://example.org/privacy');
|
||||
expect(config.legalTermsUrl, 'https://example.org/terms');
|
||||
expect(config.termsVersion, 'v1');
|
||||
expect(config.isValid, isTrue);
|
||||
expect(config.validate, returnsNormally);
|
||||
});
|
||||
|
||||
test('optional values fall back to placeholders', () {
|
||||
final config = AppConfig.fromMap(const {
|
||||
'SUPABASE_URL': 'http://localhost:54321',
|
||||
'SUPABASE_ANON_KEY': 'anon',
|
||||
});
|
||||
|
||||
expect(config.environment, AppConfig.defaultEnvironment);
|
||||
expect(config.siteUrl, 'https://shuffle.cshomelabs.work');
|
||||
expect(config.legalPrivacyUrl, AppConfig.defaultLegalPrivacyUrl);
|
||||
expect(config.legalTermsUrl, AppConfig.defaultLegalTermsUrl);
|
||||
expect(config.termsVersion, AppConfig.defaultTermsVersion);
|
||||
});
|
||||
|
||||
test('validate lists missing required values', () {
|
||||
final config = AppConfig.fromMap(const {});
|
||||
|
||||
expect(config.isValid, isFalse);
|
||||
expect(config.missingKeys, ['SUPABASE_URL', 'SUPABASE_ANON_KEY']);
|
||||
expect(
|
||||
config.validate,
|
||||
throwsA(
|
||||
isA<StateError>().having(
|
||||
(e) => e.message,
|
||||
'message',
|
||||
contains('SUPABASE_URL'),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('fromEnvironment without defines yields an invalid config', () {
|
||||
final config = AppConfig.fromEnvironment();
|
||||
|
||||
expect(config.isValid, isFalse);
|
||||
expect(config.termsVersion, AppConfig.defaultTermsVersion);
|
||||
});
|
||||
});
|
||||
}
|
||||
42
app/test/core/l10n/app_locale_test.dart
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:shuffle/core/l10n/app_locale.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('resolveAppLocale', () {
|
||||
test('keeps supported languages', () {
|
||||
expect(resolveAppLocale(const Locale('de')), const Locale('de'));
|
||||
expect(resolveAppLocale(const Locale('en')), const Locale('en'));
|
||||
});
|
||||
|
||||
test('drops country codes of supported languages', () {
|
||||
expect(resolveAppLocale(const Locale('de', 'AT')), const Locale('de'));
|
||||
});
|
||||
|
||||
test('falls back to English for unsupported or missing locales', () {
|
||||
expect(resolveAppLocale(const Locale('fr')), const Locale('en'));
|
||||
expect(resolveAppLocale(null), const Locale('en'));
|
||||
});
|
||||
});
|
||||
|
||||
group('appLocaleProvider', () {
|
||||
tearDown(() {
|
||||
TestWidgetsFlutterBinding.instance.platformDispatcher
|
||||
.clearLocalesTestValue();
|
||||
});
|
||||
|
||||
test('uses the device language and follows changes', () {
|
||||
final dispatcher = TestWidgetsFlutterBinding.instance.platformDispatcher
|
||||
..localesTestValue = [const Locale('de', 'DE')];
|
||||
final container = ProviderContainer.test();
|
||||
|
||||
expect(container.read(appLocaleProvider), const Locale('de'));
|
||||
|
||||
dispatcher.localesTestValue = [const Locale('fr', 'FR')];
|
||||
expect(container.read(appLocaleProvider), const Locale('en'));
|
||||
});
|
||||
});
|
||||
}
|
||||
20
app/test/core/logging/app_logger_test.dart
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:shuffle/core/logging/app_logger.dart';
|
||||
|
||||
void main() {
|
||||
test('AppLogger forwards records to package:logging', () {
|
||||
Logger.root.level = Level.ALL;
|
||||
final records = <LogRecord>[];
|
||||
final sub = Logger.root.onRecord.listen(records.add);
|
||||
addTearDown(sub.cancel);
|
||||
|
||||
AppLogger('Test')
|
||||
..info('hello')
|
||||
..error('failed', error: StateError('x'));
|
||||
|
||||
expect(records.map((r) => r.message), ['hello', 'failed']);
|
||||
expect(records.last.level, Level.SEVERE);
|
||||
expect(records.last.loggerName, 'Test');
|
||||
});
|
||||
}
|
||||
22
app/test/core/result/result_test.dart
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:shuffle/core/result/result.dart';
|
||||
|
||||
void main() {
|
||||
test('success exposes value and no error', () {
|
||||
const Result<int, String> result = Result.success(1);
|
||||
|
||||
expect(result.isSuccess, isTrue);
|
||||
expect(result.valueOrNull, 1);
|
||||
expect(result.errorOrNull, isNull);
|
||||
expect(result.when(success: (v) => 'ok $v', failure: (e) => e), 'ok 1');
|
||||
});
|
||||
|
||||
test('failure exposes error and no value', () {
|
||||
const Result<int, String> result = Result.failure('boom');
|
||||
|
||||
expect(result.isFailure, isTrue);
|
||||
expect(result.valueOrNull, isNull);
|
||||
expect(result.errorOrNull, 'boom');
|
||||
expect(result.when(success: (v) => 'ok', failure: (e) => e), 'boom');
|
||||
});
|
||||
}
|
||||