Delete apps/mobile/prototypes directory

This commit is contained in:
Achintha Isuru
2026-01-25 20:17:16 -05:00
committed by GitHub
parent 280cdcbc9f
commit d8fea02fcf
396 changed files with 0 additions and 59414 deletions

View File

@@ -1,45 +0,0 @@
# 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

View File

@@ -1,45 +0,0 @@
# 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: "b45fa18946ecc2d9b4009952c636ba7e2ffbb787"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: android
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: ios
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: linux
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: macos
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: web
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: windows
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
# 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'

View File

@@ -1,16 +0,0 @@
# client_app_mvp
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

View File

@@ -1,28 +0,0 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View File

@@ -1,14 +0,0 @@
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

View File

@@ -1,45 +0,0 @@
plugins {
id("com.android.application")
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
id("com.google.gms.google-services")
}
android {
namespace = "com.example.client_app_mvp"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.client_app_mvp"
// 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
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")
}
}
}
flutter {
source = "../.."
}

View File

@@ -1,68 +0,0 @@
{
"project_info": {
"project_number": "717206318340",
"project_id": "krow-apps",
"storage_bucket": "krow-apps.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:717206318340:android:b0bff06f9967d8678af451",
"android_client_info": {
"package_name": "com.example.client_app_mvp"
}
},
"oauth_client": [
{
"client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCXKJ5yME2a4FlrAzZA5LzSt97JwEwn9qE"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:717206318340:android:d3eac8c3774905e08af451",
"android_client_info": {
"package_name": "com.example.staff_app_mvp"
}
},
"oauth_client": [
{
"client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCXKJ5yME2a4FlrAzZA5LzSt97JwEwn9qE"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}

View File

@@ -1,7 +0,0 @@
<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>

View File

@@ -1,47 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="Krow Client App MVP"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
<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>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@@ -1,5 +0,0 @@
package com.example.client_app_mvp
import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity()

View File

@@ -1,12 +0,0 @@
<?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>

View File

@@ -1,12 +0,0 @@
<?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>

View File

@@ -1,18 +0,0 @@
<?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>

View File

@@ -1,18 +0,0 @@
<?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>

View File

@@ -1,7 +0,0 @@
<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>

View File

@@ -1,24 +0,0 @@
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)
}

View File

@@ -1,2 +0,0 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true

View File

@@ -1,5 +0,0 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip

View File

@@ -1,27 +0,0 @@
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 "8.11.1" apply false
id("org.jetbrains.kotlin.android") version "2.2.20" apply false
id("com.google.gms.google-services") version "4.4.2" apply false
}
include(":app")

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

View File

@@ -1,34 +0,0 @@
**/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

View File

@@ -1,26 +0,0 @@
<?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>
<key>MinimumOSVersion</key>
<string>13.0</string>
</dict>
</plist>

View File

@@ -1,2 +0,0 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View File

@@ -1,2 +0,0 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

View File

@@ -1,43 +0,0 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end

View File

@@ -1,728 +0,0 @@
// !$*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 */; };
59A242D46CCC2B41A5A2C541 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD5AC650E4AD66A8AC1F1833 /* Pods_Runner.framework */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
76284B4CE5310321526352FD /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93FA99887D920E203CE2CDBC /* Pods_RunnerTests.framework */; };
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>"; };
50734491C8F4091FC4215298 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
6B4A6F53289C89C876C48A46 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
6D7BF6C00FBA636F126BBD33 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
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>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
93FA99887D920E203CE2CDBC /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
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>"; };
B701E0489709E5092E6A038C /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
BD5AC650E4AD66A8AC1F1833 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C4A6F6F8B46779D11DEEA3E7 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
F4AA850DEDC9D26C59B80E5F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
59A242D46CCC2B41A5A2C541 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F86625E7251DC5F34D5E3557 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
76284B4CE5310321526352FD /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
09914133214C1E3120D3D9EE /* Frameworks */ = {
isa = PBXGroup;
children = (
BD5AC650E4AD66A8AC1F1833 /* Pods_Runner.framework */,
93FA99887D920E203CE2CDBC /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
172627A77D8C2EB68F8D116E /* Pods */ = {
isa = PBXGroup;
children = (
F4AA850DEDC9D26C59B80E5F /* Pods-Runner.debug.xcconfig */,
6B4A6F53289C89C876C48A46 /* Pods-Runner.release.xcconfig */,
C4A6F6F8B46779D11DEEA3E7 /* Pods-Runner.profile.xcconfig */,
6D7BF6C00FBA636F126BBD33 /* Pods-RunnerTests.debug.xcconfig */,
50734491C8F4091FC4215298 /* Pods-RunnerTests.release.xcconfig */,
B701E0489709E5092E6A038C /* Pods-RunnerTests.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
331C8082294A63A400263BE5 /* RunnerTests */ = {
isa = PBXGroup;
children = (
331C807B294A618700263BE5 /* RunnerTests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
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 */,
172627A77D8C2EB68F8D116E /* Pods */,
09914133214C1E3120D3D9EE /* Frameworks */,
);
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 */,
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 = (
AE1567838935F36DA48C52B1 /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
F86625E7251DC5F34D5E3557 /* Frameworks */,
);
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 = (
A06687346091B014AF063603 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
4F27457BBFA344CA19B6713C /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
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;
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";
};
4F27457BBFA344CA19B6713C /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
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";
};
A06687346091B014AF063603 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
AE1567838935F36DA48C52B1 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* 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 */,
);
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 = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
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)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp;
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;
baseConfigurationReference = 6D7BF6C00FBA636F126BBD33 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp.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;
baseConfigurationReference = 50734491C8F4091FC4215298 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp.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;
baseConfigurationReference = B701E0489709E5092E6A038C /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp.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 = AppIcon;
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 = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
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 = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
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)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp;
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)";
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.clientAppMvp;
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 */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@@ -1,8 +0,0 @@
<?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>

View File

@@ -1,8 +0,0 @@
<?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>

View File

@@ -1,101 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<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>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -1,8 +0,0 @@
<?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>

View File

@@ -1,8 +0,0 @@
<?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>

View File

@@ -1,13 +0,0 @@
import Flutter
import UIKit
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}

View File

@@ -1 +0,0 @@
{"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":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"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":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@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"}}

View File

@@ -1,23 +0,0 @@
{
"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"
}
}

View File

@@ -1,5 +0,0 @@
# 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.

View File

@@ -1,37 +0,0 @@
<?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>

View File

@@ -1,26 +0,0 @@
<?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>

View File

@@ -1,49 +0,0 @@
<?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>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Client App Mvp</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>client_app_mvp</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>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>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

View File

@@ -1 +0,0 @@
#import "GeneratedPluginRegistrant.h"

View File

@@ -1,12 +0,0 @@
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.
}
}

View File

@@ -1,9 +0,0 @@
{
"description": "A set of guides for interacting with the generated firebase dataconnect sdk",
"mcpServers": {
"firebase": {
"command": "npx",
"args": ["-y", "firebase-tools@latest", "experimental:mcp"]
}
}
}

View File

@@ -1,15 +0,0 @@
# Setup
This guide will walk you through setting up your environment to use the Firebase Data Connect SDK. Mostly using
documentation listed [here](https://firebase.google.com/docs/flutter/setup?platform=ios#install-cli-tools).
1. Make sure you have the latest Firebase CLI tools installed. Follow the instructions [here](https://firebase.google.com/docs/cli#setup_update_cli) to install.
2. Log into your Firebase account:
```sh
firebase login
```
3. Install the FlutterFire CLI by running the following command from any directory:
```sh
dart pub global activate flutterfire_cli
```
4. Make sure the user has initialized Firebase already based on the instructions [here](https://firebase.google.com/docs/flutter/setup?platform=ios#initialize-firebase).

View File

@@ -1,31 +0,0 @@
# Basic Usage
```dart
ExampleConnector.instance.CreateMovie(createMovieVariables).execute();
ExampleConnector.instance.UpsertUser(upsertUserVariables).execute();
ExampleConnector.instance.AddReview(addReviewVariables).execute();
ExampleConnector.instance.DeleteReview(deleteReviewVariables).execute();
ExampleConnector.instance.ListMovies().execute();
ExampleConnector.instance.ListUsers().execute();
ExampleConnector.instance.ListUserReviews().execute();
ExampleConnector.instance.GetMovieById(getMovieByIdVariables).execute();
ExampleConnector.instance.SearchMovie(searchMovieVariables).execute();
```
## Optional Fields
Some operations may have optional fields. In these cases, the Flutter SDK exposes a builder method, and will have to be set separately.
Optional fields can be discovered based on classes that have `Optional` object types.
This is an example of a mutation with an optional field:
```dart
await ExampleConnector.instance.SearchMovie({ ... })
.titleInput(...)
.execute();
```
Note: the above example is a mutation, but the same logic applies to query operations as well. Additionally, `createMovie` is an example, and may not be available to the user.

View File

@@ -1,446 +0,0 @@
# dataconnect_generated SDK
## Installation
```sh
flutter pub get firebase_data_connect
flutterfire configure
```
For more information, see [Flutter for Firebase installation documentation](https://firebase.google.com/docs/data-connect/flutter-sdk#use-core).
## Data Connect instance
Each connector creates a static class, with an instance of the `DataConnect` class that can be used to connect to your Data Connect backend and call operations.
### Connecting to the emulator
```dart
String host = 'localhost'; // or your host name
int port = 9399; // or your port number
ExampleConnector.instance.dataConnect.useDataConnectEmulator(host, port);
```
You can also call queries and mutations by using the connector class.
## Queries
### ListMovies
#### Required Arguments
```dart
// No required arguments
ExampleConnector.instance.listMovies().execute();
```
#### Return Type
`execute()` returns a `QueryResult<ListMoviesData, void>`
```dart
/// Result of an Operation Request (query/mutation).
class OperationResult<Data, Variables> {
OperationResult(this.dataConnect, this.data, this.ref);
Data data;
OperationRef<Data, Variables> ref;
FirebaseDataConnect dataConnect;
}
/// Result of a query request. Created to hold extra variables in the future.
class QueryResult<Data, Variables> extends OperationResult<Data, Variables> {
QueryResult(super.dataConnect, super.data, super.ref);
}
final result = await ExampleConnector.instance.listMovies();
ListMoviesData data = result.data;
final ref = result.ref;
```
#### Getting the Ref
Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation.
An example of how to use the `Ref` object is shown below:
```dart
final ref = ExampleConnector.instance.listMovies().ref();
ref.execute();
ref.subscribe(...);
```
### ListUsers
#### Required Arguments
```dart
// No required arguments
ExampleConnector.instance.listUsers().execute();
```
#### Return Type
`execute()` returns a `QueryResult<ListUsersData, void>`
```dart
/// Result of an Operation Request (query/mutation).
class OperationResult<Data, Variables> {
OperationResult(this.dataConnect, this.data, this.ref);
Data data;
OperationRef<Data, Variables> ref;
FirebaseDataConnect dataConnect;
}
/// Result of a query request. Created to hold extra variables in the future.
class QueryResult<Data, Variables> extends OperationResult<Data, Variables> {
QueryResult(super.dataConnect, super.data, super.ref);
}
final result = await ExampleConnector.instance.listUsers();
ListUsersData data = result.data;
final ref = result.ref;
```
#### Getting the Ref
Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation.
An example of how to use the `Ref` object is shown below:
```dart
final ref = ExampleConnector.instance.listUsers().ref();
ref.execute();
ref.subscribe(...);
```
### ListUserReviews
#### Required Arguments
```dart
// No required arguments
ExampleConnector.instance.listUserReviews().execute();
```
#### Return Type
`execute()` returns a `QueryResult<ListUserReviewsData, void>`
```dart
/// Result of an Operation Request (query/mutation).
class OperationResult<Data, Variables> {
OperationResult(this.dataConnect, this.data, this.ref);
Data data;
OperationRef<Data, Variables> ref;
FirebaseDataConnect dataConnect;
}
/// Result of a query request. Created to hold extra variables in the future.
class QueryResult<Data, Variables> extends OperationResult<Data, Variables> {
QueryResult(super.dataConnect, super.data, super.ref);
}
final result = await ExampleConnector.instance.listUserReviews();
ListUserReviewsData data = result.data;
final ref = result.ref;
```
#### Getting the Ref
Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation.
An example of how to use the `Ref` object is shown below:
```dart
final ref = ExampleConnector.instance.listUserReviews().ref();
ref.execute();
ref.subscribe(...);
```
### GetMovieById
#### Required Arguments
```dart
String id = ...;
ExampleConnector.instance.getMovieById(
id: id,
).execute();
```
#### Return Type
`execute()` returns a `QueryResult<GetMovieByIdData, GetMovieByIdVariables>`
```dart
/// Result of an Operation Request (query/mutation).
class OperationResult<Data, Variables> {
OperationResult(this.dataConnect, this.data, this.ref);
Data data;
OperationRef<Data, Variables> ref;
FirebaseDataConnect dataConnect;
}
/// Result of a query request. Created to hold extra variables in the future.
class QueryResult<Data, Variables> extends OperationResult<Data, Variables> {
QueryResult(super.dataConnect, super.data, super.ref);
}
final result = await ExampleConnector.instance.getMovieById(
id: id,
);
GetMovieByIdData data = result.data;
final ref = result.ref;
```
#### Getting the Ref
Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation.
An example of how to use the `Ref` object is shown below:
```dart
String id = ...;
final ref = ExampleConnector.instance.getMovieById(
id: id,
).ref();
ref.execute();
ref.subscribe(...);
```
### SearchMovie
#### Required Arguments
```dart
// No required arguments
ExampleConnector.instance.searchMovie().execute();
```
#### Optional Arguments
We return a builder for each query. For SearchMovie, we created `SearchMovieBuilder`. For queries and mutations with optional parameters, we return a builder class.
The builder pattern allows Data Connect to distinguish between fields that haven't been set and fields that have been set to null. A field can be set by calling its respective setter method like below:
```dart
class SearchMovieVariablesBuilder {
...
SearchMovieVariablesBuilder titleInput(String? t) {
_titleInput.value = t;
return this;
}
SearchMovieVariablesBuilder genre(String? t) {
_genre.value = t;
return this;
}
...
}
ExampleConnector.instance.searchMovie()
.titleInput(titleInput)
.genre(genre)
.execute();
```
#### Return Type
`execute()` returns a `QueryResult<SearchMovieData, SearchMovieVariables>`
```dart
/// Result of an Operation Request (query/mutation).
class OperationResult<Data, Variables> {
OperationResult(this.dataConnect, this.data, this.ref);
Data data;
OperationRef<Data, Variables> ref;
FirebaseDataConnect dataConnect;
}
/// Result of a query request. Created to hold extra variables in the future.
class QueryResult<Data, Variables> extends OperationResult<Data, Variables> {
QueryResult(super.dataConnect, super.data, super.ref);
}
final result = await ExampleConnector.instance.searchMovie();
SearchMovieData data = result.data;
final ref = result.ref;
```
#### Getting the Ref
Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation.
An example of how to use the `Ref` object is shown below:
```dart
final ref = ExampleConnector.instance.searchMovie().ref();
ref.execute();
ref.subscribe(...);
```
## Mutations
### CreateMovie
#### Required Arguments
```dart
String title = ...;
String genre = ...;
String imageUrl = ...;
ExampleConnector.instance.createMovie(
title: title,
genre: genre,
imageUrl: imageUrl,
).execute();
```
#### Return Type
`execute()` returns a `OperationResult<CreateMovieData, CreateMovieVariables>`
```dart
/// Result of an Operation Request (query/mutation).
class OperationResult<Data, Variables> {
OperationResult(this.dataConnect, this.data, this.ref);
Data data;
OperationRef<Data, Variables> ref;
FirebaseDataConnect dataConnect;
}
final result = await ExampleConnector.instance.createMovie(
title: title,
genre: genre,
imageUrl: imageUrl,
);
CreateMovieData data = result.data;
final ref = result.ref;
```
#### Getting the Ref
Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation.
An example of how to use the `Ref` object is shown below:
```dart
String title = ...;
String genre = ...;
String imageUrl = ...;
final ref = ExampleConnector.instance.createMovie(
title: title,
genre: genre,
imageUrl: imageUrl,
).ref();
ref.execute();
```
### UpsertUser
#### Required Arguments
```dart
String username = ...;
ExampleConnector.instance.upsertUser(
username: username,
).execute();
```
#### Return Type
`execute()` returns a `OperationResult<UpsertUserData, UpsertUserVariables>`
```dart
/// Result of an Operation Request (query/mutation).
class OperationResult<Data, Variables> {
OperationResult(this.dataConnect, this.data, this.ref);
Data data;
OperationRef<Data, Variables> ref;
FirebaseDataConnect dataConnect;
}
final result = await ExampleConnector.instance.upsertUser(
username: username,
);
UpsertUserData data = result.data;
final ref = result.ref;
```
#### Getting the Ref
Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation.
An example of how to use the `Ref` object is shown below:
```dart
String username = ...;
final ref = ExampleConnector.instance.upsertUser(
username: username,
).ref();
ref.execute();
```
### AddReview
#### Required Arguments
```dart
String movieId = ...;
int rating = ...;
String reviewText = ...;
ExampleConnector.instance.addReview(
movieId: movieId,
rating: rating,
reviewText: reviewText,
).execute();
```
#### Return Type
`execute()` returns a `OperationResult<AddReviewData, AddReviewVariables>`
```dart
/// Result of an Operation Request (query/mutation).
class OperationResult<Data, Variables> {
OperationResult(this.dataConnect, this.data, this.ref);
Data data;
OperationRef<Data, Variables> ref;
FirebaseDataConnect dataConnect;
}
final result = await ExampleConnector.instance.addReview(
movieId: movieId,
rating: rating,
reviewText: reviewText,
);
AddReviewData data = result.data;
final ref = result.ref;
```
#### Getting the Ref
Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation.
An example of how to use the `Ref` object is shown below:
```dart
String movieId = ...;
int rating = ...;
String reviewText = ...;
final ref = ExampleConnector.instance.addReview(
movieId: movieId,
rating: rating,
reviewText: reviewText,
).ref();
ref.execute();
```
### DeleteReview
#### Required Arguments
```dart
String movieId = ...;
ExampleConnector.instance.deleteReview(
movieId: movieId,
).execute();
```
#### Return Type
`execute()` returns a `OperationResult<DeleteReviewData, DeleteReviewVariables>`
```dart
/// Result of an Operation Request (query/mutation).
class OperationResult<Data, Variables> {
OperationResult(this.dataConnect, this.data, this.ref);
Data data;
OperationRef<Data, Variables> ref;
FirebaseDataConnect dataConnect;
}
final result = await ExampleConnector.instance.deleteReview(
movieId: movieId,
);
DeleteReviewData data = result.data;
final ref = result.ref;
```
#### Getting the Ref
Each builder returns an `execute` function, which is a helper function that creates a `Ref` object, and executes the underlying operation.
An example of how to use the `Ref` object is shown below:
```dart
String movieId = ...;
final ref = ExampleConnector.instance.deleteReview(
movieId: movieId,
).ref();
ref.execute();
```

View File

@@ -1,139 +0,0 @@
part of 'generated.dart';
class AddReviewVariablesBuilder {
String movieId;
int rating;
String reviewText;
final FirebaseDataConnect _dataConnect;
AddReviewVariablesBuilder(this._dataConnect, {required this.movieId,required this.rating,required this.reviewText,});
Deserializer<AddReviewData> dataDeserializer = (dynamic json) => AddReviewData.fromJson(jsonDecode(json));
Serializer<AddReviewVariables> varsSerializer = (AddReviewVariables vars) => jsonEncode(vars.toJson());
Future<OperationResult<AddReviewData, AddReviewVariables>> execute() {
return ref().execute();
}
MutationRef<AddReviewData, AddReviewVariables> ref() {
AddReviewVariables vars= AddReviewVariables(movieId: movieId,rating: rating,reviewText: reviewText,);
return _dataConnect.mutation("AddReview", dataDeserializer, varsSerializer, vars);
}
}
@immutable
class AddReviewReviewUpsert {
final String userId;
final String movieId;
AddReviewReviewUpsert.fromJson(dynamic json):
userId = nativeFromJson<String>(json['userId']),
movieId = nativeFromJson<String>(json['movieId']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final AddReviewReviewUpsert otherTyped = other as AddReviewReviewUpsert;
return userId == otherTyped.userId &&
movieId == otherTyped.movieId;
}
@override
int get hashCode => Object.hashAll([userId.hashCode, movieId.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['userId'] = nativeToJson<String>(userId);
json['movieId'] = nativeToJson<String>(movieId);
return json;
}
AddReviewReviewUpsert({
required this.userId,
required this.movieId,
});
}
@immutable
class AddReviewData {
final AddReviewReviewUpsert review_upsert;
AddReviewData.fromJson(dynamic json):
review_upsert = AddReviewReviewUpsert.fromJson(json['review_upsert']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final AddReviewData otherTyped = other as AddReviewData;
return review_upsert == otherTyped.review_upsert;
}
@override
int get hashCode => review_upsert.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['review_upsert'] = review_upsert.toJson();
return json;
}
AddReviewData({
required this.review_upsert,
});
}
@immutable
class AddReviewVariables {
final String movieId;
final int rating;
final String reviewText;
@Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
AddReviewVariables.fromJson(Map<String, dynamic> json):
movieId = nativeFromJson<String>(json['movieId']),
rating = nativeFromJson<int>(json['rating']),
reviewText = nativeFromJson<String>(json['reviewText']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final AddReviewVariables otherTyped = other as AddReviewVariables;
return movieId == otherTyped.movieId &&
rating == otherTyped.rating &&
reviewText == otherTyped.reviewText;
}
@override
int get hashCode => Object.hashAll([movieId.hashCode, rating.hashCode, reviewText.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['movieId'] = nativeToJson<String>(movieId);
json['rating'] = nativeToJson<int>(rating);
json['reviewText'] = nativeToJson<String>(reviewText);
return json;
}
AddReviewVariables({
required this.movieId,
required this.rating,
required this.reviewText,
});
}

View File

@@ -1,134 +0,0 @@
part of 'generated.dart';
class CreateMovieVariablesBuilder {
String title;
String genre;
String imageUrl;
final FirebaseDataConnect _dataConnect;
CreateMovieVariablesBuilder(this._dataConnect, {required this.title,required this.genre,required this.imageUrl,});
Deserializer<CreateMovieData> dataDeserializer = (dynamic json) => CreateMovieData.fromJson(jsonDecode(json));
Serializer<CreateMovieVariables> varsSerializer = (CreateMovieVariables vars) => jsonEncode(vars.toJson());
Future<OperationResult<CreateMovieData, CreateMovieVariables>> execute() {
return ref().execute();
}
MutationRef<CreateMovieData, CreateMovieVariables> ref() {
CreateMovieVariables vars= CreateMovieVariables(title: title,genre: genre,imageUrl: imageUrl,);
return _dataConnect.mutation("CreateMovie", dataDeserializer, varsSerializer, vars);
}
}
@immutable
class CreateMovieMovieInsert {
final String id;
CreateMovieMovieInsert.fromJson(dynamic json):
id = nativeFromJson<String>(json['id']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final CreateMovieMovieInsert otherTyped = other as CreateMovieMovieInsert;
return id == otherTyped.id;
}
@override
int get hashCode => id.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['id'] = nativeToJson<String>(id);
return json;
}
CreateMovieMovieInsert({
required this.id,
});
}
@immutable
class CreateMovieData {
final CreateMovieMovieInsert movie_insert;
CreateMovieData.fromJson(dynamic json):
movie_insert = CreateMovieMovieInsert.fromJson(json['movie_insert']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final CreateMovieData otherTyped = other as CreateMovieData;
return movie_insert == otherTyped.movie_insert;
}
@override
int get hashCode => movie_insert.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['movie_insert'] = movie_insert.toJson();
return json;
}
CreateMovieData({
required this.movie_insert,
});
}
@immutable
class CreateMovieVariables {
final String title;
final String genre;
final String imageUrl;
@Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
CreateMovieVariables.fromJson(Map<String, dynamic> json):
title = nativeFromJson<String>(json['title']),
genre = nativeFromJson<String>(json['genre']),
imageUrl = nativeFromJson<String>(json['imageUrl']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final CreateMovieVariables otherTyped = other as CreateMovieVariables;
return title == otherTyped.title &&
genre == otherTyped.genre &&
imageUrl == otherTyped.imageUrl;
}
@override
int get hashCode => Object.hashAll([title.hashCode, genre.hashCode, imageUrl.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['title'] = nativeToJson<String>(title);
json['genre'] = nativeToJson<String>(genre);
json['imageUrl'] = nativeToJson<String>(imageUrl);
return json;
}
CreateMovieVariables({
required this.title,
required this.genre,
required this.imageUrl,
});
}

View File

@@ -1,129 +0,0 @@
part of 'generated.dart';
class DeleteReviewVariablesBuilder {
String movieId;
final FirebaseDataConnect _dataConnect;
DeleteReviewVariablesBuilder(this._dataConnect, {required this.movieId,});
Deserializer<DeleteReviewData> dataDeserializer = (dynamic json) => DeleteReviewData.fromJson(jsonDecode(json));
Serializer<DeleteReviewVariables> varsSerializer = (DeleteReviewVariables vars) => jsonEncode(vars.toJson());
Future<OperationResult<DeleteReviewData, DeleteReviewVariables>> execute() {
return ref().execute();
}
MutationRef<DeleteReviewData, DeleteReviewVariables> ref() {
DeleteReviewVariables vars= DeleteReviewVariables(movieId: movieId,);
return _dataConnect.mutation("DeleteReview", dataDeserializer, varsSerializer, vars);
}
}
@immutable
class DeleteReviewReviewDelete {
final String userId;
final String movieId;
DeleteReviewReviewDelete.fromJson(dynamic json):
userId = nativeFromJson<String>(json['userId']),
movieId = nativeFromJson<String>(json['movieId']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final DeleteReviewReviewDelete otherTyped = other as DeleteReviewReviewDelete;
return userId == otherTyped.userId &&
movieId == otherTyped.movieId;
}
@override
int get hashCode => Object.hashAll([userId.hashCode, movieId.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['userId'] = nativeToJson<String>(userId);
json['movieId'] = nativeToJson<String>(movieId);
return json;
}
DeleteReviewReviewDelete({
required this.userId,
required this.movieId,
});
}
@immutable
class DeleteReviewData {
final DeleteReviewReviewDelete? review_delete;
DeleteReviewData.fromJson(dynamic json):
review_delete = json['review_delete'] == null ? null : DeleteReviewReviewDelete.fromJson(json['review_delete']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final DeleteReviewData otherTyped = other as DeleteReviewData;
return review_delete == otherTyped.review_delete;
}
@override
int get hashCode => review_delete.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
if (review_delete != null) {
json['review_delete'] = review_delete!.toJson();
}
return json;
}
DeleteReviewData({
this.review_delete,
});
}
@immutable
class DeleteReviewVariables {
final String movieId;
@Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
DeleteReviewVariables.fromJson(Map<String, dynamic> json):
movieId = nativeFromJson<String>(json['movieId']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final DeleteReviewVariables otherTyped = other as DeleteReviewVariables;
return movieId == otherTyped.movieId;
}
@override
int get hashCode => movieId.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['movieId'] = nativeToJson<String>(movieId);
return json;
}
DeleteReviewVariables({
required this.movieId,
});
}

View File

@@ -1,93 +0,0 @@
library dataconnect_generated;
import 'package:firebase_data_connect/firebase_data_connect.dart';
import 'package:flutter/foundation.dart';
import 'dart:convert';
part 'create_movie.dart';
part 'upsert_user.dart';
part 'add_review.dart';
part 'delete_review.dart';
part 'list_movies.dart';
part 'list_users.dart';
part 'list_user_reviews.dart';
part 'get_movie_by_id.dart';
part 'search_movie.dart';
class ExampleConnector {
CreateMovieVariablesBuilder createMovie ({required String title, required String genre, required String imageUrl, }) {
return CreateMovieVariablesBuilder(dataConnect, title: title,genre: genre,imageUrl: imageUrl,);
}
UpsertUserVariablesBuilder upsertUser ({required String username, }) {
return UpsertUserVariablesBuilder(dataConnect, username: username,);
}
AddReviewVariablesBuilder addReview ({required String movieId, required int rating, required String reviewText, }) {
return AddReviewVariablesBuilder(dataConnect, movieId: movieId,rating: rating,reviewText: reviewText,);
}
DeleteReviewVariablesBuilder deleteReview ({required String movieId, }) {
return DeleteReviewVariablesBuilder(dataConnect, movieId: movieId,);
}
ListMoviesVariablesBuilder listMovies () {
return ListMoviesVariablesBuilder(dataConnect, );
}
ListUsersVariablesBuilder listUsers () {
return ListUsersVariablesBuilder(dataConnect, );
}
ListUserReviewsVariablesBuilder listUserReviews () {
return ListUserReviewsVariablesBuilder(dataConnect, );
}
GetMovieByIdVariablesBuilder getMovieById ({required String id, }) {
return GetMovieByIdVariablesBuilder(dataConnect, id: id,);
}
SearchMovieVariablesBuilder searchMovie () {
return SearchMovieVariablesBuilder(dataConnect, );
}
static ConnectorConfig connectorConfig = ConnectorConfig(
'us-central1',
'example',
'client-krow-poc',
);
ExampleConnector({required this.dataConnect});
static ExampleConnector get instance {
return ExampleConnector(
dataConnect: FirebaseDataConnect.instanceFor(
connectorConfig: connectorConfig,
sdkType: CallerSDKType.generated));
}
FirebaseDataConnect dataConnect;
}

View File

@@ -1,297 +0,0 @@
part of 'generated.dart';
class GetMovieByIdVariablesBuilder {
String id;
final FirebaseDataConnect _dataConnect;
GetMovieByIdVariablesBuilder(this._dataConnect, {required this.id,});
Deserializer<GetMovieByIdData> dataDeserializer = (dynamic json) => GetMovieByIdData.fromJson(jsonDecode(json));
Serializer<GetMovieByIdVariables> varsSerializer = (GetMovieByIdVariables vars) => jsonEncode(vars.toJson());
Future<QueryResult<GetMovieByIdData, GetMovieByIdVariables>> execute() {
return ref().execute();
}
QueryRef<GetMovieByIdData, GetMovieByIdVariables> ref() {
GetMovieByIdVariables vars= GetMovieByIdVariables(id: id,);
return _dataConnect.query("GetMovieById", dataDeserializer, varsSerializer, vars);
}
}
@immutable
class GetMovieByIdMovie {
final String id;
final String title;
final String imageUrl;
final String? genre;
final GetMovieByIdMovieMetadata? metadata;
final List<GetMovieByIdMovieReviews> reviews;
GetMovieByIdMovie.fromJson(dynamic json):
id = nativeFromJson<String>(json['id']),
title = nativeFromJson<String>(json['title']),
imageUrl = nativeFromJson<String>(json['imageUrl']),
genre = json['genre'] == null ? null : nativeFromJson<String>(json['genre']),
metadata = json['metadata'] == null ? null : GetMovieByIdMovieMetadata.fromJson(json['metadata']),
reviews = (json['reviews'] as List<dynamic>)
.map((e) => GetMovieByIdMovieReviews.fromJson(e))
.toList();
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final GetMovieByIdMovie otherTyped = other as GetMovieByIdMovie;
return id == otherTyped.id &&
title == otherTyped.title &&
imageUrl == otherTyped.imageUrl &&
genre == otherTyped.genre &&
metadata == otherTyped.metadata &&
reviews == otherTyped.reviews;
}
@override
int get hashCode => Object.hashAll([id.hashCode, title.hashCode, imageUrl.hashCode, genre.hashCode, metadata.hashCode, reviews.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['id'] = nativeToJson<String>(id);
json['title'] = nativeToJson<String>(title);
json['imageUrl'] = nativeToJson<String>(imageUrl);
if (genre != null) {
json['genre'] = nativeToJson<String?>(genre);
}
if (metadata != null) {
json['metadata'] = metadata!.toJson();
}
json['reviews'] = reviews.map((e) => e.toJson()).toList();
return json;
}
GetMovieByIdMovie({
required this.id,
required this.title,
required this.imageUrl,
this.genre,
this.metadata,
required this.reviews,
});
}
@immutable
class GetMovieByIdMovieMetadata {
final double? rating;
final int? releaseYear;
final String? description;
GetMovieByIdMovieMetadata.fromJson(dynamic json):
rating = json['rating'] == null ? null : nativeFromJson<double>(json['rating']),
releaseYear = json['releaseYear'] == null ? null : nativeFromJson<int>(json['releaseYear']),
description = json['description'] == null ? null : nativeFromJson<String>(json['description']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final GetMovieByIdMovieMetadata otherTyped = other as GetMovieByIdMovieMetadata;
return rating == otherTyped.rating &&
releaseYear == otherTyped.releaseYear &&
description == otherTyped.description;
}
@override
int get hashCode => Object.hashAll([rating.hashCode, releaseYear.hashCode, description.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
if (rating != null) {
json['rating'] = nativeToJson<double?>(rating);
}
if (releaseYear != null) {
json['releaseYear'] = nativeToJson<int?>(releaseYear);
}
if (description != null) {
json['description'] = nativeToJson<String?>(description);
}
return json;
}
GetMovieByIdMovieMetadata({
this.rating,
this.releaseYear,
this.description,
});
}
@immutable
class GetMovieByIdMovieReviews {
final String? reviewText;
final DateTime reviewDate;
final int? rating;
final GetMovieByIdMovieReviewsUser user;
GetMovieByIdMovieReviews.fromJson(dynamic json):
reviewText = json['reviewText'] == null ? null : nativeFromJson<String>(json['reviewText']),
reviewDate = nativeFromJson<DateTime>(json['reviewDate']),
rating = json['rating'] == null ? null : nativeFromJson<int>(json['rating']),
user = GetMovieByIdMovieReviewsUser.fromJson(json['user']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final GetMovieByIdMovieReviews otherTyped = other as GetMovieByIdMovieReviews;
return reviewText == otherTyped.reviewText &&
reviewDate == otherTyped.reviewDate &&
rating == otherTyped.rating &&
user == otherTyped.user;
}
@override
int get hashCode => Object.hashAll([reviewText.hashCode, reviewDate.hashCode, rating.hashCode, user.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
if (reviewText != null) {
json['reviewText'] = nativeToJson<String?>(reviewText);
}
json['reviewDate'] = nativeToJson<DateTime>(reviewDate);
if (rating != null) {
json['rating'] = nativeToJson<int?>(rating);
}
json['user'] = user.toJson();
return json;
}
GetMovieByIdMovieReviews({
this.reviewText,
required this.reviewDate,
this.rating,
required this.user,
});
}
@immutable
class GetMovieByIdMovieReviewsUser {
final String id;
final String username;
GetMovieByIdMovieReviewsUser.fromJson(dynamic json):
id = nativeFromJson<String>(json['id']),
username = nativeFromJson<String>(json['username']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final GetMovieByIdMovieReviewsUser otherTyped = other as GetMovieByIdMovieReviewsUser;
return id == otherTyped.id &&
username == otherTyped.username;
}
@override
int get hashCode => Object.hashAll([id.hashCode, username.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['id'] = nativeToJson<String>(id);
json['username'] = nativeToJson<String>(username);
return json;
}
GetMovieByIdMovieReviewsUser({
required this.id,
required this.username,
});
}
@immutable
class GetMovieByIdData {
final GetMovieByIdMovie? movie;
GetMovieByIdData.fromJson(dynamic json):
movie = json['movie'] == null ? null : GetMovieByIdMovie.fromJson(json['movie']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final GetMovieByIdData otherTyped = other as GetMovieByIdData;
return movie == otherTyped.movie;
}
@override
int get hashCode => movie.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
if (movie != null) {
json['movie'] = movie!.toJson();
}
return json;
}
GetMovieByIdData({
this.movie,
});
}
@immutable
class GetMovieByIdVariables {
final String id;
@Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
GetMovieByIdVariables.fromJson(Map<String, dynamic> json):
id = nativeFromJson<String>(json['id']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final GetMovieByIdVariables otherTyped = other as GetMovieByIdVariables;
return id == otherTyped.id;
}
@override
int get hashCode => id.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['id'] = nativeToJson<String>(id);
return json;
}
GetMovieByIdVariables({
required this.id,
});
}

View File

@@ -1,105 +0,0 @@
part of 'generated.dart';
class ListMoviesVariablesBuilder {
final FirebaseDataConnect _dataConnect;
ListMoviesVariablesBuilder(this._dataConnect, );
Deserializer<ListMoviesData> dataDeserializer = (dynamic json) => ListMoviesData.fromJson(jsonDecode(json));
Future<QueryResult<ListMoviesData, void>> execute() {
return ref().execute();
}
QueryRef<ListMoviesData, void> ref() {
return _dataConnect.query("ListMovies", dataDeserializer, emptySerializer, null);
}
}
@immutable
class ListMoviesMovies {
final String id;
final String title;
final String imageUrl;
final String? genre;
ListMoviesMovies.fromJson(dynamic json):
id = nativeFromJson<String>(json['id']),
title = nativeFromJson<String>(json['title']),
imageUrl = nativeFromJson<String>(json['imageUrl']),
genre = json['genre'] == null ? null : nativeFromJson<String>(json['genre']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final ListMoviesMovies otherTyped = other as ListMoviesMovies;
return id == otherTyped.id &&
title == otherTyped.title &&
imageUrl == otherTyped.imageUrl &&
genre == otherTyped.genre;
}
@override
int get hashCode => Object.hashAll([id.hashCode, title.hashCode, imageUrl.hashCode, genre.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['id'] = nativeToJson<String>(id);
json['title'] = nativeToJson<String>(title);
json['imageUrl'] = nativeToJson<String>(imageUrl);
if (genre != null) {
json['genre'] = nativeToJson<String?>(genre);
}
return json;
}
ListMoviesMovies({
required this.id,
required this.title,
required this.imageUrl,
this.genre,
});
}
@immutable
class ListMoviesData {
final List<ListMoviesMovies> movies;
ListMoviesData.fromJson(dynamic json):
movies = (json['movies'] as List<dynamic>)
.map((e) => ListMoviesMovies.fromJson(e))
.toList();
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final ListMoviesData otherTyped = other as ListMoviesData;
return movies == otherTyped.movies;
}
@override
int get hashCode => movies.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['movies'] = movies.map((e) => e.toJson()).toList();
return json;
}
ListMoviesData({
required this.movies,
});
}

View File

@@ -1,192 +0,0 @@
part of 'generated.dart';
class ListUserReviewsVariablesBuilder {
final FirebaseDataConnect _dataConnect;
ListUserReviewsVariablesBuilder(this._dataConnect, );
Deserializer<ListUserReviewsData> dataDeserializer = (dynamic json) => ListUserReviewsData.fromJson(jsonDecode(json));
Future<QueryResult<ListUserReviewsData, void>> execute() {
return ref().execute();
}
QueryRef<ListUserReviewsData, void> ref() {
return _dataConnect.query("ListUserReviews", dataDeserializer, emptySerializer, null);
}
}
@immutable
class ListUserReviewsUser {
final String id;
final String username;
final List<ListUserReviewsUserReviews> reviews;
ListUserReviewsUser.fromJson(dynamic json):
id = nativeFromJson<String>(json['id']),
username = nativeFromJson<String>(json['username']),
reviews = (json['reviews'] as List<dynamic>)
.map((e) => ListUserReviewsUserReviews.fromJson(e))
.toList();
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final ListUserReviewsUser otherTyped = other as ListUserReviewsUser;
return id == otherTyped.id &&
username == otherTyped.username &&
reviews == otherTyped.reviews;
}
@override
int get hashCode => Object.hashAll([id.hashCode, username.hashCode, reviews.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['id'] = nativeToJson<String>(id);
json['username'] = nativeToJson<String>(username);
json['reviews'] = reviews.map((e) => e.toJson()).toList();
return json;
}
ListUserReviewsUser({
required this.id,
required this.username,
required this.reviews,
});
}
@immutable
class ListUserReviewsUserReviews {
final int? rating;
final DateTime reviewDate;
final String? reviewText;
final ListUserReviewsUserReviewsMovie movie;
ListUserReviewsUserReviews.fromJson(dynamic json):
rating = json['rating'] == null ? null : nativeFromJson<int>(json['rating']),
reviewDate = nativeFromJson<DateTime>(json['reviewDate']),
reviewText = json['reviewText'] == null ? null : nativeFromJson<String>(json['reviewText']),
movie = ListUserReviewsUserReviewsMovie.fromJson(json['movie']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final ListUserReviewsUserReviews otherTyped = other as ListUserReviewsUserReviews;
return rating == otherTyped.rating &&
reviewDate == otherTyped.reviewDate &&
reviewText == otherTyped.reviewText &&
movie == otherTyped.movie;
}
@override
int get hashCode => Object.hashAll([rating.hashCode, reviewDate.hashCode, reviewText.hashCode, movie.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
if (rating != null) {
json['rating'] = nativeToJson<int?>(rating);
}
json['reviewDate'] = nativeToJson<DateTime>(reviewDate);
if (reviewText != null) {
json['reviewText'] = nativeToJson<String?>(reviewText);
}
json['movie'] = movie.toJson();
return json;
}
ListUserReviewsUserReviews({
this.rating,
required this.reviewDate,
this.reviewText,
required this.movie,
});
}
@immutable
class ListUserReviewsUserReviewsMovie {
final String id;
final String title;
ListUserReviewsUserReviewsMovie.fromJson(dynamic json):
id = nativeFromJson<String>(json['id']),
title = nativeFromJson<String>(json['title']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final ListUserReviewsUserReviewsMovie otherTyped = other as ListUserReviewsUserReviewsMovie;
return id == otherTyped.id &&
title == otherTyped.title;
}
@override
int get hashCode => Object.hashAll([id.hashCode, title.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['id'] = nativeToJson<String>(id);
json['title'] = nativeToJson<String>(title);
return json;
}
ListUserReviewsUserReviewsMovie({
required this.id,
required this.title,
});
}
@immutable
class ListUserReviewsData {
final ListUserReviewsUser? user;
ListUserReviewsData.fromJson(dynamic json):
user = json['user'] == null ? null : ListUserReviewsUser.fromJson(json['user']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final ListUserReviewsData otherTyped = other as ListUserReviewsData;
return user == otherTyped.user;
}
@override
int get hashCode => user.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
if (user != null) {
json['user'] = user!.toJson();
}
return json;
}
ListUserReviewsData({
this.user,
});
}

View File

@@ -1,93 +0,0 @@
part of 'generated.dart';
class ListUsersVariablesBuilder {
final FirebaseDataConnect _dataConnect;
ListUsersVariablesBuilder(this._dataConnect, );
Deserializer<ListUsersData> dataDeserializer = (dynamic json) => ListUsersData.fromJson(jsonDecode(json));
Future<QueryResult<ListUsersData, void>> execute() {
return ref().execute();
}
QueryRef<ListUsersData, void> ref() {
return _dataConnect.query("ListUsers", dataDeserializer, emptySerializer, null);
}
}
@immutable
class ListUsersUsers {
final String id;
final String username;
ListUsersUsers.fromJson(dynamic json):
id = nativeFromJson<String>(json['id']),
username = nativeFromJson<String>(json['username']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final ListUsersUsers otherTyped = other as ListUsersUsers;
return id == otherTyped.id &&
username == otherTyped.username;
}
@override
int get hashCode => Object.hashAll([id.hashCode, username.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['id'] = nativeToJson<String>(id);
json['username'] = nativeToJson<String>(username);
return json;
}
ListUsersUsers({
required this.id,
required this.username,
});
}
@immutable
class ListUsersData {
final List<ListUsersUsers> users;
ListUsersData.fromJson(dynamic json):
users = (json['users'] as List<dynamic>)
.map((e) => ListUsersUsers.fromJson(e))
.toList();
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final ListUsersData otherTyped = other as ListUsersData;
return users == otherTyped.users;
}
@override
int get hashCode => users.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['users'] = users.map((e) => e.toJson()).toList();
return json;
}
ListUsersData({
required this.users,
});
}

View File

@@ -1,167 +0,0 @@
part of 'generated.dart';
class SearchMovieVariablesBuilder {
Optional<String> _titleInput = Optional.optional(nativeFromJson, nativeToJson);
Optional<String> _genre = Optional.optional(nativeFromJson, nativeToJson);
final FirebaseDataConnect _dataConnect;
SearchMovieVariablesBuilder titleInput(String? t) {
_titleInput.value = t;
return this;
}
SearchMovieVariablesBuilder genre(String? t) {
_genre.value = t;
return this;
}
SearchMovieVariablesBuilder(this._dataConnect, );
Deserializer<SearchMovieData> dataDeserializer = (dynamic json) => SearchMovieData.fromJson(jsonDecode(json));
Serializer<SearchMovieVariables> varsSerializer = (SearchMovieVariables vars) => jsonEncode(vars.toJson());
Future<QueryResult<SearchMovieData, SearchMovieVariables>> execute() {
return ref().execute();
}
QueryRef<SearchMovieData, SearchMovieVariables> ref() {
SearchMovieVariables vars= SearchMovieVariables(titleInput: _titleInput,genre: _genre,);
return _dataConnect.query("SearchMovie", dataDeserializer, varsSerializer, vars);
}
}
@immutable
class SearchMovieMovies {
final String id;
final String title;
final String? genre;
final String imageUrl;
SearchMovieMovies.fromJson(dynamic json):
id = nativeFromJson<String>(json['id']),
title = nativeFromJson<String>(json['title']),
genre = json['genre'] == null ? null : nativeFromJson<String>(json['genre']),
imageUrl = nativeFromJson<String>(json['imageUrl']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final SearchMovieMovies otherTyped = other as SearchMovieMovies;
return id == otherTyped.id &&
title == otherTyped.title &&
genre == otherTyped.genre &&
imageUrl == otherTyped.imageUrl;
}
@override
int get hashCode => Object.hashAll([id.hashCode, title.hashCode, genre.hashCode, imageUrl.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['id'] = nativeToJson<String>(id);
json['title'] = nativeToJson<String>(title);
if (genre != null) {
json['genre'] = nativeToJson<String?>(genre);
}
json['imageUrl'] = nativeToJson<String>(imageUrl);
return json;
}
SearchMovieMovies({
required this.id,
required this.title,
this.genre,
required this.imageUrl,
});
}
@immutable
class SearchMovieData {
final List<SearchMovieMovies> movies;
SearchMovieData.fromJson(dynamic json):
movies = (json['movies'] as List<dynamic>)
.map((e) => SearchMovieMovies.fromJson(e))
.toList();
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final SearchMovieData otherTyped = other as SearchMovieData;
return movies == otherTyped.movies;
}
@override
int get hashCode => movies.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['movies'] = movies.map((e) => e.toJson()).toList();
return json;
}
SearchMovieData({
required this.movies,
});
}
@immutable
class SearchMovieVariables {
late final Optional<String>titleInput;
late final Optional<String>genre;
@Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
SearchMovieVariables.fromJson(Map<String, dynamic> json) {
titleInput = Optional.optional(nativeFromJson, nativeToJson);
titleInput.value = json['titleInput'] == null ? null : nativeFromJson<String>(json['titleInput']);
genre = Optional.optional(nativeFromJson, nativeToJson);
genre.value = json['genre'] == null ? null : nativeFromJson<String>(json['genre']);
}
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final SearchMovieVariables otherTyped = other as SearchMovieVariables;
return titleInput == otherTyped.titleInput &&
genre == otherTyped.genre;
}
@override
int get hashCode => Object.hashAll([titleInput.hashCode, genre.hashCode]);
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
if(titleInput.state == OptionalState.set) {
json['titleInput'] = titleInput.toJson();
}
if(genre.state == OptionalState.set) {
json['genre'] = genre.toJson();
}
return json;
}
SearchMovieVariables({
required this.titleInput,
required this.genre,
});
}

View File

@@ -1,122 +0,0 @@
part of 'generated.dart';
class UpsertUserVariablesBuilder {
String username;
final FirebaseDataConnect _dataConnect;
UpsertUserVariablesBuilder(this._dataConnect, {required this.username,});
Deserializer<UpsertUserData> dataDeserializer = (dynamic json) => UpsertUserData.fromJson(jsonDecode(json));
Serializer<UpsertUserVariables> varsSerializer = (UpsertUserVariables vars) => jsonEncode(vars.toJson());
Future<OperationResult<UpsertUserData, UpsertUserVariables>> execute() {
return ref().execute();
}
MutationRef<UpsertUserData, UpsertUserVariables> ref() {
UpsertUserVariables vars= UpsertUserVariables(username: username,);
return _dataConnect.mutation("UpsertUser", dataDeserializer, varsSerializer, vars);
}
}
@immutable
class UpsertUserUserUpsert {
final String id;
UpsertUserUserUpsert.fromJson(dynamic json):
id = nativeFromJson<String>(json['id']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final UpsertUserUserUpsert otherTyped = other as UpsertUserUserUpsert;
return id == otherTyped.id;
}
@override
int get hashCode => id.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['id'] = nativeToJson<String>(id);
return json;
}
UpsertUserUserUpsert({
required this.id,
});
}
@immutable
class UpsertUserData {
final UpsertUserUserUpsert user_upsert;
UpsertUserData.fromJson(dynamic json):
user_upsert = UpsertUserUserUpsert.fromJson(json['user_upsert']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final UpsertUserData otherTyped = other as UpsertUserData;
return user_upsert == otherTyped.user_upsert;
}
@override
int get hashCode => user_upsert.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['user_upsert'] = user_upsert.toJson();
return json;
}
UpsertUserData({
required this.user_upsert,
});
}
@immutable
class UpsertUserVariables {
final String username;
@Deprecated('fromJson is deprecated for Variable classes as they are no longer required for deserialization.')
UpsertUserVariables.fromJson(Map<String, dynamic> json):
username = nativeFromJson<String>(json['username']);
@override
bool operator ==(Object other) {
if(identical(this, other)) {
return true;
}
if(other.runtimeType != runtimeType) {
return false;
}
final UpsertUserVariables otherTyped = other as UpsertUserVariables;
return username == otherTyped.username;
}
@override
int get hashCode => username.hashCode;
Map<String, dynamic> toJson() {
Map<String, dynamic> json = {};
json['username'] = nativeToJson<String>(username);
return json;
}
UpsertUserVariables({
required this.username,
});
}

View File

@@ -1,28 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'theme.dart';
import 'router.dart';
import 'widgets/web_mobile_frame.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
const app = AppRoot();
runApp(ProviderScope(child: kIsWeb ? const WebMobileFrame(child: app) : app));
}
class AppRoot extends ConsumerWidget {
const AppRoot({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return MaterialApp.router(
title: 'Krow Client App',
theme: AppTheme.lightTheme,
routerConfig: router,
debugShowCheckedModeBanner: false,
);
}
}

View File

@@ -1,165 +0,0 @@
import 'package:go_router/go_router.dart';
import 'screens/auth/client_get_started_screen.dart';
import 'screens/auth/client_sign_in_screen.dart';
import 'screens/auth/client_sign_up_screen.dart';
import 'screens/client/client_home_screen.dart';
import 'screens/client/client_workers_screen.dart';
import 'screens/client/client_timesheets_screen.dart';
import 'screens/client/client_shifts_screen.dart';
import 'screens/client/client_reports_screen.dart';
import 'screens/client/create_order_screen.dart';
import 'screens/client/client_settings_screen.dart';
import 'screens/client/client_billing_screen.dart';
import 'screens/client/client_coverage_screen.dart';
import 'screens/client/client_hubs_screen.dart';
import 'screens/client/verify_worker_attire_screen.dart';
import 'screens/client/reports/daily_ops_report_screen.dart';
import 'screens/client/reports/spend_report_screen.dart';
import 'screens/client/reports/forecast_report_screen.dart';
import 'screens/client/reports/performance_report_screen.dart';
import 'screens/client/reports/no_show_report_screen.dart';
import 'screens/client/reports/coverage_report_screen.dart';
import 'screens/client/create_order_pages/rapid_order_flow_page.dart';
import 'screens/client/create_order_pages/one_time_order_flow_page.dart';
import 'screens/client/create_order_pages/recurring_order_flow_page.dart';
import 'screens/client/create_order_pages/permanent_order_flow_page.dart';
import 'widgets/scaffold_with_nav_bar.dart';
final router = GoRouter(
initialLocation: '/client-get-started',
routes: [
GoRoute(
path: '/client-get-started',
builder: (context, state) => const ClientGetStartedScreen(),
),
GoRoute(
path: '/client-sign-in',
builder: (context, state) => const ClientSignInScreen(),
),
GoRoute(
path: '/client-sign-up',
builder: (context, state) => const ClientSignUpScreen(),
),
GoRoute(
path: '/create-order',
builder: (context, state) => const CreateOrderScreen(),
routes: [
GoRoute(
path: 'rapid',
builder: (context, state) => const RapidOrderFlowPage(),
),
GoRoute(
path: 'one-time',
builder: (context, state) => const OneTimeOrderFlowPage(),
),
GoRoute(
path: 'recurring',
builder: (context, state) => const RecurringOrderFlowPage(),
),
GoRoute(
path: 'permanent',
builder: (context, state) => const PermanentOrderFlowPage(),
),
],
),
GoRoute(
path: '/client-settings',
builder: (context, state) => const ClientSettingsScreen(),
),
GoRoute(
path: '/client-hubs',
builder: (context, state) => const ClientHubsScreen(),
),
GoRoute(
path: '/verify-worker-attire',
builder: (context, state) => const VerifyWorkerAttireScreen(),
),
// Report Routes
GoRoute(
path: '/daily-ops-report',
builder: (context, state) => const DailyOpsReportScreen(),
),
GoRoute(
path: '/spend-report',
builder: (context, state) => const SpendReportScreen(),
),
GoRoute(
path: '/forecast-report',
builder: (context, state) => const ForecastReportScreen(),
),
GoRoute(
path: '/performance-report',
builder: (context, state) => const PerformanceReportScreen(),
),
GoRoute(
path: '/no-show-report',
builder: (context, state) => const NoShowReportScreen(),
),
GoRoute(
path: '/coverage-report-detail',
builder: (context, state) => const CoverageReportScreen(),
),
// Moved Workers and Timesheets out of bottom nav, accessible as standalone routes
GoRoute(
path: '/client-workers',
builder: (context, state) => const ClientWorkersScreen(),
),
GoRoute(
path: '/client-timesheets',
builder: (context, state) => const ClientTimesheetsScreen(),
),
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) {
return ScaffoldWithNavBar(navigationShell: navigationShell);
},
branches: [
// Index 0: Coverage
StatefulShellBranch(
routes: [
GoRoute(
path: '/client-coverage',
builder: (context, state) => const ClientCoverageScreen(),
),
],
),
// Index 1: Billing
StatefulShellBranch(
routes: [
GoRoute(
path: '/client-billing',
builder: (context, state) => const ClientBillingScreen(),
),
],
),
// Index 2: Home
StatefulShellBranch(
routes: [
GoRoute(
path: '/client-home',
builder: (context, state) => const ClientHomeScreen(),
),
],
),
// Index 3: Orders (Shifts)
StatefulShellBranch(
routes: [
GoRoute(
path: '/client-shifts',
builder: (context, state) => const ClientShiftsScreen(),
),
],
),
// Index 4: Reports
StatefulShellBranch(
routes: [
GoRoute(
path: '/client-reports',
builder: (context, state) => const ClientReportsScreen(),
),
],
),
],
),
],
);

View File

@@ -1,392 +0,0 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:lucide_icons/lucide_icons.dart';
import '../../theme.dart';
class ClientGetStartedScreen extends StatelessWidget {
const ClientGetStartedScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.krowBlue,
body: SafeArea(
child: Column(
children: [
const SizedBox(height: 12),
// Logo
Image.network(
'https://qtrypzzcjebvfcihiynt.supabase.co/storage/v1/object/public/base44-prod/public/692e9622b387da7cdcd95980/29a493751_PNG3Krow.png',
height: 40,
fit: BoxFit.contain,
),
// Floating Cards Area
const Expanded(
child: Stack(
alignment: Alignment.center,
clipBehavior: Clip.none,
children: [
// Card 1 - Shift Order
Positioned(left: 24, top: 32, child: _ShiftOrderCard()),
// Card 2 - Worker Profile
Positioned(right: 24, top: 16, child: _WorkerProfileCard()),
// Card 3 - Calendar
Positioned(top: 112, child: _CalendarCard()),
],
),
),
// Bottom Content
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 40),
child: Column(
children: [
const Text(
'Take Control of Your\nShifts and Events',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.bold,
height: 1.1,
),
),
const SizedBox(height: 12),
const Text(
'Streamline your operations with powerful tools to manage schedules, track performance, and keep your team on the same page—all in one place',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white70,
fontSize: 14,
height: 1.4,
),
),
const SizedBox(height: 32),
// Sign In Button
SizedBox(
width: double.infinity,
height: 56,
child: ElevatedButton(
onPressed: () => context.push('/client-sign-in'),
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.krowYellow,
foregroundColor: AppColors.krowCharcoal,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28),
),
elevation: 0,
),
child: const Text(
'Sign In',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
const SizedBox(height: 12),
// Create Account Button
SizedBox(
width: double.infinity,
height: 56,
child: ElevatedButton(
onPressed: () => context.push('/client-sign-up'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: AppColors.krowCharcoal,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28),
),
elevation: 0,
),
child: const Text(
'Create Account',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
),
),
],
),
),
],
),
),
);
}
}
class _ShiftOrderCard extends StatelessWidget {
const _ShiftOrderCard();
@override
Widget build(BuildContext context) {
return Transform.rotate(
angle: -12 * 3.14159 / 180,
child: Container(
width: 160,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Container(
width: 20,
height: 20,
decoration: BoxDecoration(
color: Colors.green.shade100,
borderRadius: BorderRadius.circular(4),
),
child: const Center(
child: Icon(Icons.check, size: 14, color: Colors.green),
),
),
const SizedBox(width: 8),
const Text(
'Confirmed',
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w600,
color: Colors.green,
),
),
],
),
const SizedBox(height: 8),
const Text(
'Taste of the Town',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: AppColors.krowCharcoal,
),
),
const Text(
'Event Catering',
style: TextStyle(fontSize: 10, color: Colors.grey),
),
const SizedBox(height: 8),
const Row(
children: [
Icon(LucideIcons.calendar, size: 12, color: Colors.grey),
SizedBox(width: 4),
Text(
'01.21.2025, 06:30 pm',
style: TextStyle(fontSize: 10, color: Colors.grey),
),
],
),
],
),
),
);
}
}
class _WorkerProfileCard extends StatelessWidget {
const _WorkerProfileCard();
@override
Widget build(BuildContext context) {
return Transform.rotate(
angle: 8 * 3.14159 / 180,
child: Container(
width: 144,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 48,
height: 48,
decoration: const BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Colors.orangeAccent, Colors.deepOrange],
),
),
),
const SizedBox(height: 8),
const Text(
'★ Verified',
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w600,
color: Colors.green,
),
),
const SizedBox(height: 2),
const Text(
'Jane Johnson',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: AppColors.krowCharcoal,
),
),
const Text(
'Server • 4.9 ★',
style: TextStyle(fontSize: 10, color: Colors.grey),
),
],
),
),
);
}
}
class _CalendarCard extends StatelessWidget {
const _CalendarCard();
@override
Widget build(BuildContext context) {
return Container(
width: 192,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'January 2025',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: AppColors.krowCharcoal,
),
),
Icon(LucideIcons.clipboardList, size: 16, color: Colors.grey),
],
),
const SizedBox(height: 8),
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 7,
mainAxisSpacing: 2,
crossAxisSpacing: 2,
childAspectRatio: 1,
),
itemCount: 7 + 31,
itemBuilder: (context, index) {
if (index < 7) {
final days = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
return Center(
child: Text(
days[index],
style: const TextStyle(fontSize: 8, color: Colors.grey),
),
);
}
final day = index - 7 + 1;
Color? bg;
Color? text;
if (day == 21) {
bg = Colors.blue.shade600;
text = Colors.white;
} else if (day == 15) {
// Adjusted to match visual roughly
bg = Colors.green.shade100;
text = Colors.green.shade600;
}
return Container(
decoration: BoxDecoration(
color: bg,
borderRadius: BorderRadius.circular(4),
),
child: Center(
child: Text(
'$day',
style: TextStyle(
fontSize: 8,
color: text ?? Colors.grey.shade600,
),
),
),
);
},
),
const SizedBox(height: 8),
Row(
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Colors.green.shade100,
borderRadius: BorderRadius.circular(4),
),
child: const Text(
'Active Event',
style: TextStyle(fontSize: 8, color: Colors.green),
),
),
const SizedBox(width: 4),
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Colors.amber.shade100,
borderRadius: BorderRadius.circular(4),
),
child: const Text(
'Assigned Event',
style: TextStyle(fontSize: 8, color: Colors.amber),
),
),
],
),
],
),
);
}
}

View File

@@ -1,384 +0,0 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:lucide_icons/lucide_icons.dart';
import '../../theme.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class ClientSignInScreen extends StatefulWidget {
const ClientSignInScreen({super.key});
@override
State<ClientSignInScreen> createState() => _ClientSignInScreenState();
}
class _ClientSignInScreenState extends State<ClientSignInScreen> {
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
bool _obscurePassword = true;
bool _isLoading = false;
void _handleSignIn() async {
setState(() => _isLoading = true);
// Simulate sign in
await Future.delayed(const Duration(seconds: 1));
if (mounted) {
setState(() => _isLoading = false);
context.go('/client-home');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.krowBlue,
body: SafeArea(
bottom: false,
child: Column(
children: [
// Header
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
GestureDetector(
onTap: () => context.pop(),
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
LucideIcons.chevronLeft,
color: Colors.white,
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(bottom: 32),
child: Image.network(
'https://qtrypzzcjebvfcihiynt.supabase.co/storage/v1/object/public/base44-prod/public/692e9622b387da7cdcd95980/29a493751_PNG3Krow.png',
height: 40,
fit: BoxFit.contain,
),
),
// Form Card
Expanded(
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(32),
topRight: Radius.circular(32),
),
),
padding: const EdgeInsets.fromLTRB(24, 32, 24, 0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Welcome Back',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: AppColors.krowCharcoal,
),
),
const SizedBox(height: 8),
const Text(
'Sign in to manage your shifts and workers',
style: TextStyle(
fontSize: 14,
color: AppColors.krowMuted,
),
),
const SizedBox(height: 32),
// Email Field
const Text(
'Email',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.krowCharcoal,
),
),
const SizedBox(height: 8),
TextField(
controller: _emailController,
decoration: InputDecoration(
hintText: 'Enter your email',
prefixIcon: const Icon(
LucideIcons.mail,
color: AppColors.krowMuted,
size: 20,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBorder,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBorder,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBlue,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
),
),
const SizedBox(height: 20),
// Password Field
const Text(
'Password',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.krowCharcoal,
),
),
const SizedBox(height: 8),
TextField(
controller: _passwordController,
obscureText: _obscurePassword,
decoration: InputDecoration(
hintText: 'Enter your password',
prefixIcon: const Icon(
LucideIcons.lock,
color: AppColors.krowMuted,
size: 20,
),
suffixIcon: IconButton(
icon: Icon(
_obscurePassword
? LucideIcons.eyeOff
: LucideIcons.eye,
color: AppColors.krowMuted,
size: 20,
),
onPressed: () => setState(
() => _obscurePassword = !_obscurePassword,
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBorder,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBorder,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBlue,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
),
),
// Forgot Password
Align(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () {},
child: const Text(
'Forgot Password?',
style: TextStyle(
color: AppColors.krowBlue,
fontWeight: FontWeight.w500,
fontSize: 14,
),
),
),
),
const SizedBox(height: 8),
// Sign In Button
SizedBox(
height: 56,
child: ElevatedButton(
onPressed: _isLoading ? null : _handleSignIn,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.krowBlue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 0,
),
child: _isLoading
? const CircularProgressIndicator(
color: Colors.white,
)
: const Text(
'Sign In',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
),
const SizedBox(height: 24),
// Divider
const Row(
children: [
Expanded(child: Divider(color: AppColors.krowBorder)),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text(
'or',
style: TextStyle(
color: AppColors.krowMuted,
fontSize: 14,
),
),
),
Expanded(child: Divider(color: AppColors.krowBorder)),
],
),
const SizedBox(height: 24),
// Social Buttons
_SocialButton(
text: 'Sign In with Apple',
icon: Icons.apple,
onPressed: _handleSignIn,
),
const SizedBox(height: 12),
_SocialButton(
text: 'Sign In with Google',
icon: Icons
.flutter_dash, // Custom Google icon logic if needed
isGoogle: true,
onPressed: _handleSignIn,
),
const SizedBox(height: 32),
// Sign Up Link
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"Don't have an account? ",
style: TextStyle(
color: AppColors.krowMuted,
fontSize: 14,
),
),
GestureDetector(
onTap: () => context.push('/client-sign-up'),
child: const Text(
'Sign Up',
style: TextStyle(
color: AppColors.krowBlue,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
),
],
),
const SizedBox(height: 40),
],
),
),
),
),
],
),
),
);
}
}
class _SocialButton extends StatelessWidget {
final String text;
final IconData? icon;
final bool isGoogle;
final VoidCallback onPressed;
const _SocialButton({
required this.text,
this.icon,
this.isGoogle = false,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 56,
child: OutlinedButton(
onPressed: onPressed,
style: OutlinedButton.styleFrom(
side: const BorderSide(color: AppColors.krowBorder),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
foregroundColor: AppColors.krowCharcoal,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (text.contains('Apple'))
const FaIcon(
FontAwesomeIcons.apple,
color: Colors.black,
size: 20,
)
else if (isGoogle)
const FaIcon(
FontAwesomeIcons.google,
color: Colors.black,
size: 20,
)
else
Icon(icon, color: AppColors.krowCharcoal, size: 20),
const SizedBox(width: 12),
Text(
text,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: AppColors.krowCharcoal,
),
),
],
),
),
);
}
}

View File

@@ -1,463 +0,0 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:lucide_icons/lucide_icons.dart';
import '../../theme.dart';
class ClientSignUpScreen extends StatefulWidget {
const ClientSignUpScreen({super.key});
@override
State<ClientSignUpScreen> createState() => _ClientSignUpScreenState();
}
class _ClientSignUpScreenState extends State<ClientSignUpScreen> {
final _companyController = TextEditingController();
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
final _confirmPasswordController = TextEditingController();
bool _obscurePassword = true;
bool _isLoading = false;
void _handleSignUp() async {
setState(() => _isLoading = true);
// Simulate sign up
await Future.delayed(const Duration(seconds: 1));
if (mounted) {
setState(() => _isLoading = false);
context.go('/client-home');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.krowBlue,
body: SafeArea(
bottom: false,
child: Column(
children: [
// Header
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
children: [
GestureDetector(
onTap: () => context.pop(),
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1),
shape: BoxShape.circle,
),
child: const Icon(
LucideIcons.chevronLeft,
color: Colors.white,
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(bottom: 24),
child: Image.network(
'https://qtrypzzcjebvfcihiynt.supabase.co/storage/v1/object/public/base44-prod/public/692e9622b387da7cdcd95980/29a493751_PNG3Krow.png',
height: 40,
fit: BoxFit.contain,
),
),
// Form Card
Expanded(
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(32),
topRight: Radius.circular(32),
),
),
padding: const EdgeInsets.fromLTRB(24, 32, 24, 0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Create Account',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: AppColors.krowCharcoal,
),
),
const SizedBox(height: 8),
const Text(
'Get started with Krow for your business',
style: TextStyle(
fontSize: 14,
color: AppColors.krowMuted,
),
),
const SizedBox(height: 24),
// Company Name Field
const Text(
'Company Name',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.krowCharcoal,
),
),
const SizedBox(height: 8),
TextField(
controller: _companyController,
decoration: InputDecoration(
hintText: 'Enter company name',
prefixIcon: const Icon(
LucideIcons.building2,
color: AppColors.krowMuted,
size: 20,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBorder,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBorder,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBlue,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
),
),
const SizedBox(height: 20),
// Email Field
const Text(
'Email',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.krowCharcoal,
),
),
const SizedBox(height: 8),
TextField(
controller: _emailController,
decoration: InputDecoration(
hintText: 'Enter your email',
prefixIcon: const Icon(
LucideIcons.mail,
color: AppColors.krowMuted,
size: 20,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBorder,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBorder,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBlue,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
),
),
const SizedBox(height: 20),
// Password Field
const Text(
'Password',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.krowCharcoal,
),
),
const SizedBox(height: 8),
TextField(
controller: _passwordController,
obscureText: _obscurePassword,
decoration: InputDecoration(
hintText: 'Create a password',
prefixIcon: const Icon(
LucideIcons.lock,
color: AppColors.krowMuted,
size: 20,
),
suffixIcon: IconButton(
icon: Icon(
_obscurePassword
? LucideIcons.eyeOff
: LucideIcons.eye,
color: AppColors.krowMuted,
size: 20,
),
onPressed: () => setState(
() => _obscurePassword = !_obscurePassword,
),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBorder,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBorder,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBlue,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
),
),
const SizedBox(height: 20),
// Confirm Password Field
const Text(
'Confirm Password',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: AppColors.krowCharcoal,
),
),
const SizedBox(height: 8),
TextField(
controller: _confirmPasswordController,
obscureText: _obscurePassword,
decoration: InputDecoration(
hintText: 'Confirm your password',
prefixIcon: const Icon(
LucideIcons.lock,
color: AppColors.krowMuted,
size: 20,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBorder,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBorder,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: AppColors.krowBlue,
),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 16,
),
),
),
const SizedBox(height: 32),
// Create Account Button
SizedBox(
height: 56,
child: ElevatedButton(
onPressed: _isLoading ? null : _handleSignUp,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.krowBlue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 0,
),
child: _isLoading
? const CircularProgressIndicator(
color: Colors.white,
)
: const Text(
'Create Account',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
),
),
const SizedBox(height: 24),
// Divider
const Row(
children: [
Expanded(child: Divider(color: AppColors.krowBorder)),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text(
'or',
style: TextStyle(
color: AppColors.krowMuted,
fontSize: 14,
),
),
),
Expanded(child: Divider(color: AppColors.krowBorder)),
],
),
const SizedBox(height: 24),
// Social Buttons
_SocialButton(
text: 'Sign Up with Apple',
icon: Icons.apple,
onPressed: () {},
),
const SizedBox(height: 12),
_SocialButton(
text: 'Sign Up with Google',
icon: null,
isGoogle: true,
onPressed: () {},
),
const SizedBox(height: 32),
// Sign In Link
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"Already have an account? ",
style: TextStyle(
color: AppColors.krowMuted,
fontSize: 14,
),
),
GestureDetector(
onTap: () => context.push('/client-sign-in'),
child: const Text(
'Sign In',
style: TextStyle(
color: AppColors.krowBlue,
fontWeight: FontWeight.w600,
fontSize: 14,
),
),
),
],
),
const SizedBox(height: 40),
],
),
),
),
),
],
),
),
);
}
}
class _SocialButton extends StatelessWidget {
final String text;
final IconData? icon;
final bool isGoogle;
final VoidCallback onPressed;
const _SocialButton({
required this.text,
this.icon,
this.isGoogle = false,
required this.onPressed,
});
@override
Widget build(BuildContext context) {
return SizedBox(
height: 56,
child: OutlinedButton(
onPressed: onPressed,
style: OutlinedButton.styleFrom(
side: const BorderSide(color: AppColors.krowBorder),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
foregroundColor: AppColors.krowCharcoal,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (isGoogle)
Container(
width: 20,
height: 20,
decoration: const BoxDecoration(shape: BoxShape.circle),
child: Image.network(
'https://www.gstatic.com/images/branding/product/1x/gsa_512dp.png',
width: 20,
height: 20,
),
)
else if (text.contains('Apple'))
Image.network(
'https://upload.wikimedia.org/wikipedia/commons/thumb/f/fa/Apple_logo_black.svg/480px-Apple_logo_black.svg.png',
height: 24,
)
else
Icon(icon, color: AppColors.krowCharcoal, size: 20),
const SizedBox(width: 12),
Text(
text,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: AppColors.krowCharcoal,
),
),
],
),
),
);
}
}

View File

@@ -1,990 +0,0 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:lucide_icons/lucide_icons.dart';
import '../../theme.dart';
class ClientBillingScreen extends StatefulWidget {
const ClientBillingScreen({super.key});
@override
State<ClientBillingScreen> createState() => _ClientBillingScreenState();
}
class _ClientBillingScreenState extends State<ClientBillingScreen>
with SingleTickerProviderStateMixin {
late TabController _periodTabController;
// Mock Data
final double currentBill = 4250.00;
final double savings = 320.00;
final List<Map<String, dynamic>> pendingInvoices = [
{
'id': 'INV-PEND-001',
'title': 'Server Staff - Downtown Event',
'location_address': '123 Main St, City Center',
'client_name': 'TechCorp Inc.',
'date': '2024-01-24', // Use a recent date
'invoiceTotal': 840.00,
'workers_count': 3,
'total_hours': 24.0,
},
{
'id': 'INV-PEND-002',
'title': 'Bartenders - Private Party',
'location_address': '456 High St, West End',
'client_name': 'TechCorp Inc.',
'date': '2024-01-23',
'invoiceTotal': 620.00,
'workers_count': 2,
'total_hours': 16.0,
}
];
final List<Map<String, dynamic>> breakdown = [
{'category': 'Server Staff', 'hours': 120, 'amount': 2160.00},
{'category': 'Bartenders', 'hours': 80, 'amount': 1520.00},
{'category': 'Kitchen Staff', 'hours': 40, 'amount': 640.00},
{'category': 'Event Staff', 'hours': 25, 'amount': 425.00},
];
final List<Map<String, dynamic>> invoices = [
{
'id': 'INV-2024-012',
'date': '2024-12-15',
'amount': 5280.00,
'status': 'paid'
},
{
'id': 'INV-2024-011',
'date': '2024-12-08',
'amount': 4850.00,
'status': 'paid'
},
{
'id': 'INV-2024-010',
'date': '2024-12-01',
'amount': 4120.00,
'status': 'paid'
},
];
@override
void initState() {
super.initState();
_periodTabController = TabController(length: 2, vsync: this);
}
@override
void dispose() {
_periodTabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
// Colors matching React
const krowBlue = Color(0xFF0A39DF);
const krowYellow = Color(0xFFFFED4A);
const krowCharcoal = Color(0xFF121826);
// const krowMuted = Color(0xFF6A7382); // Already in theme? Using AppColors.krowMuted
return Scaffold(
backgroundColor: AppColors.krowBackground,
body: Column(
children: [
// Header
Container(
padding: const EdgeInsets.fromLTRB(20, 60, 20, 20),
color: krowBlue,
child: Column(
children: [
// Top Bar
Row(
children: [
GestureDetector(
onTap: () => context.go('/client-home'),
child: Container(
width: 36,
height: 36,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
shape: BoxShape.circle,
),
child: const Icon(
LucideIcons.arrowLeft,
color: Colors.white,
size: 16,
),
),
),
const SizedBox(width: 12),
const Text(
'Billing',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
const SizedBox(height: 20),
// Current Bill
Column(
children: [
Text(
'Current Period',
style: TextStyle(
color: Colors.white.withOpacity(0.7),
fontSize: 12,
),
),
const SizedBox(height: 4),
Text(
'\$${currentBill.toStringAsFixed(2)}',
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: krowYellow,
borderRadius: BorderRadius.circular(100),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(
LucideIcons.trendingDown,
size: 12,
color: krowCharcoal,
),
const SizedBox(width: 4),
Text(
'\$${savings.toStringAsFixed(0)} saved',
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: krowCharcoal,
),
),
],
),
),
],
),
],
),
),
// Content
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Pending Invoices
if (pendingInvoices.isNotEmpty) ...[
Row(
children: [
Container(
width: 6,
height: 6,
decoration: const BoxDecoration(
color: Colors.orange,
shape: BoxShape.circle,
),
),
const SizedBox(width: 8),
const Text(
'Awaiting Approval',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
const SizedBox(width: 8),
Container(
width: 24,
height: 24,
decoration: const BoxDecoration(
color: krowYellow,
shape: BoxShape.circle,
),
child: Center(
child: Text(
'${pendingInvoices.length}',
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
),
),
],
),
const SizedBox(height: 12),
...pendingInvoices.map(
(invoice) => Padding(
padding: const EdgeInsets.only(bottom: 8),
child: _buildPendingInvoiceCard(invoice),
),
),
const SizedBox(height: 16),
],
// Payment Method
_buildPaymentMethodCard(krowBlue, krowYellow, krowCharcoal),
const SizedBox(height: 16),
// Spending Breakdown
_buildBreakdownCard(krowCharcoal),
const SizedBox(height: 16),
// Savings Card
_buildSavingsCard(krowBlue, krowYellow, krowCharcoal),
const SizedBox(height: 24),
// Invoice History
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Invoice History',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
TextButton(
onPressed: () {},
style: TextButton.styleFrom(
padding: EdgeInsets.zero,
minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
child: Row(
children: [
Text(
'View all',
style: TextStyle(
fontSize: 12,
color: krowBlue,
fontWeight: FontWeight.w500,
),
),
Icon(
LucideIcons.chevronRight,
size: 16,
color: krowBlue,
),
],
),
),
],
),
const SizedBox(height: 8),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xFFE3E6E9)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 2,
offset: const Offset(0, 1),
),
],
),
child: Column(
children: invoices.asMap().entries.map((entry) {
final index = entry.key;
final invoice = entry.value;
return Column(
children: [
if (index > 0)
const Divider(
height: 1,
color: Color(0xFFF1F5F9),
),
_buildInvoiceItem(invoice),
],
);
}).toList(),
),
),
const SizedBox(height: 24),
// Export Button
OutlinedButton.icon(
onPressed: () {},
style: OutlinedButton.styleFrom(
minimumSize: const Size(double.infinity, 44),
side: const BorderSide(color: Color(0xFFE3E6E9)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
foregroundColor: krowCharcoal,
),
icon: const Icon(LucideIcons.download, size: 16),
label: const Text(
'Export All Invoices',
style: TextStyle(fontSize: 14),
),
),
const SizedBox(height: 24),
],
),
),
),
],
),
);
}
Widget _buildPendingInvoiceCard(Map<String, dynamic> invoice) {
const krowBlue = Color(0xFF0A39DF);
const krowCharcoal = Color(0xFF121826);
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xFFE3E6E9)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 2,
offset: const Offset(0, 1),
),
],
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Address
Row(
children: [
const Icon(
LucideIcons.mapPin,
size: 14,
color: Color(0xFF475569),
),
const SizedBox(width: 4),
Expanded(
child: Text(
invoice['location_address'],
style: const TextStyle(
fontSize: 12,
color: Color(0xFF475569),
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 4),
// Title
Text(
invoice['title'],
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
const SizedBox(height: 4),
// Client & Date
Row(
children: [
Text(
invoice['client_name'],
style: const TextStyle(
fontSize: 12,
color: Color(0xFF64748B),
),
),
const SizedBox(width: 6),
const Text(
'',
style: TextStyle(fontSize: 12, color: Color(0xFF94A3B8)),
),
const SizedBox(width: 6),
Text(
invoice['date'], // Should ideally format date
style: const TextStyle(
fontSize: 12,
color: Color(0xFF475569),
),
),
],
),
const SizedBox(height: 8),
// Status
Row(
children: [
Container(
width: 6,
height: 6,
decoration: const BoxDecoration(
color: Colors.orange,
shape: BoxShape.circle,
),
),
const SizedBox(width: 6),
const Text(
'PENDING APPROVAL',
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: Colors.orange,
letterSpacing: 0.5,
),
),
],
),
const SizedBox(height: 12),
// Grid Stats
Container(
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: const BoxDecoration(
border: Border.symmetric(
horizontal: BorderSide(color: Color(0xFFF1F5F9)),
),
),
child: Row(
children: [
Expanded(
child: Column(
children: [
const Icon(
LucideIcons.dollarSign,
size: 14,
color: Color(0xFF94A3B8),
),
const SizedBox(height: 2),
Text(
'\$${invoice['invoiceTotal'].toStringAsFixed(2)}',
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
const Text(
'Total',
style: TextStyle(
fontSize: 10,
color: Color(0xFF64748B),
),
),
],
),
),
Container(width: 1, height: 30, color: const Color(0xFFF1F5F9)),
Expanded(
child: Column(
children: [
const Icon(
LucideIcons.users,
size: 14,
color: Color(0xFF94A3B8),
),
const SizedBox(height: 2),
Text(
'${invoice['workers_count']}',
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
const Text(
'workers',
style: TextStyle(
fontSize: 10,
color: Color(0xFF64748B),
),
),
],
),
),
Container(width: 1, height: 30, color: const Color(0xFFF1F5F9)),
Expanded(
child: Column(
children: [
const Icon(
LucideIcons.clock,
size: 14,
color: Color(0xFF94A3B8),
),
const SizedBox(height: 2),
Text(
'${invoice['total_hours'].toStringAsFixed(1)}',
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
const Text(
'HRS',
style: TextStyle(
fontSize: 10,
color: Color(0xFF64748B),
),
),
],
),
),
],
),
),
const SizedBox(height: 12),
// Approve Button
ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: krowBlue,
foregroundColor: Colors.white,
minimumSize: const Size(double.infinity, 36),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
elevation: 0,
),
child: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(LucideIcons.checkCircle, size: 16),
SizedBox(width: 6),
Text(
'Review & Approve',
style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
),
],
),
),
],
),
),
);
}
Widget _buildPaymentMethodCard(
Color krowBlue,
Color krowYellow,
Color krowCharcoal,
) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xFFE3E6E9)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 2,
offset: const Offset(0, 1),
),
],
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Payment Method',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
TextButton.icon(
onPressed: () {},
icon: Icon(LucideIcons.plus, size: 14, color: krowBlue),
label: Text(
'Add',
style: TextStyle(fontSize: 12, color: krowBlue),
),
style: TextButton.styleFrom(
padding: EdgeInsets.zero,
minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
),
],
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: const Color(0xFFF8FAFC),
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Container(
width: 40,
height: 28,
decoration: BoxDecoration(
color: krowBlue,
borderRadius: BorderRadius.circular(4),
),
child: const Center(
child: Text(
'VISA',
style: TextStyle(
color: Colors.white,
fontSize: 10,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'•••• 4242',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
const Text(
'Expires 12/25',
style: TextStyle(
fontSize: 10,
color: Color(0xFF64748B),
),
),
],
),
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
decoration: BoxDecoration(
color: krowYellow,
borderRadius: BorderRadius.circular(4),
),
child: Text(
'Default',
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
),
],
),
),
],
),
);
}
Widget _buildBreakdownCard(Color krowCharcoal) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0xFFE3E6E9)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 2,
offset: const Offset(0, 1),
),
],
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'This Period Breakdown',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
Container(
height: 24,
decoration: BoxDecoration(
color: const Color(0xFFF1F5F9),
borderRadius: BorderRadius.circular(6),
),
child: TabBar(
controller: _periodTabController,
isScrollable: true,
indicator: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(4),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 1,
),
],
),
labelColor: krowCharcoal,
unselectedLabelColor: const Color(0xFF64748B),
labelStyle: const TextStyle(
fontSize: 10,
fontWeight: FontWeight.w600,
),
padding: const EdgeInsets.all(2),
indicatorSize: TabBarIndicatorSize.tab,
labelPadding: const EdgeInsets.symmetric(horizontal: 8),
dividerColor: Colors.transparent,
tabs: const [Tab(text: 'Week'), Tab(text: 'Month')],
),
),
],
),
const SizedBox(height: 8),
...breakdown.map((item) => _buildBreakdownRow(item, krowCharcoal)),
const Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: Divider(height: 1, color: Color(0xFFE2E8F0)),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Total',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
Text(
'\$${breakdown.fold(0.0, (sum, item) => sum + (item['amount'] as double)).toStringAsFixed(2)}',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
],
),
],
),
);
}
Widget _buildBreakdownRow(Map<String, dynamic> item, Color krowCharcoal) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 6),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item['category'],
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: krowCharcoal,
),
),
Text(
'${item['hours']} hours',
style: const TextStyle(fontSize: 10, color: Color(0xFF64748B)),
),
],
),
Text(
'\$${(item['amount'] as double).toStringAsFixed(2)}',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: krowCharcoal,
),
),
],
),
);
}
Widget _buildSavingsCard(
Color krowBlue,
Color krowYellow,
Color krowCharcoal,
) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: krowYellow.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: krowYellow),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: krowYellow,
borderRadius: BorderRadius.circular(8),
),
child: Icon(LucideIcons.trendingDown, size: 16, color: krowCharcoal),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Rate Optimization',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
const SizedBox(height: 4),
const Text(
'Save \$180/month by switching 3 shifts',
style: TextStyle(fontSize: 12, color: Color(0xFF475569)),
),
const SizedBox(height: 8),
SizedBox(
height: 28,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: krowBlue,
foregroundColor: Colors.white,
elevation: 0,
padding: const EdgeInsets.symmetric(horizontal: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text(
'View Details',
style: TextStyle(fontSize: 10),
),
),
),
],
),
),
],
),
);
}
Widget _buildInvoiceItem(Map<String, dynamic> invoice) {
const krowCharcoal = Color(0xFF121826);
const krowBlue = Color(0xFF0A39DF);
return Padding(
padding: const EdgeInsets.all(12),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: const Color(0xFFF1F5F9),
borderRadius: BorderRadius.circular(8),
),
child: const Icon(
LucideIcons.fileText,
size: 16,
color: Color(0xFF64748B),
),
),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
invoice['id'],
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: krowCharcoal,
),
),
Text(
invoice['date'], // Should format date
style: const TextStyle(
fontSize: 10,
color: Color(0xFF64748B),
),
),
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'\$${(invoice['amount'] as double).toStringAsFixed(2)}',
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: krowCharcoal,
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: krowBlue.withOpacity(0.1),
borderRadius: BorderRadius.circular(4),
),
child: Text(
invoice['status'].toString().toUpperCase(),
style: const TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: krowBlue,
),
),
),
],
),
const SizedBox(width: 8),
const Icon(LucideIcons.download, size: 16, color: Color(0xFF94A3B8)),
],
),
);
}
}

View File

@@ -1,967 +0,0 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart';
import 'package:lucide_icons/lucide_icons.dart';
class ClientCoverageScreen extends StatefulWidget {
const ClientCoverageScreen({super.key});
@override
State<ClientCoverageScreen> createState() => _ClientCoverageScreenState();
}
class _ClientCoverageScreenState extends State<ClientCoverageScreen> {
DateTime _selectedDate = DateTime.now();
late DateTime _today;
// Mock Data
final List<Map<String, dynamic>> _shifts = [
{
'id': '1',
'title': 'Banquet Server',
'location': 'Grand Ballroom',
'startTime': '16:00', // 4:00 PM
'workersNeeded': 10,
'date': DateTime.now().toIso8601String().split('T')[0],
'workers': [
{
'name': 'Sarah Wilson',
'status': 'confirmed',
'checkInTime': '15:55',
},
{'name': 'Mike Ross', 'status': 'confirmed', 'checkInTime': '16:00'},
{
'name': 'Jane Doe',
'status': 'confirmed',
'checkInTime': null,
}, // En route
{'name': 'John Smith', 'status': 'late', 'checkInTime': null},
],
},
{
'id': '2',
'title': 'Bartender',
'location': 'Lobby Bar',
'startTime': '17:00', // 5:00 PM
'workersNeeded': 4,
'date': DateTime.now().toIso8601String().split('T')[0],
'workers': [
{
'name': 'Emily Blunt',
'status': 'confirmed',
'checkInTime': '16:45',
},
{
'name': 'Chris Evans',
'status': 'confirmed',
'checkInTime': '16:50',
},
{
'name': 'Tom Holland',
'status': 'confirmed',
'checkInTime': null,
}, // En route
],
},
];
@override
void initState() {
super.initState();
_today = DateTime.now();
_today = DateTime(_today.year, _today.month, _today.day);
}
List<DateTime> _getCalendarDays() {
final List<DateTime> days = [];
final startDate = _selectedDate.subtract(const Duration(days: 3));
for (int i = 0; i < 7; i++) {
days.add(startDate.add(Duration(days: i)));
}
return days;
}
String _formatTime(String? time) {
if (time == null) return '';
final parts = time.split(':');
final dt = DateTime(2022, 1, 1, int.parse(parts[0]), int.parse(parts[1]));
return DateFormat('h:mm a').format(dt);
}
@override
Widget build(BuildContext context) {
// Process mock data for stats
final shiftsToday = _shifts; // In a real app, filter by date
final allApps = shiftsToday
.expand(
(s) => (s['workers'] as List).map((w) => {...w, 'shift_id': s['id']}),
)
.toList();
final totalNeeded = shiftsToday.fold(
0,
(sum, s) => sum + (s['workersNeeded'] as int),
);
final confirmedApps = allApps
.where((a) => a['status'] == 'confirmed')
.toList();
final totalConfirmed = confirmedApps.length;
final coveragePercent = totalNeeded > 0
? ((totalConfirmed / totalNeeded) * 100).round()
: 100;
final lateWorkers = allApps.where((a) => a['status'] == 'late').toList();
final onTimeWorkers = confirmedApps
.where((a) => a['checkInTime'] != null)
.toList();
final enRouteWorkers = confirmedApps
.where((a) => a['checkInTime'] == null)
.toList();
final calendarDays = _getCalendarDays();
return Scaffold(
backgroundColor: const Color(0xFFF8FAFC), // slate-50
body: SingleChildScrollView(
child: Column(
children: [
// Header
Container(
padding: const EdgeInsets.only(
top: 60,
left: 20,
right: 20,
bottom: 24,
),
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xFF2563EB), // blue-600
Color(0xFF0891B2), // cyan-600
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
GestureDetector(
onTap: () => context.go('/client-home'),
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
shape: BoxShape.circle,
),
child: const Icon(
LucideIcons.arrowLeft,
color: Colors.white,
size: 20,
),
),
),
const SizedBox(width: 12),
const Text(
'Daily Coverage',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
Container(
width: 36,
height: 36,
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.circular(8),
),
child: IconButton(
onPressed: () {
setState(() {
// refresh logic
});
},
icon: const Icon(
LucideIcons.refreshCw,
color: Colors.white,
size: 16,
),
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
style: IconButton.styleFrom(
hoverColor: Colors.white.withOpacity(0.2),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
),
],
),
const SizedBox(height: 16),
// Calendar Selector
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_NavButton(
text: '← Prev Week',
onTap: () {
setState(() {
_selectedDate = _selectedDate.subtract(
const Duration(days: 7),
);
});
},
),
_NavButton(
text: 'Today',
onTap: () {
setState(() {
final now = DateTime.now();
_selectedDate = DateTime(
now.year,
now.month,
now.day,
);
});
},
),
_NavButton(
text: 'Next Week →',
onTap: () {
setState(() {
_selectedDate = _selectedDate.add(
const Duration(days: 7),
);
});
},
),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: calendarDays.map((date) {
final isSelected =
date.year == _selectedDate.year &&
date.month == _selectedDate.month &&
date.day == _selectedDate.day;
final isToday =
date.year == _today.year &&
date.month == _today.month &&
date.day == _today.day;
return GestureDetector(
onTap: () {
setState(() {
_selectedDate = date;
});
},
child: Container(
width: 44, // roughly grid-cols-7 spacing
height: 60,
decoration: BoxDecoration(
color: isSelected
? Colors.white
: Colors.white.withOpacity(0.1),
borderRadius: BorderRadius.circular(12),
border: isToday && !isSelected
? Border.all(color: Colors.white, width: 2)
: null,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
date.day.toString().padLeft(2, '0'),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: isSelected
? const Color(0xFF0A39DF)
: Colors.white,
),
),
Text(
DateFormat('E').format(date),
style: TextStyle(
fontSize: 9,
fontWeight: FontWeight.w500,
color: isSelected
? const Color(0xFF6A7382)
: Colors.white.withOpacity(0.7),
),
),
],
),
),
);
}).toList(),
),
],
),
const SizedBox(height: 16),
// Compact Coverage Summary
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1),
borderRadius: BorderRadius.circular(16),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Coverage Status',
style: TextStyle(
fontSize: 12,
color: Colors.white.withOpacity(0.7),
),
),
Text(
'$coveragePercent%',
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'Workers',
style: TextStyle(
fontSize: 12,
color: Colors.white.withOpacity(0.7),
),
),
Text(
'$totalConfirmed/$totalNeeded',
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
],
),
],
),
),
],
),
),
// Content Body
Transform.translate(
offset: const Offset(0, -16),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: [
// Quick Stats
Row(
children: [
Expanded(
child: _QuickStatCard(
value: '${onTimeWorkers.length}',
label: 'Checked In',
valueColor: const Color(0xFF059669), // emerald-600
),
),
const SizedBox(width: 12),
Expanded(
child: _QuickStatCard(
value: '${enRouteWorkers.length}',
label: 'En Route',
valueColor: const Color(0xFFD97706), // amber-600
),
),
const SizedBox(width: 12),
Expanded(
child: _QuickStatCard(
value: '${lateWorkers.length}',
label: 'Late',
valueColor: const Color(0xFFDC2626), // red-600
),
),
],
),
// Alerts
if (lateWorkers.isNotEmpty) ...[
const SizedBox(height: 20),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: const LinearGradient(
colors: [
Color(0xFFFEF2F2), // red-50
Color(0xFFFFF1F2), // rose-50
],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: const Color(0xFFFEE2E2),
), // red-100
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.02),
blurRadius: 2,
),
],
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(
LucideIcons.alertTriangle,
color: Color(0xFFEF4444), // red-500
size: 20,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${lateWorkers.length} worker(s) running late',
style: const TextStyle(
fontWeight: FontWeight.w500,
color: Color(0xFFB91C1C), // red-700
fontSize: 14,
),
),
const SizedBox(height: 4),
const Text(
'Auto-backup system activated - finding replacements',
style: TextStyle(
fontSize: 14,
color: Color(0xFFDC2626), // red-600
),
),
],
),
),
],
),
),
],
const SizedBox(height: 20),
// Live Activity Header
const Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
'Live Activity',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Color(0xFF0F172A), // slate-900
),
),
],
),
const SizedBox(height: 12),
// Shifts List
if (shiftsToday.isEmpty)
Container(
padding: const EdgeInsets.all(32),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.02),
blurRadius: 2,
),
],
),
child: const Column(
children: [
Icon(
LucideIcons.users,
size: 48,
color: Color(0xFFCBD5E1),
), // slate-300
SizedBox(height: 12),
Text(
'No shifts scheduled for this day',
style: TextStyle(
color: Color(0xFF64748B), // slate-500
),
),
],
),
)
else
...shiftsToday.map((shift) {
final shiftApps = (shift['workers'] as List);
final workersNeeded = shift['workersNeeded'] as int;
final coverage = workersNeeded > 0
? ((shiftApps.length / workersNeeded) * 100).round()
: 100;
return Container(
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.02),
blurRadius: 2,
),
],
),
clipBehavior: Clip.antiAlias,
child: Column(
children: [
// Shift Header
Container(
padding: const EdgeInsets.all(16),
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xFFEFF6FF), // blue-50
Color(0xFFECFEFF), // cyan-50
],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
),
border: Border(
bottom: BorderSide(
color: Color(0xFFE2E8F0),
), // slate-200
),
),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 8,
height: 8,
decoration: const BoxDecoration(
color: Color(
0xFF3B82F6,
), // blue-500
shape: BoxShape.circle,
),
),
const SizedBox(width: 8),
Text(
shift['title'],
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Color(
0xFF0F172A,
), // slate-900
fontSize: 16,
),
),
],
),
const SizedBox(height: 8),
Row(
children: [
const Icon(
LucideIcons.mapPin,
size: 12,
color: Color(0xFF475569),
), // slate-600
const SizedBox(width: 4),
Text(
shift['location'],
style: const TextStyle(
fontSize: 12,
color: Color(
0xFF475569,
), // slate-600
),
),
const SizedBox(width: 12),
const Icon(
LucideIcons.clock,
size: 12,
color: Color(0xFF475569),
),
const SizedBox(width: 4),
Text(
_formatTime(
shift['startTime'],
),
style: const TextStyle(
fontSize: 12,
color: Color(0xFF475569),
),
),
],
),
],
),
),
_CoverageBadge(
current: shiftApps.length,
total: workersNeeded,
coveragePercent: coverage,
),
],
),
),
// Workers List
if (shiftApps.isNotEmpty)
Padding(
padding: const EdgeInsets.all(12),
child: Column(
children: shiftApps.map<Widget>((worker) {
final isLast = worker == shiftApps.last;
return Padding(
padding: EdgeInsets.only(
bottom: isLast ? 0 : 8,
),
child: _WorkerRow(
name: worker['name'],
status: worker['status'],
checkInTime: worker['checkInTime'],
formatTime: _formatTime,
shiftStartTime: _formatTime(
shift['startTime'],
),
),
);
}).toList(),
),
)
else
const Padding(
padding: EdgeInsets.all(16),
child: Text(
'No workers assigned yet',
style: TextStyle(
color: Color(0xFF64748B), // slate-500
fontSize: 14,
),
),
),
],
),
);
}),
const SizedBox(height: 80), // Bottom padding
],
),
),
),
],
),
),
);
}
}
class _NavButton extends StatelessWidget {
final String text;
final VoidCallback onTap;
const _NavButton({required this.text, required this.onTap});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(8),
),
child: Text(
text,
style: const TextStyle(color: Colors.white, fontSize: 14),
),
),
);
}
}
class _QuickStatCard extends StatelessWidget {
final String value;
final String label;
final Color valueColor;
const _QuickStatCard({
required this.value,
required this.label,
required this.valueColor,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(
12,
), // rounded-xl check? React uses default which is usually 0.5rem(8px) or 0.75rem(12px) for Card
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.06), // shadow-md
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Column(
children: [
Text(
value,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: valueColor,
),
),
Text(
label,
style: const TextStyle(
fontSize: 12,
color: Color(0xFF64748B), // slate-500
),
),
],
),
);
}
}
class _CoverageBadge extends StatelessWidget {
final int current;
final int total;
final int coveragePercent;
const _CoverageBadge({
required this.current,
required this.total,
required this.coveragePercent,
});
@override
Widget build(BuildContext context) {
Color bg;
Color text;
if (coveragePercent >= 100) {
bg = const Color(0xFF10B981); // emerald-500
text = Colors.white;
} else if (coveragePercent >= 80) {
bg = const Color(0xFFF59E0B); // amber-500
text = Colors.white;
} else {
bg = const Color(0xFFEF4444); // red-500
text = Colors.white;
}
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 2),
decoration: BoxDecoration(
color: bg,
borderRadius: BorderRadius.circular(100), // rounded-full
),
child: Text(
'$current/$total',
style: TextStyle(
color: text,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
);
}
}
class _WorkerRow extends StatelessWidget {
final String name;
final String status;
final String? checkInTime;
final String Function(String?) formatTime;
final String shiftStartTime;
const _WorkerRow({
required this.name,
required this.status,
required this.checkInTime,
required this.formatTime,
required this.shiftStartTime,
});
@override
Widget build(BuildContext context) {
Color bg;
Color border;
Color textBg;
Color textColor;
IconData icon;
String statusText;
Color badgeBg;
Color badgeText;
String badgeLabel;
if (status == 'confirmed' && checkInTime != null) {
// Checked In
bg = const Color(0xFFECFDF5); // emerald-50
border = const Color(0xFF10B981); // emerald-500
textBg = const Color(0xFFD1FAE5); // emerald-100
textColor = const Color(0xFF047857); // emerald-700
icon = LucideIcons.checkCircle;
statusText = '✓ Checked In at ${formatTime(checkInTime)}';
badgeBg = const Color(0xFF10B981); // emerald-500
badgeText = Colors.white;
badgeLabel = 'On Site';
} else if (status == 'confirmed' && checkInTime == null) {
// En Route
bg = const Color(0xFFFFFBEB); // amber-50
border = const Color(0xFFF59E0B); // amber-500
textBg = const Color(0xFFFEF3C7); // amber-100
textColor = const Color(0xFFB45309); // amber-700
icon = LucideIcons.clock;
statusText = 'En Route - Expected $shiftStartTime';
badgeBg = const Color(0xFFF59E0B); // amber-500
badgeText = Colors.white;
badgeLabel = 'En Route';
} else {
// Late
bg = const Color(0xFFFEF2F2); // red-50
border = const Color(0xFFEF4444); // red-500
textBg = const Color(0xFFFEE2E2); // red-100
textColor = const Color(0xFFB91C1C); // red-700
icon = LucideIcons.alertTriangle;
statusText = '⚠ Running Late';
badgeBg = const Color(0xFFEF4444); // red-500
badgeText = Colors.white;
badgeLabel = 'Late';
}
return Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: bg,
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Stack(
clipBehavior: Clip.none,
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(color: border, width: 2),
),
child: CircleAvatar(
backgroundColor: textBg,
child: Text(
name.isNotEmpty ? name[0] : 'W',
style: TextStyle(
color: textColor,
fontWeight: FontWeight.w600,
fontSize: 16,
),
),
),
),
Positioned(
bottom: -2,
right: -2,
child: Container(
width: 16,
height: 16,
decoration: BoxDecoration(
color: border,
shape: BoxShape.circle,
),
child: Icon(icon, size: 10, color: Colors.white),
),
),
],
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Color(0xFF0F172A), // slate-900
),
),
Text(
statusText,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: textColor,
),
),
],
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: badgeBg,
borderRadius: BorderRadius.circular(100), // rounded-full
),
child: Text(
badgeLabel,
style: TextStyle(
color: badgeText,
fontSize: 10, // xs
fontWeight: FontWeight.bold,
),
),
),
],
),
);
}
}

View File

@@ -1,753 +0,0 @@
import 'package:flutter/material.dart';
import 'package:lucide_icons/lucide_icons.dart';
import 'package:go_router/go_router.dart';
class ClientHubsScreen extends StatefulWidget {
const ClientHubsScreen({super.key});
@override
State<ClientHubsScreen> createState() => _ClientHubsScreenState();
}
class _ClientHubsScreenState extends State<ClientHubsScreen> {
// Mock Data
final List<Map<String, dynamic>> _hubs = [];
bool _showAddHub = false;
bool _showIdentifyNFC = false;
Map<String, dynamic>? _selectedHub;
String? _nfcTagId;
final _nameController = TextEditingController();
final _locationNameController = TextEditingController();
final _addressController = TextEditingController();
void _addHub() {
if (_nameController.text.isEmpty) return;
setState(() {
_hubs.add({
'id': DateTime.now().millisecondsSinceEpoch.toString(),
'name': _nameController.text,
'locationName': _locationNameController.text,
'address': _addressController.text,
'nfcTagId': null,
});
_nameController.clear();
_locationNameController.clear();
_addressController.clear();
_showAddHub = false;
});
}
void _deleteHub(String id) {
setState(() {
_hubs.removeWhere((hub) => hub['id'] == id);
});
}
void _simulateNFCScan() {
setState(() {
_nfcTagId =
'NFC-${DateTime.now().millisecondsSinceEpoch.toString().substring(8).toUpperCase()}';
});
}
void _assignTag() {
if (_selectedHub != null && _nfcTagId != null) {
setState(() {
final index = _hubs.indexWhere((h) => h['id'] == _selectedHub!['id']);
if (index != -1) {
_hubs[index]['nfcTagId'] = _nfcTagId;
}
_showIdentifyNFC = false;
_nfcTagId = null;
_selectedHub = null;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF8FAFC), // slate-50
body: Stack(
children: [
CustomScrollView(
slivers: [
SliverAppBar(
backgroundColor: const Color(0xFF121826),
automaticallyImplyLeading: false,
expandedHeight: 140,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
background: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFF121826), Color(0xFF1E293B)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
padding: const EdgeInsets.fromLTRB(20, 48, 20, 0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
onTap: () => context.pop(),
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
shape: BoxShape.circle,
),
child: const Icon(
LucideIcons.arrowLeft,
color: Colors.white,
size: 20,
),
),
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Hubs',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 24,
),
),
Text(
'Manage clock-in locations',
style: TextStyle(
color: Color(0xFFCBD5E1), // slate-300
fontSize: 14,
),
),
],
),
ElevatedButton.icon(
onPressed: () =>
setState(() => _showAddHub = true),
icon: const Icon(
LucideIcons.plus,
size: 16,
color: Color(0xFF121826),
),
label: const Text(
'Add Hub',
style: TextStyle(
color: Color(0xFF121826),
fontWeight: FontWeight.bold,
fontSize: 13,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFFFED4A),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 4,
padding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
),
),
],
),
],
),
),
),
),
SliverPadding(
padding: const EdgeInsets.fromLTRB(20, 20, 20, 100),
sliver: SliverList(
delegate: SliverChildListDelegate([
const SizedBox(height: 12),
..._hubs.map((hub) => _buildHubCard(hub)),
if (_hubs.isEmpty) _buildEmptyState(),
const SizedBox(height: 20),
_buildInfoCard(),
]),
),
),
],
),
if (_showAddHub) _buildAddHubDialog(),
if (_showIdentifyNFC) _buildIdentifyNFCDialog(),
],
),
);
}
Widget _buildHubCard(Map<String, dynamic> hub) {
final bool hasNfc = hub['nfcTagId'] != null;
return Container(
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.04),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Container(
width: 52,
height: 52,
decoration: BoxDecoration(
color: const Color(0xFFEFF6FF), // blue-50
borderRadius: BorderRadius.circular(16),
),
child: Icon(
hasNfc ? LucideIcons.checkCircle : LucideIcons.nfc,
color: hasNfc
? const Color(0xFF16A34A)
: const Color(0xFF94A3B8), // green-600 or slate-400
size: 24,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
hub['name'],
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: Color(0xFF0F172A),
),
),
if (hub['locationName'].isNotEmpty)
Text(
hub['locationName'],
style: const TextStyle(
color: Color(0xFF64748B),
fontSize: 12,
),
),
if (hub['address'].isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Row(
children: [
const Icon(
LucideIcons.mapPin,
size: 12,
color: Color(0xFF94A3B8),
),
const SizedBox(width: 4),
Expanded(
child: Text(
hub['address'],
style: const TextStyle(
color: Color(0xFF64748B),
fontSize: 12,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
if (hasNfc)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Text(
'Tag: ${hub['nfcTagId']}',
style: const TextStyle(
color: Color(0xFF16A34A),
fontSize: 12,
fontFamily: 'monospace',
fontWeight: FontWeight.bold,
),
),
),
],
),
),
Row(
children: [
IconButton(
onPressed: () {
setState(() {
_selectedHub = hub;
_showIdentifyNFC = true;
});
},
icon: const Icon(
LucideIcons.nfc,
color: Color(0xFF2563EB),
size: 20,
),
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
splashRadius: 20,
),
const SizedBox(width: 8),
IconButton(
onPressed: () => _deleteHub(hub['id']),
icon: const Icon(
LucideIcons.trash2,
color: Color(0xFFDC2626),
size: 20,
), // red-600
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
splashRadius: 20,
),
],
),
],
),
),
);
}
Widget _buildEmptyState() {
return Container(
padding: const EdgeInsets.all(32),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.04),
blurRadius: 10,
offset: const Offset(0, 4),
),
],
),
child: Column(
children: [
Container(
width: 64,
height: 64,
decoration: const BoxDecoration(
color: Color(0xFFF1F5F9), // slate-100
shape: BoxShape.circle,
),
child: const Icon(
LucideIcons.nfc,
size: 32,
color: Color(0xFF94A3B8),
),
),
const SizedBox(height: 16),
const Text(
'No hubs yet',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Color(0xFF0F172A),
),
),
const SizedBox(height: 8),
const Text(
'Create clock-in stations for your locations',
textAlign: TextAlign.center,
style: TextStyle(color: Color(0xFF64748B), fontSize: 14),
),
const SizedBox(height: 24),
ElevatedButton.icon(
onPressed: () => setState(() => _showAddHub = true),
icon: const Icon(
LucideIcons.plus,
size: 16,
color: Color(0xFF121826),
),
label: const Text(
'Add Your First Hub',
style: TextStyle(
color: Color(0xFF121826),
fontWeight: FontWeight.bold,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFFFED4A),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 4,
),
),
],
),
);
}
Widget _buildInfoCard() {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFFEFF6FF), // blue-50
borderRadius: BorderRadius.circular(16),
),
child: const Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Icon(LucideIcons.nfc, size: 20, color: Color(0xFF2563EB)),
SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'About Hubs',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Color(0xFF0F172A),
),
),
SizedBox(height: 4),
Text(
'Hubs are clock-in stations at your locations. Assign NFC tags to each hub so workers can quickly clock in/out using their phones.',
style: TextStyle(
color: Color(0xFF334155),
fontSize: 12,
height: 1.4,
),
),
],
),
),
],
),
);
}
Widget _buildAddHubDialog() {
return Container(
color: Colors.black.withOpacity(0.5),
child: Center(
child: Container(
width: MediaQuery.of(context).size.width * 0.9,
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24),
boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.1), blurRadius: 20),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Add New Hub',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xFF0F172A),
),
),
const SizedBox(height: 24),
_buildFieldLabel('Hub Name *'),
TextField(
controller: _nameController,
decoration: _buildInputDecoration(
'e.g., Main Kitchen, Front Desk',
),
),
const SizedBox(height: 16),
_buildFieldLabel('Location Name'),
TextField(
controller: _locationNameController,
decoration: _buildInputDecoration('e.g., Downtown Restaurant'),
),
const SizedBox(height: 16),
_buildFieldLabel('Address'),
TextField(
controller: _addressController,
decoration: _buildInputDecoration('Full address'),
),
const SizedBox(height: 32),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () => setState(() => _showAddHub = false),
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
side: const BorderSide(color: Color(0xFFE2E8F0)),
),
child: const Text(
'Cancel',
style: TextStyle(color: Color(0xFF64748B)),
),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: _addHub,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFFFED4A),
foregroundColor: const Color(0xFF121826),
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 0,
),
child: const Text(
'Create Hub',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
),
],
),
],
),
),
),
);
}
Widget _buildIdentifyNFCDialog() {
return Container(
color: Colors.black.withOpacity(0.5),
child: Center(
child: Container(
width: MediaQuery.of(context).size.width * 0.9,
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(24),
boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.1), blurRadius: 20),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'Identify NFC Tag',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xFF0F172A),
),
),
const SizedBox(height: 32),
Container(
width: 80,
height: 80,
decoration: const BoxDecoration(
color: Color(0xFFEFF6FF), // blue-50
shape: BoxShape.circle,
),
child: const Icon(
LucideIcons.nfc,
size: 40,
color: Color(0xFF2563EB),
),
),
const SizedBox(height: 16),
Text(
_selectedHub?['name'] ?? '',
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
color: Color(0xFF0F172A),
),
),
const SizedBox(height: 8),
const Text(
'Tap your phone to the NFC tag to identify it',
textAlign: TextAlign.center,
style: TextStyle(color: Color(0xFF64748B), fontSize: 14),
),
const SizedBox(height: 24),
ElevatedButton.icon(
onPressed: _simulateNFCScan,
icon: const Icon(LucideIcons.nfc, size: 20),
label: const Text(
'Scan NFC Tag',
style: TextStyle(fontWeight: FontWeight.bold),
),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF0047FF),
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 14,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 4,
),
),
if (_nfcTagId != null) ...[
const SizedBox(height: 24),
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFFF0FDF4), // green-50
borderRadius: BorderRadius.circular(16),
),
child: Column(
children: [
const Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
LucideIcons.checkCircle,
size: 20,
color: Color(0xFF16A34A),
),
SizedBox(width: 8),
Text(
'Tag Identified',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Color(0xFF0F172A),
),
),
],
),
const SizedBox(height: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: const Color(0xFFDCE8E0)),
),
child: Text(
_nfcTagId!,
style: const TextStyle(
fontFamily: 'monospace',
fontWeight: FontWeight.bold,
fontSize: 12,
color: Color(0xFF334155),
),
),
),
],
),
),
],
const SizedBox(height: 32),
Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: () {
setState(() {
_showIdentifyNFC = false;
_nfcTagId = null;
_selectedHub = null;
});
},
style: OutlinedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
side: const BorderSide(color: Color(0xFFE2E8F0)),
),
child: const Text(
'Cancel',
style: TextStyle(color: Color(0xFF64748B)),
),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: _nfcTagId != null ? _assignTag : null,
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFFFFED4A),
foregroundColor: const Color(0xFF121826),
padding: const EdgeInsets.symmetric(vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 0,
),
child: const Text(
'Assign Tag',
style: TextStyle(fontWeight: FontWeight.bold),
),
),
),
],
),
],
),
),
),
);
}
Widget _buildFieldLabel(String label) {
return Padding(
padding: const EdgeInsets.only(bottom: 6),
child: Text(
label,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Color(0xFF0F172A),
),
),
);
}
InputDecoration _buildInputDecoration(String hint) {
return InputDecoration(
hintText: hint,
hintStyle: const TextStyle(color: Color(0xFF94A3B8), fontSize: 14),
filled: true,
fillColor: const Color(0xFFF8FAFC),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0xFFE2E8F0)),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0xFFE2E8F0)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0xFF2563EB), width: 2),
),
);
}
}

View File

@@ -1,544 +0,0 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:lucide_icons/lucide_icons.dart';
class ClientReportsScreen extends StatefulWidget {
const ClientReportsScreen({super.key});
@override
State<ClientReportsScreen> createState() => _ClientReportsScreenState();
}
class _ClientReportsScreenState extends State<ClientReportsScreen>
with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 4, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF8FAFC), // slate-50
body: SingleChildScrollView(
child: Column(
children: [
// Header
Container(
padding: const EdgeInsets.only(
top: 60,
left: 20,
right: 20,
bottom: 32,
),
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
Color(0xFF0A39DF), // React primary
Color(0xFF0830B8), // React darker
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Column(
children: [
Row(
children: [
GestureDetector(
onTap: () => context.go('/client-home'),
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
shape: BoxShape.circle,
),
child: const Icon(
LucideIcons.arrowLeft,
color: Colors.white,
size: 20,
),
),
),
const SizedBox(width: 12),
const Text(
'Workforce Control Tower',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
const SizedBox(height: 24),
// Tabs
Container(
height: 44,
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: TabBar(
controller: _tabController,
indicator: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
labelColor: const Color(0xFF0A39DF),
unselectedLabelColor: Colors.white,
labelStyle: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 14,
),
indicatorSize: TabBarIndicatorSize.tab,
dividerColor: Colors.transparent,
tabs: const [
Tab(text: 'Today'),
Tab(text: 'Week'),
Tab(text: 'Month'),
Tab(text: 'Quarter'),
],
),
),
],
),
),
// Content
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Key Metrics - 6 items as in React
GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 1.2,
children: const [
_MetricCard(
icon: LucideIcons.clock,
label: 'Total Hrs',
value: '1,248',
badgeText: 'This period',
badgeColor: Color(0xFFEEF2FF), // indigo-50
badgeTextColor: Color(0xFF4338CA), // indigo-700
iconColor: Color(0xFF4F46E5), // indigo-600
),
_MetricCard(
icon: LucideIcons.trendingUp,
label: 'OT Hours',
value: '64',
badgeText: '5.1% of total',
badgeColor: Color(0xFFF1F5F9), // slate-100
badgeTextColor: Color(0xFF475569), // slate-600
iconColor: Color(0xFFD97706), // amber-600
),
_MetricCard(
icon: LucideIcons.dollarSign,
label: 'Total Spend',
value: '\$17.2k',
badgeText: '↓ 8% vs last week',
badgeColor: Color(0xFFD1FAE5), // emerald-100
badgeTextColor: Color(0xFF047857), // emerald-700
iconColor: Color(0xFF10B981), // emerald-600
),
_MetricCard(
icon: LucideIcons.trendingUp,
label: 'Fill Rate',
value: '96%',
badgeText: '↑ 2% improvement',
badgeColor: Color(0xFFDBEAFE), // blue-100
badgeTextColor: Color(0xFF1D4ED8), // blue-700
iconColor: Color(0xFF2563EB), // blue-600
),
_MetricCard(
icon: LucideIcons.clock,
label: 'Avg Fill Time',
value: '2.4 hrs',
badgeText: 'Industry best',
badgeColor: Color(0xFFDBEAFE), // blue-100
badgeTextColor: Color(0xFF1D4ED8), // blue-700
iconColor: Color(0xFF2563EB), // blue-600
),
_MetricCard(
icon: LucideIcons.alertTriangle,
label: 'No-Show Rate',
value: '2%',
badgeText: 'Below avg',
badgeColor: Color(0xFFD1FAE5), // emerald-100
badgeTextColor: Color(0xFF047857), // emerald-700
iconColor: Color(0xFFDC2626), // red-600
),
],
),
// Quick Reports
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Quick Reports',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Color(0xFF0F172A), // slate-900
),
),
TextButton.icon(
onPressed: () {},
icon: const Icon(LucideIcons.download, size: 16),
label: const Text('Export All'),
style: TextButton.styleFrom(
foregroundColor: const Color(0xFF2563EB), // blue-600
padding: EdgeInsets.zero,
minimumSize: Size.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
),
],
),
GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 1.3,
children: const [
_ReportCard(
icon: LucideIcons.calendar,
name: 'Daily Ops Report',
iconBgColor: Color(0xFFDBEAFE), // blue-100
iconColor: Color(0xFF2563EB), // blue-600
route: '/daily-ops-report',
),
_ReportCard(
icon: LucideIcons.dollarSign,
name: 'Spend Report',
iconBgColor: Color(0xFFD1FAE5), // emerald-100
iconColor: Color(0xFF059669), // emerald-600
route: '/spend-report',
),
_ReportCard(
icon: LucideIcons.users,
name: 'Coverage Report',
iconBgColor: Color(0xFFDBEAFE), // blue-100
iconColor: Color(0xFF2563EB), // blue-600
route: '/coverage-report-detail',
),
_ReportCard(
icon: LucideIcons.alertTriangle,
name: 'No-Show Report',
iconBgColor: Color(0xFFFEE2E2), // red-100
iconColor: Color(0xFFDC2626), // red-600
route: '/no-show-report',
),
_ReportCard(
icon: LucideIcons.trendingUp,
name: 'Forecast Report',
iconBgColor: Color(0xFFFEF3C7), // amber-100
iconColor: Color(0xFFD97706), // amber-600
route: '/forecast-report',
),
_ReportCard(
icon: LucideIcons.barChart3,
name: 'Performance Report',
iconBgColor: Color(0xFFDBEAFE), // blue-100
iconColor: Color(0xFF2563EB), // blue-600
route: '/performance-report',
),
],
),
// AI Insights
Container(
width: double.infinity,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFFEBF5FF), // Light blue as in React
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.02),
blurRadius: 2,
offset: const Offset(0, 1),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'💡 AI Insights',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: Color(0xFF0F172A), // slate-900
),
),
const SizedBox(height: 12),
_InsightRow(
children: [
const TextSpan(text: 'You could save '),
const TextSpan(
text: '\$1,200/month',
style: TextStyle(fontWeight: FontWeight.bold),
),
const TextSpan(
text: ' by booking workers 48hrs in advance',
),
],
),
_InsightRow(
children: [
const TextSpan(text: 'Weekend demand is '),
const TextSpan(
text: '40% higher',
style: TextStyle(fontWeight: FontWeight.bold),
),
const TextSpan(
text: ' - consider scheduling earlier',
),
],
),
_InsightRow(
children: [
const TextSpan(
text: 'Your top 5 workers complete ',
),
const TextSpan(
text: '95% of shifts',
style: TextStyle(fontWeight: FontWeight.bold),
),
const TextSpan(text: ' - mark them as preferred'),
],
),
],
),
),
const SizedBox(height: 100), // pb-24
],
),
),
],
),
),
);
}
}
class _MetricCard extends StatelessWidget {
final IconData icon;
final String label;
final String value;
final String badgeText;
final Color badgeColor;
final Color badgeTextColor;
final Color iconColor;
const _MetricCard({
required this.icon,
required this.label,
required this.value,
required this.badgeText,
required this.badgeColor,
required this.badgeTextColor,
required this.iconColor,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.06), // shadow-md
blurRadius: 4,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(icon, size: 16, color: iconColor),
const SizedBox(width: 8),
Text(
label,
style: const TextStyle(
fontSize: 12,
color: Color(0xFF64748B), // slate-500
),
),
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
value,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Color(0xFF0F172A), // slate-900
),
),
const SizedBox(height: 4),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: badgeColor,
borderRadius: BorderRadius.circular(10),
),
child: Text(
badgeText,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w500,
color: badgeTextColor,
),
),
),
],
),
],
),
);
}
}
class _ReportCard extends StatelessWidget {
final IconData icon;
final String name;
final Color iconBgColor;
final Color iconColor;
final String route;
const _ReportCard({
required this.icon,
required this.name,
required this.iconBgColor,
required this.iconColor,
required this.route,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => context.push(route),
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(color: Colors.black.withOpacity(0.02), blurRadius: 2),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: iconBgColor,
borderRadius: BorderRadius.circular(12),
),
child: Icon(icon, size: 20, color: iconColor),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Color(0xFF0F172A),
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
const Row(
children: [
Icon(
LucideIcons.download,
size: 12,
color: Color(0xFF64748B),
),
SizedBox(width: 4),
Text(
'2-click export',
style: TextStyle(fontSize: 12, color: Color(0xFF64748B)),
),
],
),
],
),
],
),
),
);
}
}
class _InsightRow extends StatelessWidget {
final List<InlineSpan> children;
const _InsightRow({required this.children});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'',
style: TextStyle(color: Color(0xFF334155), fontSize: 14),
),
Expanded(
child: Text.rich(
TextSpan(
style: const TextStyle(
fontSize: 14,
color: Color(0xFF334155),
height: 1.4,
),
children: children,
),
),
),
],
),
);
}
}

Some files were not shown because too many files have changed in this diff Show More