Add application source code and update project structure

This commit is contained in:
PhongMacbook
2025-11-05 03:20:59 +07:00
parent 95f8296211
commit b145c7844f
155 changed files with 9171 additions and 0 deletions

View File

50
Application Product/Source/source/.gitignore vendored Executable file
View File

@@ -0,0 +1,50 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# 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
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Firebase  this is necessary if you use Firebase since it could otherwise
# lead to leaking of private certificates to your repository, which is no bueno.
.firebase/
# Web related
lib/generated_plugin_registrant.dart
# 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

@@ -0,0 +1,10 @@
# 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: 4d7946a68d26794349189cf21b3f68cc6fe61dcb
channel: stable
project_type: app

View File

@@ -0,0 +1,7 @@
# UVita
A new Flutter project.
## Getting Started
FlutterFlow projects are built to run on the Flutter _stable_ release.

View File

@@ -0,0 +1,29 @@
# 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
unnecessary_string_escapes: false
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View File

@@ -0,0 +1,11 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties

View File

@@ -0,0 +1,79 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
compileSdkVersion 34
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
checkReleaseBuilds false
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.mycompany.uvita"
minSdkVersion 21
targetSdkVersion 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
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.debug
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.10"
}

View File

@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mycompany.uvita">
<!-- Flutter 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

@@ -0,0 +1,62 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mycompany.uvita"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:label="UVita"
tools:replace="android:label"
android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
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"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!-- Deep linking -->
<meta-data android:name="flutter_deeplinking_enabled" android:value="true" />
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="uvita" android:host="uvita.com" />
</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>
</manifest>

View File

@@ -0,0 +1,6 @@
package com.mycompany.uvita
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter 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

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter 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

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter 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

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<string name="app_name">UVita</string>
</resources>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter 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

@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mycompany.uvita">
<!-- Flutter 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

@@ -0,0 +1,18 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@@ -0,0 +1,4 @@
org.gradle.jvmargs=-Xmx4608m
android.useAndroidX=true
android.enableJetifier=true
android.enableR8=true

View File

@@ -0,0 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

View File

@@ -0,0 +1,27 @@
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return 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 "7.3.0" apply false
id "org.jetbrains.kotlin.android" version "1.8.10" apply false
}
include ":app"

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

View File

@@ -0,0 +1,33 @@
*.mode1v3
*.mode2v3
*.moved-aside
*.pbxuser
*.perspectivev3
**/*sync/
.sconsign.dblite
.tags*
**/.vagrant/
**/DerivedData/
Icon?
**/Pods/
**/.symlinks/
profile
xcuserdata
**/.generated/
build/
Flutter/App.framework
Flutter/Flutter.framework
Flutter/Flutter.podspec
Flutter/Generated.xcconfig
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

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

View File

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

View File

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

View File

@@ -0,0 +1,31 @@
<?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>ImageNotification</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>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.usernotifications.service</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
</dict>
</dict>
</plist>

View File

@@ -0,0 +1,27 @@
import FirebaseMessaging
import UserNotifications
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = request.content
.mutableCopy() as? UNMutableNotificationContent
guard let bestAttemptContent = bestAttemptContent else { return }
FIRMessagingExtensionHelper().populateNotificationContent(
bestAttemptContent,
withContentHandler: contentHandler)
}
override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}

View File

@@ -0,0 +1,45 @@
# Uncomment this line to define a global platform for your project
platform :ios, '14.0.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! :linkage => :static
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET'
end
end
end

View File

@@ -0,0 +1,513 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
44A671D52BC7AFBA0042F967 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 44A671D42BC7AFBA0042F967 /* PrivacyInfo.xcprivacy */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
6436409A27A31CD800820AF7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6436409C27A31CD800820AF7 /* InfoPlist.strings */; };
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 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>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
44A671D42BC7AFBA0042F967 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; 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>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
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 */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
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 */,
6436409C27A31CD800820AF7 /* InfoPlist.strings */,
44A671D42BC7AFBA0042F967 /* PrivacyInfo.xcprivacy */,
);
path = Runner;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = "";
TargetAttributes = {
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 */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
44A671D52BC7AFBA0042F967 /* PrivacyInfo.xcprivacy in Resources */,
6436409A27A31CD800820AF7 /* InfoPlist.strings 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;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
6436409C27A31CD800820AF7 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
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;
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;
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 = 14.0.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_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mycompany.uvita;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
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;
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 = 14.0.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;
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;
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 = 14.0.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
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_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mycompany.uvita;
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_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.mycompany.uvita;
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 */
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

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

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
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"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</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

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

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>

View File

@@ -0,0 +1,14 @@
import UIKit
import Flutter
@UIApplicationMain
@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

@@ -0,0 +1,122 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View File

@@ -0,0 +1,5 @@
# Launch Screen Assets
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>UVita</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>UVita</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array> <dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>uvita.com</string>
<key>CFBundleURLSchemes</key>
<array>
<string>uvita</string>
</array>
</dict>
</array>
<key>FlutterDeepLinkingEnabled</key>
<true/>
<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>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

@@ -0,0 +1,5 @@
<?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/>
</plist>

View File

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

View File

@@ -0,0 +1,6 @@
<?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>
</dict>
</plist>

View File

@@ -0,0 +1,66 @@
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/flutter_flow/flutter_flow_widgets.dart';
import '/widget/advice/advice_widget.dart';
import '/widget/advice_copy/advice_copy_widget.dart';
import '/widget/box/box_widget.dart';
import '/widget/dashboard01_recent_activity/dashboard01_recent_activity_widget.dart';
import '/widget/healthy/healthy_widget.dart';
import '/widget/healthy_copy/healthy_copy_widget.dart';
import '/widget/material_card2/material_card2_widget.dart';
import '/widget/temp_and_u_v/temp_and_u_v_widget.dart';
import '/widget/time_count/time_count_widget.dart';
import 'analyst_widget.dart' show AnalystWidget;
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
class AnalystModel extends FlutterFlowModel<AnalystWidget> {
/// State fields for stateful widgets in this page.
// Model for Time_Count component.
late TimeCountModel timeCountModel;
// Model for box component.
late BoxModel boxModel;
// Model for TempAndUV component.
late TempAndUVModel tempAndUVModel;
// Model for Dashboard01RecentActivity component.
late Dashboard01RecentActivityModel dashboard01RecentActivityModel;
// Model for MaterialCard2 component.
late MaterialCard2Model materialCard2Model;
// Model for Advice component.
late AdviceModel adviceModel;
// Model for AdviceCopy component.
late AdviceCopyModel adviceCopyModel;
// Model for HealthyCopy component.
late HealthyCopyModel healthyCopyModel;
// Model for Healthy component.
late HealthyModel healthyModel;
@override
void initState(BuildContext context) {
timeCountModel = createModel(context, () => TimeCountModel());
boxModel = createModel(context, () => BoxModel());
tempAndUVModel = createModel(context, () => TempAndUVModel());
dashboard01RecentActivityModel =
createModel(context, () => Dashboard01RecentActivityModel());
materialCard2Model = createModel(context, () => MaterialCard2Model());
adviceModel = createModel(context, () => AdviceModel());
adviceCopyModel = createModel(context, () => AdviceCopyModel());
healthyCopyModel = createModel(context, () => HealthyCopyModel());
healthyModel = createModel(context, () => HealthyModel());
}
@override
void dispose() {
timeCountModel.dispose();
boxModel.dispose();
tempAndUVModel.dispose();
dashboard01RecentActivityModel.dispose();
materialCard2Model.dispose();
adviceModel.dispose();
adviceCopyModel.dispose();
healthyCopyModel.dispose();
healthyModel.dispose();
}
}

View File

@@ -0,0 +1,127 @@
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/flutter_flow/flutter_flow_widgets.dart';
import '/widget/advice/advice_widget.dart';
import '/widget/advice_copy/advice_copy_widget.dart';
import '/widget/box/box_widget.dart';
import '/widget/dashboard01_recent_activity/dashboard01_recent_activity_widget.dart';
import '/widget/healthy/healthy_widget.dart';
import '/widget/healthy_copy/healthy_copy_widget.dart';
import '/widget/material_card2/material_card2_widget.dart';
import '/widget/temp_and_u_v/temp_and_u_v_widget.dart';
import '/widget/time_count/time_count_widget.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'analyst_model.dart';
export 'analyst_model.dart';
class AnalystWidget extends StatefulWidget {
const AnalystWidget({super.key});
@override
State<AnalystWidget> createState() => _AnalystWidgetState();
}
class _AnalystWidgetState extends State<AnalystWidget> {
late AnalystModel _model;
final scaffoldKey = GlobalKey<ScaffoldState>();
@override
void initState() {
super.initState();
_model = createModel(context, () => AnalystModel());
}
@override
void dispose() {
_model.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
key: scaffoldKey,
backgroundColor: Color(0xFFDDDCDC),
body: SafeArea(
top: true,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Padding(
padding: EdgeInsets.all(22.0),
child: wrapWithModel(
model: _model.timeCountModel,
updateCallback: () => safeSetState(() {}),
child: TimeCountWidget(),
),
),
Padding(
padding: EdgeInsets.all(2.0),
child: wrapWithModel(
model: _model.boxModel,
updateCallback: () => safeSetState(() {}),
child: BoxWidget(),
),
),
Padding(
padding: EdgeInsets.all(6.0),
child: wrapWithModel(
model: _model.tempAndUVModel,
updateCallback: () => safeSetState(() {}),
child: TempAndUVWidget(),
),
),
Padding(
padding: EdgeInsets.all(4.0),
child: wrapWithModel(
model: _model.dashboard01RecentActivityModel,
updateCallback: () => safeSetState(() {}),
child: Dashboard01RecentActivityWidget(),
),
),
wrapWithModel(
model: _model.materialCard2Model,
updateCallback: () => safeSetState(() {}),
child: MaterialCard2Widget(),
),
Padding(
padding: EdgeInsets.all(20.0),
child: wrapWithModel(
model: _model.adviceModel,
updateCallback: () => safeSetState(() {}),
child: AdviceWidget(),
),
),
Padding(
padding: EdgeInsets.all(20.0),
child: wrapWithModel(
model: _model.adviceCopyModel,
updateCallback: () => safeSetState(() {}),
child: AdviceCopyWidget(),
),
),
wrapWithModel(
model: _model.healthyCopyModel,
updateCallback: () => safeSetState(() {}),
child: HealthyCopyWidget(),
),
wrapWithModel(
model: _model.healthyModel,
updateCallback: () => safeSetState(() {}),
child: HealthyWidget(),
),
],
),
),
),
),
);
}
}

View File

@@ -0,0 +1,14 @@
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import 'card35_news_article_widget.dart' show Card35NewsArticleWidget;
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
class Card35NewsArticleModel extends FlutterFlowModel<Card35NewsArticleWidget> {
@override
void initState(BuildContext context) {}
@override
void dispose() {}
}

View File

@@ -0,0 +1,184 @@
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'card35_news_article_model.dart';
export 'card35_news_article_model.dart';
class Card35NewsArticleWidget extends StatefulWidget {
const Card35NewsArticleWidget({super.key});
@override
State<Card35NewsArticleWidget> createState() =>
_Card35NewsArticleWidgetState();
}
class _Card35NewsArticleWidgetState extends State<Card35NewsArticleWidget> {
late Card35NewsArticleModel _model;
@override
void setState(VoidCallback callback) {
super.setState(callback);
_model.onUpdate();
}
@override
void initState() {
super.initState();
_model = createModel(context, () => Card35NewsArticleModel());
}
@override
void dispose() {
_model.maybeDispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsetsDirectional.fromSTEB(16.0, 12.0, 16.0, 0.0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: FlutterFlowTheme.of(context).secondaryBackground,
borderRadius: BorderRadius.circular(8.0),
),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 160.0,
child: Stack(
alignment: AlignmentDirectional(0.0, 1.0),
children: [
Align(
alignment: AlignmentDirectional(0.0, -1.0),
child: ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(0.0),
bottomRight: Radius.circular(0.0),
topLeft: Radius.circular(8.0),
topRight: Radius.circular(8.0),
),
child: Image.asset(
'assets/images/230302-AWS-services.jpg',
width: double.infinity,
height: 130.0,
fit: BoxFit.cover,
),
),
),
Align(
alignment: AlignmentDirectional(0.0, 1.0),
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(16.0, 0.0, 24.0, 0.0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
Icon(
Icons.grid_on_rounded,
color: Color(0xFF9A0F0F),
size: 24.0,
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
8.0, 0.0, 0.0, 0.0),
child: Text(
'NASA NEWS',
style: FlutterFlowTheme.of(context)
.bodyMedium
.override(
fontFamily: 'Inter',
color: Color(0xFFAE1010),
fontSize: 23.0,
letterSpacing: 0.0,
fontWeight: FontWeight.bold,
),
),
),
],
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.0, 0.0, 0.0, 12.0),
child: Container(
width: 40.0,
height: 40.0,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
FlutterFlowTheme.of(context).primary,
FlutterFlowTheme.of(context).secondary,
FlutterFlowTheme.of(context).alternate
],
stops: [0.0, 0.3, 1.0],
begin: AlignmentDirectional(1.0, 0.98),
end: AlignmentDirectional(-1.0, -0.98),
),
shape: BoxShape.circle,
),
child: Padding(
padding: EdgeInsets.all(2.0),
child: Container(
width: 40.0,
height: 40.0,
decoration: BoxDecoration(
color: FlutterFlowTheme.of(context)
.secondaryBackground,
shape: BoxShape.circle,
),
child: Icon(
Icons.chevron_right_rounded,
color: FlutterFlowTheme.of(context)
.primaryText,
size: 32.0,
),
),
),
),
),
],
),
),
),
],
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(16.0, 8.0, 0.0, 0.0),
child: Text(
'Explore Open Data on AWS',
style: FlutterFlowTheme.of(context).titleLarge.override(
fontFamily: 'Inter Tight',
fontSize: 24.0,
letterSpacing: 0.0,
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(16.0, 4.0, 16.0, 0.0),
child: Text(
'NASA partners with Amazon Web Services (AWS) to offer high-value scientific datasets for faster research. The data spans multiple fields and is suitable for AI training, supporting NASA\'s commitment to open science.sss',
style: FlutterFlowTheme.of(context).labelMedium.override(
fontFamily: 'Inter',
fontSize: 19.0,
letterSpacing: 0.0,
),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,16 @@
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/flutter_flow/flutter_flow_widgets.dart';
import 'card38_location_details_widget.dart' show Card38LocationDetailsWidget;
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
class Card38LocationDetailsModel
extends FlutterFlowModel<Card38LocationDetailsWidget> {
@override
void initState(BuildContext context) {}
@override
void dispose() {}
}

View File

@@ -0,0 +1,208 @@
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import '/flutter_flow/flutter_flow_widgets.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'card38_location_details_model.dart';
export 'card38_location_details_model.dart';
class Card38LocationDetailsWidget extends StatefulWidget {
const Card38LocationDetailsWidget({super.key});
@override
State<Card38LocationDetailsWidget> createState() =>
_Card38LocationDetailsWidgetState();
}
class _Card38LocationDetailsWidgetState
extends State<Card38LocationDetailsWidget> {
late Card38LocationDetailsModel _model;
@override
void setState(VoidCallback callback) {
super.setState(callback);
_model.onUpdate();
}
@override
void initState() {
super.initState();
_model = createModel(context, () => Card38LocationDetailsModel());
}
@override
void dispose() {
_model.maybeDispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsetsDirectional.fromSTEB(16.0, 0.0, 16.0, 12.0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: FlutterFlowTheme.of(context).secondaryBackground,
boxShadow: [
BoxShadow(
blurRadius: 3.0,
color: Color(0x33000000),
offset: Offset(
0.0,
1.0,
),
)
],
borderRadius: BorderRadius.circular(12.0),
),
child: Padding(
padding: EdgeInsets.all(12.0),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: Image.asset(
'assets/images/VZIc6KAR_400x400.jpg',
width: 94.0,
height: 93.0,
fit: BoxFit.cover,
),
),
Expanded(
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(12.0, 8.0, 0.0, 0.0),
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'NASA NEWS',
style:
FlutterFlowTheme.of(context).bodyLarge.override(
fontFamily: 'Inter',
fontSize: 21.0,
letterSpacing: 0.0,
fontWeight: FontWeight.bold,
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.0, 4.0, 0.0, 0.0),
child: SelectionArea(
child: Text(
'Astromaterials Data System',
style: FlutterFlowTheme.of(context)
.bodySmall
.override(
fontFamily: 'Inter',
color: Color(0xFFB40404),
fontSize: 23.0,
letterSpacing: 0.0,
fontWeight: FontWeight.bold,
),
)),
),
],
),
),
),
Icon(
Icons.check_circle_outline_rounded,
color: FlutterFlowTheme.of(context).secondaryText,
size: 24.0,
),
],
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0.0, 8.0, 0.0, 0.0),
child: Text(
'OSIRIS-REx has returned samples from asteroid Bennu, now available in NASA\'s Astromaterials Data System (Astromat). Explore data from Bennu, lunar samples, meteorites, and more with 40+ years of searchable archives',
style: FlutterFlowTheme.of(context).bodyLarge.override(
fontFamily: 'Inter',
fontSize: 21.0,
letterSpacing: 0.0,
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0.0, 0.0, 0.0, 4.0),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0.0, 8.0, 0.0, 0.0),
child: SelectionArea(
child: Text(
'Last Activity',
style: FlutterFlowTheme.of(context).labelSmall.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
),
)),
),
Expanded(
child: Align(
alignment: AlignmentDirectional(-1.0, 0.0),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
4.0, 8.0, 0.0, 0.0),
child: SelectionArea(
child: Text(
'Yesterday, 4:21pm',
textAlign: TextAlign.start,
style:
FlutterFlowTheme.of(context).bodySmall.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
),
)),
),
),
),
],
),
),
FFButtonWidget(
onPressed: () {
print('Button pressed ...');
},
text: 'NEWS',
options: FFButtonOptions(
height: 40.0,
padding: EdgeInsetsDirectional.fromSTEB(16.0, 0.0, 16.0, 0.0),
iconPadding:
EdgeInsetsDirectional.fromSTEB(0.0, 0.0, 0.0, 0.0),
color: Color(0xFFFFCF00),
textStyle: FlutterFlowTheme.of(context).titleSmall.override(
fontFamily: 'Inter Tight',
color: Colors.white,
letterSpacing: 0.0,
),
elevation: 2.0,
borderSide: BorderSide(
color: Colors.transparent,
width: 1.0,
),
borderRadius: BorderRadius.circular(8.0),
),
),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,14 @@
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import 'notifi_widget.dart' show NotifiWidget;
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
class NotifiModel extends FlutterFlowModel<NotifiWidget> {
@override
void initState(BuildContext context) {}
@override
void dispose() {}
}

View File

@@ -0,0 +1,185 @@
import '/flutter_flow/flutter_flow_theme.dart';
import '/flutter_flow/flutter_flow_util.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'notifi_model.dart';
export 'notifi_model.dart';
class NotifiWidget extends StatefulWidget {
const NotifiWidget({super.key});
@override
State<NotifiWidget> createState() => _NotifiWidgetState();
}
class _NotifiWidgetState extends State<NotifiWidget> {
late NotifiModel _model;
@override
void setState(VoidCallback callback) {
super.setState(callback);
_model.onUpdate();
}
@override
void initState() {
super.initState();
_model = createModel(context, () => NotifiModel());
}
@override
void dispose() {
_model.maybeDispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsetsDirectional.fromSTEB(16.0, 0.0, 16.0, 1.0),
child: Container(
width: double.infinity,
decoration: BoxDecoration(
color: FlutterFlowTheme.of(context).secondaryBackground,
boxShadow: [
BoxShadow(
blurRadius: 0.0,
color: FlutterFlowTheme.of(context).primaryBackground,
offset: Offset(
0.0,
1.0,
),
)
],
borderRadius: BorderRadius.circular(12.0),
),
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(16.0, 0.0, 16.0, 0.0),
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
flex: 4,
child: Padding(
padding:
EdgeInsetsDirectional.fromSTEB(0.0, 12.0, 12.0, 12.0),
child: Row(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 44.0,
height: 44.0,
decoration: BoxDecoration(
color: FlutterFlowTheme.of(context).primaryBackground,
shape: BoxShape.circle,
),
child: Padding(
padding: EdgeInsets.all(2.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(40.0),
child: Image.network(
'https://images.unsplash.com/photo-1474176857210-7287d38d27c6?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8NTB8fHVzZXJzfGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=900&q=60',
width: 36.0,
height: 36.0,
fit: BoxFit.cover,
),
),
),
),
Expanded(
child: Padding(
padding: EdgeInsetsDirectional.fromSTEB(
12.0, 0.0, 0.0, 0.0),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.0, 4.0, 0.0, 0.0),
child: Text(
'Andrew Hernandez',
style: FlutterFlowTheme.of(context)
.bodyLarge
.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
),
),
),
Text(
'Jan. 28th, 4:30pm',
style: FlutterFlowTheme.of(context)
.labelSmall
.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
),
),
],
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.0, 4.0, 0.0, 0.0),
child: Text(
'@username',
style: FlutterFlowTheme.of(context)
.bodySmall
.override(
fontFamily: 'Inter',
color: FlutterFlowTheme.of(context)
.primary,
letterSpacing: 0.0,
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(
0.0, 4.0, 0.0, 0.0),
child: Text(
'FlutterFlow is a visual development platform that allows you to easily create beautiful and responsive user interfaces for your mobile and web applications. ',
style: FlutterFlowTheme.of(context)
.labelSmall
.override(
fontFamily: 'Inter',
letterSpacing: 0.0,
),
),
),
],
),
),
),
],
),
),
),
Padding(
padding: EdgeInsetsDirectional.fromSTEB(0.0, 20.0, 0.0, 0.0),
child: Container(
width: 12.0,
height: 12.0,
decoration: BoxDecoration(
color: FlutterFlowTheme.of(context).secondary,
shape: BoxShape.circle,
),
alignment: AlignmentDirectional(0.0, 0.0),
),
),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,112 @@
import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
enum AnimationTrigger {
onPageLoad,
onActionTrigger,
}
class AnimationInfo {
AnimationInfo({
required this.trigger,
required this.effectsBuilder,
this.loop = false,
this.reverse = false,
this.applyInitialState = true,
});
final AnimationTrigger trigger;
final List<Effect> Function()? effectsBuilder;
final bool applyInitialState;
final bool loop;
final bool reverse;
late AnimationController controller;
List<Effect>? _effects;
List<Effect> get effects => _effects ??= effectsBuilder!();
void maybeUpdateEffects(List<Effect>? updatedEffects) {
if (updatedEffects != null) {
_effects = updatedEffects;
}
}
}
void createAnimation(AnimationInfo animation, TickerProvider vsync) {
final newController = AnimationController(vsync: vsync);
animation.controller = newController;
}
void setupAnimations(Iterable<AnimationInfo> animations, TickerProvider vsync) {
animations.forEach((animation) => createAnimation(animation, vsync));
}
extension AnimatedWidgetExtension on Widget {
Widget animateOnPageLoad(
AnimationInfo animationInfo, {
List<Effect>? effects,
}) {
animationInfo.maybeUpdateEffects(effects);
return Animate(
effects: animationInfo.effects,
child: this,
onPlay: (controller) => animationInfo.loop
? controller.repeat(reverse: animationInfo.reverse)
: null,
onComplete: (controller) => !animationInfo.loop && animationInfo.reverse
? controller.reverse()
: null,
);
}
Widget animateOnActionTrigger(
AnimationInfo animationInfo, {
List<Effect>? effects,
bool hasBeenTriggered = false,
}) {
animationInfo.maybeUpdateEffects(effects);
return hasBeenTriggered || animationInfo.applyInitialState
? Animate(
controller: animationInfo.controller,
autoPlay: false,
effects: animationInfo.effects,
child: this)
: this;
}
}
class TiltEffect extends Effect<Offset> {
const TiltEffect({
Duration? delay,
Duration? duration,
Curve? curve,
Offset? begin,
Offset? end,
}) : super(
delay: delay,
duration: duration,
curve: curve,
begin: begin ?? const Offset(0.0, 0.0),
end: end ?? const Offset(0.0, 0.0),
);
@override
Widget build(
BuildContext context,
Widget child,
AnimationController controller,
EffectEntry entry,
) {
Animation<Offset> animation = buildAnimation(controller, entry);
return getOptimizedBuilder<Offset>(
animation: animation,
builder: (_, __) => Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.001)
..rotateX(animation.value.dx)
..rotateY(animation.value.dy),
alignment: Alignment.center,
child: child,
),
);
}
}

View File

@@ -0,0 +1,325 @@
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:intl/intl.dart';
import 'package:table_calendar/table_calendar.dart';
DateTime kFirstDay = DateTime(1970, 1, 1);
DateTime kLastDay = DateTime(2100, 1, 1);
extension DateTimeExtension on DateTime {
DateTime get startOfDay => DateTime(year, month, day);
DateTime get endOfDay => DateTime(year, month, day, 23, 59);
}
class FlutterFlowCalendar extends StatefulWidget {
const FlutterFlowCalendar({
Key? key,
required this.color,
this.onChange,
this.initialDate,
this.weekFormat = false,
this.weekStartsMonday = false,
this.twoRowHeader = false,
this.iconColor,
this.dateStyle,
this.dayOfWeekStyle,
this.inactiveDateStyle,
this.selectedDateStyle,
this.titleStyle,
this.rowHeight,
this.locale,
}) : super(key: key);
final bool weekFormat;
final bool weekStartsMonday;
final bool twoRowHeader;
final Color color;
final void Function(DateTimeRange?)? onChange;
final DateTime? initialDate;
final Color? iconColor;
final TextStyle? dateStyle;
final TextStyle? dayOfWeekStyle;
final TextStyle? inactiveDateStyle;
final TextStyle? selectedDateStyle;
final TextStyle? titleStyle;
final double? rowHeight;
final String? locale;
@override
State<StatefulWidget> createState() => _FlutterFlowCalendarState();
}
class _FlutterFlowCalendarState extends State<FlutterFlowCalendar> {
late DateTime focusedDay;
late DateTime selectedDay;
late DateTimeRange selectedRange;
@override
void initState() {
super.initState();
focusedDay = widget.initialDate ?? DateTime.now();
selectedDay = widget.initialDate ?? DateTime.now();
selectedRange = DateTimeRange(
start: selectedDay.startOfDay,
end: selectedDay.endOfDay,
);
SchedulerBinding.instance
.addPostFrameCallback((_) => setSelectedDay(selectedRange.start));
}
CalendarFormat get calendarFormat =>
widget.weekFormat ? CalendarFormat.week : CalendarFormat.month;
StartingDayOfWeek get startingDayOfWeek => widget.weekStartsMonday
? StartingDayOfWeek.monday
: StartingDayOfWeek.sunday;
Color get color => widget.color;
Color get lightColor => widget.color.withOpacity(0.85);
Color get lighterColor => widget.color.withOpacity(0.60);
void setSelectedDay(
DateTime? newSelectedDay, [
DateTime? newSelectedEnd,
]) {
final newRange = newSelectedDay == null
? null
: DateTimeRange(
start: newSelectedDay.startOfDay,
end: newSelectedEnd ?? newSelectedDay.endOfDay,
);
setState(() {
selectedDay = newSelectedDay ?? selectedDay;
selectedRange = newRange ?? selectedRange;
if (widget.onChange != null) {
widget.onChange!(newRange);
}
});
}
@override
Widget build(BuildContext context) => Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
CalendarHeader(
focusedDay: focusedDay,
onLeftChevronTap: () => setState(
() => focusedDay = widget.weekFormat
? _previousWeek(focusedDay)
: _previousMonth(focusedDay),
),
onRightChevronTap: () => setState(
() => focusedDay = widget.weekFormat
? _nextWeek(focusedDay)
: _nextMonth(focusedDay),
),
onTodayButtonTap: () => setState(() => focusedDay = DateTime.now()),
titleStyle: widget.titleStyle,
iconColor: widget.iconColor,
locale: widget.locale,
twoRowHeader: widget.twoRowHeader,
),
TableCalendar(
focusedDay: focusedDay,
selectedDayPredicate: (date) => isSameDay(selectedDay, date),
firstDay: kFirstDay,
lastDay: kLastDay,
calendarFormat: calendarFormat,
headerVisible: false,
locale: widget.locale,
rowHeight: widget.rowHeight ?? MediaQuery.sizeOf(context).width / 7,
calendarStyle: CalendarStyle(
defaultTextStyle:
widget.dateStyle ?? const TextStyle(color: Color(0xFF5A5A5A)),
weekendTextStyle: widget.dateStyle ??
const TextStyle(color: const Color(0xFF5A5A5A)),
holidayTextStyle: widget.dateStyle ??
const TextStyle(color: const Color(0xFF5C6BC0)),
selectedTextStyle:
const TextStyle(color: Color(0xFFFAFAFA), fontSize: 16.0)
.merge(widget.selectedDateStyle),
todayTextStyle:
const TextStyle(color: Color(0xFFFAFAFA), fontSize: 16.0)
.merge(widget.selectedDateStyle),
outsideTextStyle: const TextStyle(color: Color(0xFF9E9E9E))
.merge(widget.inactiveDateStyle),
selectedDecoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
),
todayDecoration: BoxDecoration(
color: lighterColor,
shape: BoxShape.circle,
),
markerDecoration: BoxDecoration(
color: lightColor,
shape: BoxShape.circle,
),
markersMaxCount: 3,
canMarkersOverflow: true,
),
availableGestures: AvailableGestures.horizontalSwipe,
startingDayOfWeek: startingDayOfWeek,
daysOfWeekStyle: DaysOfWeekStyle(
weekdayStyle: const TextStyle(color: Color(0xFF616161))
.merge(widget.dayOfWeekStyle),
weekendStyle: const TextStyle(color: Color(0xFF616161))
.merge(widget.dayOfWeekStyle),
),
onPageChanged: (focused) {
if (focusedDay.startOfDay != focused.startOfDay) {
setState(() => focusedDay = focused);
}
},
onDaySelected: (newSelectedDay, focused) {
if (!isSameDay(selectedDay, newSelectedDay)) {
setSelectedDay(newSelectedDay);
if (focusedDay.startOfDay != focused.startOfDay) {
setState(() => focusedDay = focused);
}
}
},
),
],
);
}
class CalendarHeader extends StatelessWidget {
const CalendarHeader({
Key? key,
required this.focusedDay,
required this.onLeftChevronTap,
required this.onRightChevronTap,
required this.onTodayButtonTap,
this.iconColor,
this.titleStyle,
this.locale,
this.twoRowHeader = false,
}) : super(key: key);
final DateTime focusedDay;
final VoidCallback onLeftChevronTap;
final VoidCallback onRightChevronTap;
final VoidCallback onTodayButtonTap;
final Color? iconColor;
final TextStyle? titleStyle;
final String? locale;
final bool twoRowHeader;
@override
Widget build(BuildContext context) => Container(
decoration: const BoxDecoration(),
margin: const EdgeInsets.all(0),
padding: const EdgeInsets.symmetric(vertical: 8),
child: twoRowHeader ? _buildTwoRowHeader() : _buildOneRowHeader(),
);
Widget _buildTwoRowHeader() => Column(
children: [
Row(
mainAxisSize: MainAxisSize.max,
children: [
const SizedBox(width: 16),
_buildDateWidget(),
],
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: _buildCustomIconButtons(),
),
],
);
Widget _buildOneRowHeader() => Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
const SizedBox(width: 16),
_buildDateWidget(),
..._buildCustomIconButtons(),
],
);
Widget _buildDateWidget() => Expanded(
child: Text(
DateFormat.yMMMM(locale).format(focusedDay),
style: const TextStyle(fontSize: 17).merge(titleStyle),
),
);
List<Widget> _buildCustomIconButtons() => <Widget>[
CustomIconButton(
icon: Icon(Icons.calendar_today, color: iconColor),
onTap: onTodayButtonTap,
),
CustomIconButton(
icon: Icon(Icons.chevron_left, color: iconColor),
onTap: onLeftChevronTap,
),
CustomIconButton(
icon: Icon(Icons.chevron_right, color: iconColor),
onTap: onRightChevronTap,
),
];
}
class CustomIconButton extends StatelessWidget {
const CustomIconButton({
Key? key,
required this.icon,
required this.onTap,
this.margin = const EdgeInsets.symmetric(horizontal: 4),
this.padding = const EdgeInsets.all(10),
}) : super(key: key);
final Icon icon;
final VoidCallback onTap;
final EdgeInsetsGeometry margin;
final EdgeInsetsGeometry padding;
@override
Widget build(BuildContext context) => Padding(
padding: margin,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(100),
child: Padding(
padding: padding,
child: Icon(
icon.icon,
color: icon.color,
size: icon.size,
),
),
),
);
}
DateTime _previousWeek(DateTime week) {
return week.subtract(const Duration(days: 7));
}
DateTime _nextWeek(DateTime week) {
return week.add(const Duration(days: 7));
}
DateTime _previousMonth(DateTime month) {
if (month.month == 1) {
return DateTime(month.year - 1, 12);
} else {
return DateTime(month.year, month.month - 1);
}
}
DateTime _nextMonth(DateTime month) {
if (month.month == 12) {
return DateTime(month.year + 1, 1);
} else {
return DateTime(month.year, month.month + 1);
}
}

View File

@@ -0,0 +1,547 @@
import 'dart:math';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
export 'package:fl_chart/fl_chart.dart'
show BarAreaData, FlDotData, LineChartBarData, BarChartAlignment;
class FlutterFlowLineChart extends StatelessWidget {
const FlutterFlowLineChart({
Key? key,
required this.data,
required this.xAxisLabelInfo,
required this.yAxisLabelInfo,
required this.axisBounds,
this.chartStylingInfo = const ChartStylingInfo(),
}) : super(key: key);
final List<FFLineChartData> data;
final AxisLabelInfo xAxisLabelInfo;
final AxisLabelInfo yAxisLabelInfo;
final AxisBounds axisBounds;
final ChartStylingInfo chartStylingInfo;
List<LineChartBarData> get dataWithSpots =>
data.map((d) => d.settings.copyWith(spots: d.spots)).toList();
@override
Widget build(BuildContext context) => LineChart(
LineChartData(
lineTouchData: LineTouchData(
handleBuiltInTouches: chartStylingInfo.enableTooltip,
touchTooltipData: LineTouchTooltipData(
getTooltipColor: (group) =>
chartStylingInfo.tooltipBackgroundColor ?? Colors.black,
),
),
gridData: FlGridData(show: chartStylingInfo.showGrid),
borderData: FlBorderData(
border: Border.all(
color: chartStylingInfo.borderColor,
width: chartStylingInfo.borderWidth,
),
show: chartStylingInfo.showBorder,
),
titlesData: getTitlesData(
xAxisLabelInfo,
yAxisLabelInfo,
),
lineBarsData: dataWithSpots,
minX: axisBounds.minX,
minY: axisBounds.minY,
maxX: axisBounds.maxX,
maxY: axisBounds.maxY,
backgroundColor: chartStylingInfo.backgroundColor,
),
);
}
class FlutterFlowBarChart extends StatelessWidget {
const FlutterFlowBarChart({
Key? key,
required this.barData,
required this.xLabels,
required this.xAxisLabelInfo,
required this.yAxisLabelInfo,
required this.axisBounds,
this.stacked = false,
this.barWidth,
this.barBorderRadius,
this.barSpace,
this.groupSpace,
this.alignment = BarChartAlignment.center,
this.chartStylingInfo = const ChartStylingInfo(),
}) : super(key: key);
final List<FFBarChartData> barData;
final List<String> xLabels;
final AxisLabelInfo xAxisLabelInfo;
final AxisLabelInfo yAxisLabelInfo;
final AxisBounds axisBounds;
final bool stacked;
final double? barWidth;
final BorderRadius? barBorderRadius;
final double? barSpace;
final double? groupSpace;
final BarChartAlignment alignment;
final ChartStylingInfo chartStylingInfo;
Map<int, List<double>> get dataMap => xLabels.asMap().map((key, value) =>
MapEntry(key, barData.map((data) => data.data[key]).toList()));
List<BarChartGroupData> get groups => dataMap.entries.map((entry) {
final groupInt = entry.key;
final groupData = entry.value;
return BarChartGroupData(
x: groupInt,
barsSpace: barSpace,
barRods: groupData.asMap().entries.map((rod) {
final rodInt = rod.key;
final rodSettings = barData[rodInt];
final rodValue = rod.value;
return BarChartRodData(
toY: rodValue,
color: rodSettings.color,
width: barWidth,
borderRadius: barBorderRadius,
borderSide: BorderSide(
width: rodSettings.borderWidth,
color: rodSettings.borderColor,
),
);
}).toList());
}).toList();
List<BarChartGroupData> get stacks => dataMap.entries.map((entry) {
final groupInt = entry.key;
final stackData = entry.value;
return BarChartGroupData(
x: groupInt,
barsSpace: barSpace,
barRods: [
BarChartRodData(
toY: sum(stackData),
width: barWidth,
borderRadius: barBorderRadius,
rodStackItems: stackData.asMap().entries.map((stack) {
final stackInt = stack.key;
final stackSettings = barData[stackInt];
final start =
stackInt == 0 ? 0.0 : sum(stackData.sublist(0, stackInt));
return BarChartRodStackItem(
start,
start + stack.value,
stackSettings.color,
BorderSide(
width: stackSettings.borderWidth,
color: stackSettings.borderColor,
),
);
}).toList(),
)
],
);
}).toList();
double sum(List<double> list) => list.reduce((a, b) => a + b);
@override
Widget build(BuildContext context) {
return BarChart(
BarChartData(
barTouchData: BarTouchData(
handleBuiltInTouches: chartStylingInfo.enableTooltip,
touchTooltipData: BarTouchTooltipData(
getTooltipColor: (group) =>
chartStylingInfo.tooltipBackgroundColor ?? Colors.black,
),
),
alignment: alignment,
gridData: FlGridData(show: chartStylingInfo.showGrid),
borderData: FlBorderData(
border: Border.all(
color: chartStylingInfo.borderColor,
width: chartStylingInfo.borderWidth,
),
show: chartStylingInfo.showBorder,
),
titlesData: getTitlesData(
xAxisLabelInfo,
yAxisLabelInfo,
getXTitlesWidget: (val, _) => Text(
xLabels[val.toInt()],
style: xAxisLabelInfo.labelTextStyle,
),
),
barGroups: stacked ? stacks : groups,
groupsSpace: groupSpace,
minY: axisBounds.minY,
maxY: axisBounds.maxY,
backgroundColor: chartStylingInfo.backgroundColor,
),
);
}
}
enum PieChartSectionLabelType {
none,
value,
percent,
}
class FlutterFlowPieChart extends StatelessWidget {
const FlutterFlowPieChart({
Key? key,
required this.data,
this.donutHoleRadius = 0,
this.donutHoleColor = Colors.transparent,
this.sectionLabelType = PieChartSectionLabelType.none,
this.sectionLabelStyle,
this.labelFormatter = const LabelFormatter(),
}) : super(key: key);
final FFPieChartData data;
final double donutHoleRadius;
final Color donutHoleColor;
final PieChartSectionLabelType sectionLabelType;
final TextStyle? sectionLabelStyle;
final LabelFormatter labelFormatter;
double get sumOfValues => data.data.reduce((a, b) => a + b);
@override
Widget build(BuildContext context) => PieChart(
PieChartData(
centerSpaceRadius: donutHoleRadius,
centerSpaceColor: donutHoleColor,
sectionsSpace: 0,
sections: data.data.asMap().entries.map(
(section) {
String? title;
final index = section.key;
final sectionData = section.value;
final colorsLength = data.colors.length;
final otherPropsLength = data.radius.length;
switch (sectionLabelType) {
case PieChartSectionLabelType.value:
title = formatLabel(labelFormatter, sectionData);
break;
case PieChartSectionLabelType.percent:
title =
'${formatLabel(labelFormatter, sectionData / sumOfValues * 100)}%';
break;
default:
break;
}
return PieChartSectionData(
value: sectionData,
color: data.colors[index % colorsLength],
radius: otherPropsLength == 1
? data.radius.first
: data.radius[index],
borderSide: BorderSide(
color: (otherPropsLength == 1
? data.borderColor?.first
: data.borderColor?.elementAt(index)) ??
Colors.transparent,
width: (otherPropsLength == 1
? data.borderWidth?.first
: data.borderWidth?.elementAt(index)) ??
0.0,
),
showTitle: sectionLabelType != PieChartSectionLabelType.none,
titleStyle: sectionLabelStyle,
title: title,
);
},
).toList(),
),
);
}
class FlutterFlowChartLegendWidget extends StatelessWidget {
const FlutterFlowChartLegendWidget({
Key? key,
required this.entries,
this.width,
this.height,
this.textStyle,
this.padding,
this.backgroundColor = Colors.transparent,
this.borderRadius,
this.borderWidth = 1.0,
this.borderColor = const Color(0xFF000000),
this.indicatorSize = 10,
this.indicatorBorderRadius,
this.textPadding = const EdgeInsets.all(0),
}) : super(key: key);
final List<LegendEntry> entries;
final double? width;
final double? height;
final TextStyle? textStyle;
final EdgeInsetsGeometry? padding;
final Color backgroundColor;
final BorderRadius? borderRadius;
final double borderWidth;
final Color borderColor;
final double indicatorSize;
final BorderRadius? indicatorBorderRadius;
final EdgeInsetsGeometry textPadding;
@override
Widget build(BuildContext context) => Container(
width: width,
height: height,
padding: padding,
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: borderRadius,
border: Border.all(
color: borderColor,
width: borderWidth,
),
),
child: Column(
children: entries
.map(
(entry) => Row(
children: [
Container(
height: indicatorSize,
width: indicatorSize,
decoration: BoxDecoration(
color: entry.color,
borderRadius: indicatorBorderRadius,
),
),
Padding(
padding: textPadding,
child: Text(
entry.name,
style: textStyle,
),
)
],
),
)
.toList(),
),
);
}
class LegendEntry {
const LegendEntry(this.color, this.name);
final Color color;
final String name;
}
class ChartStylingInfo {
const ChartStylingInfo({
this.backgroundColor = Colors.white,
this.showGrid = false,
this.enableTooltip = false,
this.tooltipBackgroundColor,
this.borderColor = Colors.black,
this.borderWidth = 1.0,
this.showBorder = true,
});
final Color backgroundColor;
final bool showGrid;
final bool enableTooltip;
final Color? tooltipBackgroundColor;
final Color borderColor;
final double borderWidth;
final bool showBorder;
}
class AxisLabelInfo {
const AxisLabelInfo({
this.title = '',
this.titleTextStyle,
this.showLabels = false,
this.labelTextStyle,
this.labelInterval,
this.labelFormatter = const LabelFormatter(),
this.reservedSize,
});
final String title;
final TextStyle? titleTextStyle;
final bool showLabels;
final TextStyle? labelTextStyle;
final double? labelInterval;
final LabelFormatter labelFormatter;
final double? reservedSize;
}
class LabelFormatter {
const LabelFormatter({
this.numberFormat,
});
final String Function(double)? numberFormat;
NumberFormat get defaultFormat => NumberFormat()..significantDigits = 2;
}
class AxisBounds {
const AxisBounds({this.minX, this.minY, this.maxX, this.maxY});
final double? minX;
final double? minY;
final double? maxX;
final double? maxY;
}
class FFLineChartData {
const FFLineChartData({
required this.xData,
required this.yData,
required this.settings,
});
final List<dynamic> xData;
final List<dynamic> yData;
final LineChartBarData settings;
List<FlSpot> get spots {
final x = _dataToDouble(xData);
final y = _dataToDouble(yData);
assert(x.length == y.length, 'X and Y data must be the same length');
return Iterable<int>.generate(min(x.length, y.length))
.where((i) => x[i] != null && y[i] != null)
.map((i) => FlSpot(x[i]!, y[i]!))
.toList();
}
}
class FFBarChartData {
const FFBarChartData({
required this.yData,
required this.color,
this.borderWidth = 0,
this.borderColor = Colors.transparent,
});
final List<dynamic> yData;
final Color color;
final double borderWidth;
final Color borderColor;
List<double> get data => _dataToDouble(yData).map((e) => e ?? 0.0).toList();
}
class FFPieChartData {
const FFPieChartData({
required this.values,
required this.colors,
required this.radius,
this.borderWidth,
this.borderColor,
});
final List<dynamic> values;
final List<Color> colors;
final List<double> radius;
final List<double>? borderWidth;
final List<Color>? borderColor;
List<double> get data => _dataToDouble(values).map((e) => e ?? 0.0).toList();
}
List<double?> _dataToDouble(List<dynamic> data) {
if (data.isEmpty) {
return [];
}
if (data.first is double) {
return data.map((d) => d as double).toList();
}
if (data.first is int) {
return data.map((d) => (d as int).toDouble()).toList();
}
if (data.first is DateTime) {
return data
.map((d) => (d as DateTime).millisecondsSinceEpoch.toDouble())
.toList();
}
if (data.first is String) {
// First try to parse as doubles
if (double.tryParse(data.first as String) != null) {
return data.map((d) => double.tryParse(d as String)).toList();
}
if (int.tryParse(data.first as String) != null) {
return data.map((d) => int.tryParse(d as String)?.toDouble()).toList();
}
if (DateTime.tryParse(data.first as String) != null) {
return data
.map((d) =>
DateTime.tryParse(d as String)?.millisecondsSinceEpoch.toDouble())
.toList();
}
}
return [];
}
FlTitlesData getTitlesData(
AxisLabelInfo xAxisLabelInfo,
AxisLabelInfo yAxisLabelInfo, {
Widget Function(double, TitleMeta)? getXTitlesWidget,
}) =>
FlTitlesData(
bottomTitles: AxisTitles(
axisNameWidget: xAxisLabelInfo.title.isEmpty
? null
: Text(
xAxisLabelInfo.title,
style: xAxisLabelInfo.titleTextStyle,
),
axisNameSize: xAxisLabelInfo.titleTextStyle?.fontSize != null
? xAxisLabelInfo.titleTextStyle!.fontSize! + 12
: 16,
sideTitles: SideTitles(
getTitlesWidget: (val, _) => getXTitlesWidget != null
? getXTitlesWidget(val, _)
: Text(
formatLabel(xAxisLabelInfo.labelFormatter, val),
style: xAxisLabelInfo.labelTextStyle,
),
showTitles: xAxisLabelInfo.showLabels,
interval: xAxisLabelInfo.labelInterval,
reservedSize: xAxisLabelInfo.reservedSize ?? 22,
),
),
rightTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
topTitles: AxisTitles(sideTitles: SideTitles(showTitles: false)),
leftTitles: AxisTitles(
axisNameWidget: yAxisLabelInfo.title.isEmpty
? null
: Text(
yAxisLabelInfo.title,
style: yAxisLabelInfo.titleTextStyle,
),
axisNameSize: yAxisLabelInfo.titleTextStyle?.fontSize != null
? yAxisLabelInfo.titleTextStyle!.fontSize! + 12
: 16,
sideTitles: SideTitles(
getTitlesWidget: (val, _) => Text(
formatLabel(yAxisLabelInfo.labelFormatter, val),
style: yAxisLabelInfo.labelTextStyle,
),
showTitles: yAxisLabelInfo.showLabels,
interval: yAxisLabelInfo.labelInterval,
reservedSize: yAxisLabelInfo.reservedSize ?? 22,
),
),
);
String formatLabel(LabelFormatter formatter, double value) {
if (formatter.numberFormat != null) {
return formatter.numberFormat!(value);
}
return formatter.defaultFormat.format(value);
}

View File

@@ -0,0 +1,170 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class FlutterFlowIconButton extends StatefulWidget {
const FlutterFlowIconButton({
Key? key,
required this.icon,
this.borderColor,
this.borderRadius,
this.borderWidth,
this.buttonSize,
this.fillColor,
this.disabledColor,
this.disabledIconColor,
this.hoverColor,
this.hoverIconColor,
this.onPressed,
this.showLoadingIndicator = false,
}) : super(key: key);
final Widget icon;
final double? borderRadius;
final double? buttonSize;
final Color? fillColor;
final Color? disabledColor;
final Color? disabledIconColor;
final Color? hoverColor;
final Color? hoverIconColor;
final Color? borderColor;
final double? borderWidth;
final bool showLoadingIndicator;
final Function()? onPressed;
@override
State<FlutterFlowIconButton> createState() => _FlutterFlowIconButtonState();
}
class _FlutterFlowIconButtonState extends State<FlutterFlowIconButton> {
bool loading = false;
late double? iconSize;
late Color? iconColor;
late Widget effectiveIcon;
@override
void initState() {
super.initState();
_updateIcon();
}
@override
void didUpdateWidget(FlutterFlowIconButton oldWidget) {
super.didUpdateWidget(oldWidget);
_updateIcon();
}
void _updateIcon() {
final isFontAwesome = widget.icon is FaIcon;
if (isFontAwesome) {
FaIcon icon = widget.icon as FaIcon;
effectiveIcon = FaIcon(
icon.icon,
size: icon.size,
);
iconSize = icon.size;
iconColor = icon.color;
} else {
Icon icon = widget.icon as Icon;
effectiveIcon = Icon(
icon.icon,
size: icon.size,
);
iconSize = icon.size;
iconColor = icon.color;
}
}
@override
Widget build(BuildContext context) {
ButtonStyle style = ButtonStyle(
shape: MaterialStateProperty.resolveWith<OutlinedBorder>(
(states) {
return RoundedRectangleBorder(
borderRadius: BorderRadius.circular(widget.borderRadius ?? 0),
side: BorderSide(
color: widget.borderColor ?? Colors.transparent,
width: widget.borderWidth ?? 0,
),
);
},
),
iconColor: MaterialStateProperty.resolveWith<Color?>(
(states) {
if (states.contains(MaterialState.disabled) &&
widget.disabledIconColor != null) {
return widget.disabledIconColor;
}
if (states.contains(MaterialState.hovered) &&
widget.hoverIconColor != null) {
return widget.hoverIconColor;
}
return iconColor;
},
),
backgroundColor: MaterialStateProperty.resolveWith<Color?>(
(states) {
if (states.contains(MaterialState.disabled) &&
widget.disabledColor != null) {
return widget.disabledColor;
}
if (states.contains(MaterialState.hovered) &&
widget.hoverColor != null) {
return widget.hoverColor;
}
return widget.fillColor;
},
),
overlayColor: MaterialStateProperty.resolveWith<Color?>((states) {
if (states.contains(MaterialState.pressed)) {
return null;
}
return widget.hoverColor == null ? null : Colors.transparent;
}),
);
return SizedBox(
width: widget.buttonSize,
height: widget.buttonSize,
child: Theme(
data: ThemeData.from(
colorScheme: Theme.of(context).colorScheme,
useMaterial3: true,
),
child: IgnorePointer(
ignoring: (widget.showLoadingIndicator && loading),
child: IconButton(
icon: (widget.showLoadingIndicator && loading)
? Container(
width: iconSize,
height: iconSize,
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
iconColor ?? Colors.white,
),
),
)
: effectiveIcon,
onPressed: widget.onPressed == null
? null
: () async {
if (loading) {
return;
}
setState(() => loading = true);
try {
await widget.onPressed!();
} finally {
if (mounted) {
setState(() => loading = false);
}
}
},
splashRadius: widget.buttonSize,
style: style,
),
),
),
);
}
}

View File

@@ -0,0 +1,168 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:provider/provider.dart';
import 'flutter_flow_util.dart';
Widget wrapWithModel<T extends FlutterFlowModel>({
required T model,
required Widget child,
required VoidCallback updateCallback,
bool updateOnChange = false,
}) {
// Set the component to optionally update the page on updates.
model.setOnUpdate(
onUpdate: updateCallback,
updateOnChange: updateOnChange,
);
// Models for components within a page will be disposed by the page's model,
// so we don't want the component widget to dispose them until the page is
// itself disposed.
model.disposeOnWidgetDisposal = false;
// Wrap in a Provider so that the model can be accessed by the component.
return Provider<T>.value(
value: model,
child: child,
);
}
T createModel<T extends FlutterFlowModel>(
BuildContext context,
T Function() defaultBuilder,
) {
final model = context.read<T?>() ?? defaultBuilder();
model._init(context);
return model;
}
abstract class FlutterFlowModel<W extends Widget> {
// Initialization methods
bool _isInitialized = false;
void initState(BuildContext context);
void _init(BuildContext context) {
if (!_isInitialized) {
initState(context);
_isInitialized = true;
}
if (context.widget is W) _widget = context.widget as W;
}
// The widget associated with this model. This is useful for accessing the
// parameters of the widget, for example.
W? _widget;
W? get widget => _widget;
// Dispose methods
// Whether to dispose this model when the corresponding widget is
// disposed. By default this is true for pages and false for components,
// as page/component models handle the disposal of their children.
bool disposeOnWidgetDisposal = true;
void dispose();
void maybeDispose() {
if (disposeOnWidgetDisposal) {
dispose();
}
// Remove reference to widget for garbage collection purposes.
_widget = null;
}
// Whether to update the containing page / component on updates.
bool updateOnChange = false;
// Function to call when the model receives an update.
VoidCallback _updateCallback = () {};
void onUpdate() => updateOnChange ? _updateCallback() : () {};
FlutterFlowModel setOnUpdate({
bool updateOnChange = false,
required VoidCallback onUpdate,
}) =>
this
.._updateCallback = onUpdate
..updateOnChange = updateOnChange;
// Update the containing page when this model received an update.
void updatePage(VoidCallback callback) {
callback();
_updateCallback();
}
}
class FlutterFlowDynamicModels<T extends FlutterFlowModel> {
FlutterFlowDynamicModels(this.defaultBuilder);
final T Function() defaultBuilder;
final Map<String, T> _childrenModels = {};
final Map<String, int> _childrenIndexes = {};
Set<String>? _activeKeys;
T getModel(String uniqueKey, int index) {
_updateActiveKeys(uniqueKey);
_childrenIndexes[uniqueKey] = index;
return _childrenModels[uniqueKey] ??= defaultBuilder();
}
List<S> getValues<S>(S? Function(T) getValue) {
return _childrenIndexes.entries
// Sort keys by index.
.sorted((a, b) => a.value.compareTo(b.value))
.where((e) => _childrenModels[e.key] != null)
// Map each model to the desired value and return as list. In order
// to preserve index order, rather than removing null values we provide
// default values (for types with reasonable defaults).
.map((e) => getValue(_childrenModels[e.key]!) ?? _getDefaultValue<S>()!)
.toList();
}
S? getValueAtIndex<S>(int index, S? Function(T) getValue) {
final uniqueKey =
_childrenIndexes.entries.firstWhereOrNull((e) => e.value == index)?.key;
return getValueForKey(uniqueKey, getValue);
}
S? getValueForKey<S>(String? uniqueKey, S? Function(T) getValue) {
final model = _childrenModels[uniqueKey];
return model != null ? getValue(model) : null;
}
void dispose() => _childrenModels.values.forEach((model) => model.dispose());
void _updateActiveKeys(String uniqueKey) {
final shouldResetActiveKeys = _activeKeys == null;
_activeKeys ??= {};
_activeKeys!.add(uniqueKey);
if (shouldResetActiveKeys) {
// Add a post-frame callback to remove and dispose of unused models after
// we're done building, then reset `_activeKeys` to null so we know to do
// this again next build.
SchedulerBinding.instance.addPostFrameCallback((_) {
_childrenIndexes.removeWhere((k, _) => !_activeKeys!.contains(k));
_childrenModels.keys
.toSet()
.difference(_activeKeys!)
// Remove and dispose of unused models since they are not being used
// elsewhere and would not otherwise be disposed.
.forEach((k) => _childrenModels.remove(k)?.maybeDispose());
_activeKeys = null;
});
}
}
}
T? _getDefaultValue<T>() {
switch (T) {
case int:
return 0 as T;
case double:
return 0.0 as T;
case String:
return '' as T;
case bool:
return false as T;
default:
return null as T;
}
}
extension TextValidationExtensions on String? Function(BuildContext, String?)? {
String? Function(String?)? asValidator(BuildContext context) =>
this != null ? (val) => this!(context, val) : null;
}

View File

@@ -0,0 +1,353 @@
// ignore_for_file: overridden_fields, annotate_overrides
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart';
const kThemeModeKey = '__theme_mode__';
SharedPreferences? _prefs;
abstract class FlutterFlowTheme {
static Future initialize() async =>
_prefs = await SharedPreferences.getInstance();
static ThemeMode get themeMode {
final darkMode = _prefs?.getBool(kThemeModeKey);
return darkMode == null
? ThemeMode.system
: darkMode
? ThemeMode.dark
: ThemeMode.light;
}
static void saveThemeMode(ThemeMode mode) => mode == ThemeMode.system
? _prefs?.remove(kThemeModeKey)
: _prefs?.setBool(kThemeModeKey, mode == ThemeMode.dark);
static FlutterFlowTheme of(BuildContext context) {
return Theme.of(context).brightness == Brightness.dark
? DarkModeTheme()
: LightModeTheme();
}
@Deprecated('Use primary instead')
Color get primaryColor => primary;
@Deprecated('Use secondary instead')
Color get secondaryColor => secondary;
@Deprecated('Use tertiary instead')
Color get tertiaryColor => tertiary;
late Color primary;
late Color secondary;
late Color tertiary;
late Color alternate;
late Color primaryText;
late Color secondaryText;
late Color primaryBackground;
late Color secondaryBackground;
late Color accent1;
late Color accent2;
late Color accent3;
late Color accent4;
late Color success;
late Color warning;
late Color error;
late Color info;
@Deprecated('Use displaySmallFamily instead')
String get title1Family => displaySmallFamily;
@Deprecated('Use displaySmall instead')
TextStyle get title1 => typography.displaySmall;
@Deprecated('Use headlineMediumFamily instead')
String get title2Family => typography.headlineMediumFamily;
@Deprecated('Use headlineMedium instead')
TextStyle get title2 => typography.headlineMedium;
@Deprecated('Use headlineSmallFamily instead')
String get title3Family => typography.headlineSmallFamily;
@Deprecated('Use headlineSmall instead')
TextStyle get title3 => typography.headlineSmall;
@Deprecated('Use titleMediumFamily instead')
String get subtitle1Family => typography.titleMediumFamily;
@Deprecated('Use titleMedium instead')
TextStyle get subtitle1 => typography.titleMedium;
@Deprecated('Use titleSmallFamily instead')
String get subtitle2Family => typography.titleSmallFamily;
@Deprecated('Use titleSmall instead')
TextStyle get subtitle2 => typography.titleSmall;
@Deprecated('Use bodyMediumFamily instead')
String get bodyText1Family => typography.bodyMediumFamily;
@Deprecated('Use bodyMedium instead')
TextStyle get bodyText1 => typography.bodyMedium;
@Deprecated('Use bodySmallFamily instead')
String get bodyText2Family => typography.bodySmallFamily;
@Deprecated('Use bodySmall instead')
TextStyle get bodyText2 => typography.bodySmall;
String get displayLargeFamily => typography.displayLargeFamily;
TextStyle get displayLarge => typography.displayLarge;
String get displayMediumFamily => typography.displayMediumFamily;
TextStyle get displayMedium => typography.displayMedium;
String get displaySmallFamily => typography.displaySmallFamily;
TextStyle get displaySmall => typography.displaySmall;
String get headlineLargeFamily => typography.headlineLargeFamily;
TextStyle get headlineLarge => typography.headlineLarge;
String get headlineMediumFamily => typography.headlineMediumFamily;
TextStyle get headlineMedium => typography.headlineMedium;
String get headlineSmallFamily => typography.headlineSmallFamily;
TextStyle get headlineSmall => typography.headlineSmall;
String get titleLargeFamily => typography.titleLargeFamily;
TextStyle get titleLarge => typography.titleLarge;
String get titleMediumFamily => typography.titleMediumFamily;
TextStyle get titleMedium => typography.titleMedium;
String get titleSmallFamily => typography.titleSmallFamily;
TextStyle get titleSmall => typography.titleSmall;
String get labelLargeFamily => typography.labelLargeFamily;
TextStyle get labelLarge => typography.labelLarge;
String get labelMediumFamily => typography.labelMediumFamily;
TextStyle get labelMedium => typography.labelMedium;
String get labelSmallFamily => typography.labelSmallFamily;
TextStyle get labelSmall => typography.labelSmall;
String get bodyLargeFamily => typography.bodyLargeFamily;
TextStyle get bodyLarge => typography.bodyLarge;
String get bodyMediumFamily => typography.bodyMediumFamily;
TextStyle get bodyMedium => typography.bodyMedium;
String get bodySmallFamily => typography.bodySmallFamily;
TextStyle get bodySmall => typography.bodySmall;
Typography get typography => ThemeTypography(this);
}
class LightModeTheme extends FlutterFlowTheme {
@Deprecated('Use primary instead')
Color get primaryColor => primary;
@Deprecated('Use secondary instead')
Color get secondaryColor => secondary;
@Deprecated('Use tertiary instead')
Color get tertiaryColor => tertiary;
late Color primary = const Color(0xFF4B39EF);
late Color secondary = const Color(0xFF39D2C0);
late Color tertiary = const Color(0xFFEE8B60);
late Color alternate = const Color(0xFFE0E3E7);
late Color primaryText = const Color(0xFF14181B);
late Color secondaryText = const Color(0xFF57636C);
late Color primaryBackground = const Color(0xFFF1F4F8);
late Color secondaryBackground = const Color(0xFFFFFFFF);
late Color accent1 = const Color(0x4C4B39EF);
late Color accent2 = const Color(0x4D39D2C0);
late Color accent3 = const Color(0x4DEE8B60);
late Color accent4 = const Color(0xCCFFFFFF);
late Color success = const Color(0xFF249689);
late Color warning = const Color(0xFFF9CF58);
late Color error = const Color(0xFFFF5963);
late Color info = const Color(0xFFFFFFFF);
}
abstract class Typography {
String get displayLargeFamily;
TextStyle get displayLarge;
String get displayMediumFamily;
TextStyle get displayMedium;
String get displaySmallFamily;
TextStyle get displaySmall;
String get headlineLargeFamily;
TextStyle get headlineLarge;
String get headlineMediumFamily;
TextStyle get headlineMedium;
String get headlineSmallFamily;
TextStyle get headlineSmall;
String get titleLargeFamily;
TextStyle get titleLarge;
String get titleMediumFamily;
TextStyle get titleMedium;
String get titleSmallFamily;
TextStyle get titleSmall;
String get labelLargeFamily;
TextStyle get labelLarge;
String get labelMediumFamily;
TextStyle get labelMedium;
String get labelSmallFamily;
TextStyle get labelSmall;
String get bodyLargeFamily;
TextStyle get bodyLarge;
String get bodyMediumFamily;
TextStyle get bodyMedium;
String get bodySmallFamily;
TextStyle get bodySmall;
}
class ThemeTypography extends Typography {
ThemeTypography(this.theme);
final FlutterFlowTheme theme;
String get displayLargeFamily => 'Inter Tight';
TextStyle get displayLarge => GoogleFonts.getFont(
'Inter Tight',
color: theme.primaryText,
fontWeight: FontWeight.w600,
fontSize: 64.0,
);
String get displayMediumFamily => 'Inter Tight';
TextStyle get displayMedium => GoogleFonts.getFont(
'Inter Tight',
color: theme.primaryText,
fontWeight: FontWeight.w600,
fontSize: 44.0,
);
String get displaySmallFamily => 'Inter Tight';
TextStyle get displaySmall => GoogleFonts.getFont(
'Inter Tight',
color: theme.primaryText,
fontWeight: FontWeight.w600,
fontSize: 36.0,
);
String get headlineLargeFamily => 'Inter Tight';
TextStyle get headlineLarge => GoogleFonts.getFont(
'Inter Tight',
color: theme.primaryText,
fontWeight: FontWeight.w600,
fontSize: 32.0,
);
String get headlineMediumFamily => 'Inter Tight';
TextStyle get headlineMedium => GoogleFonts.getFont(
'Inter Tight',
color: theme.primaryText,
fontWeight: FontWeight.w600,
fontSize: 28.0,
);
String get headlineSmallFamily => 'Inter Tight';
TextStyle get headlineSmall => GoogleFonts.getFont(
'Inter Tight',
color: theme.primaryText,
fontWeight: FontWeight.w600,
fontSize: 24.0,
);
String get titleLargeFamily => 'Inter Tight';
TextStyle get titleLarge => GoogleFonts.getFont(
'Inter Tight',
color: theme.primaryText,
fontWeight: FontWeight.w600,
fontSize: 20.0,
);
String get titleMediumFamily => 'Inter Tight';
TextStyle get titleMedium => GoogleFonts.getFont(
'Inter Tight',
color: theme.primaryText,
fontWeight: FontWeight.w600,
fontSize: 18.0,
);
String get titleSmallFamily => 'Inter Tight';
TextStyle get titleSmall => GoogleFonts.getFont(
'Inter Tight',
color: theme.primaryText,
fontWeight: FontWeight.w600,
fontSize: 16.0,
);
String get labelLargeFamily => 'Inter';
TextStyle get labelLarge => GoogleFonts.getFont(
'Inter',
color: theme.secondaryText,
fontWeight: FontWeight.normal,
fontSize: 16.0,
);
String get labelMediumFamily => 'Inter';
TextStyle get labelMedium => GoogleFonts.getFont(
'Inter',
color: theme.secondaryText,
fontWeight: FontWeight.normal,
fontSize: 14.0,
);
String get labelSmallFamily => 'Inter';
TextStyle get labelSmall => GoogleFonts.getFont(
'Inter',
color: theme.secondaryText,
fontWeight: FontWeight.normal,
fontSize: 12.0,
);
String get bodyLargeFamily => 'Inter';
TextStyle get bodyLarge => GoogleFonts.getFont(
'Inter',
color: theme.primaryText,
fontWeight: FontWeight.normal,
fontSize: 16.0,
);
String get bodyMediumFamily => 'Inter';
TextStyle get bodyMedium => GoogleFonts.getFont(
'Inter',
color: theme.primaryText,
fontWeight: FontWeight.normal,
fontSize: 14.0,
);
String get bodySmallFamily => 'Inter';
TextStyle get bodySmall => GoogleFonts.getFont(
'Inter',
color: theme.primaryText,
fontWeight: FontWeight.normal,
fontSize: 12.0,
);
}
class DarkModeTheme extends FlutterFlowTheme {
@Deprecated('Use primary instead')
Color get primaryColor => primary;
@Deprecated('Use secondary instead')
Color get secondaryColor => secondary;
@Deprecated('Use tertiary instead')
Color get tertiaryColor => tertiary;
late Color primary = const Color(0xFF4B39EF);
late Color secondary = const Color(0xFF39D2C0);
late Color tertiary = const Color(0xFFEE8B60);
late Color alternate = const Color(0xFF262D34);
late Color primaryText = const Color(0xFFFFFFFF);
late Color secondaryText = const Color(0xFF95A1AC);
late Color primaryBackground = const Color(0xFF1D2428);
late Color secondaryBackground = const Color(0xFF14181B);
late Color accent1 = const Color(0x4C4B39EF);
late Color accent2 = const Color(0x4D39D2C0);
late Color accent3 = const Color(0x4DEE8B60);
late Color accent4 = const Color(0xB2262D34);
late Color success = const Color(0xFF249689);
late Color warning = const Color(0xFFF9CF58);
late Color error = const Color(0xFFFF5963);
late Color info = const Color(0xFFFFFFFF);
}
extension TextStyleHelper on TextStyle {
TextStyle override({
String? fontFamily,
Color? color,
double? fontSize,
FontWeight? fontWeight,
double? letterSpacing,
FontStyle? fontStyle,
bool useGoogleFonts = true,
TextDecoration? decoration,
double? lineHeight,
List<Shadow>? shadows,
}) =>
useGoogleFonts
? GoogleFonts.getFont(
fontFamily!,
color: color ?? this.color,
fontSize: fontSize ?? this.fontSize,
letterSpacing: letterSpacing ?? this.letterSpacing,
fontWeight: fontWeight ?? this.fontWeight,
fontStyle: fontStyle ?? this.fontStyle,
decoration: decoration,
height: lineHeight,
shadows: shadows,
)
: copyWith(
fontFamily: fontFamily,
color: color,
fontSize: fontSize,
letterSpacing: letterSpacing,
fontWeight: fontWeight,
fontStyle: fontStyle,
decoration: decoration,
height: lineHeight,
shadows: shadows,
);
}

View File

@@ -0,0 +1,427 @@
import 'dart:io';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:collection/collection.dart';
import 'package:from_css_color/from_css_color.dart';
import 'dart:math' show pow, pi, sin;
import 'package:intl/intl.dart';
import 'package:json_path/json_path.dart';
import 'package:timeago/timeago.dart' as timeago;
import 'package:url_launcher/url_launcher.dart';
import '../main.dart';
import 'lat_lng.dart';
export 'lat_lng.dart';
export 'place.dart';
export 'uploaded_file.dart';
export 'flutter_flow_model.dart';
export 'dart:math' show min, max;
export 'dart:typed_data' show Uint8List;
export 'dart:convert' show jsonEncode, jsonDecode;
export 'package:intl/intl.dart';
export 'package:page_transition/page_transition.dart';
export 'nav/nav.dart';
T valueOrDefault<T>(T? value, T defaultValue) =>
(value is String && value.isEmpty) || value == null ? defaultValue : value;
String dateTimeFormat(String format, DateTime? dateTime, {String? locale}) {
if (dateTime == null) {
return '';
}
if (format == 'relative') {
return timeago.format(dateTime, locale: locale, allowFromNow: true);
}
return DateFormat(format, locale).format(dateTime);
}
Future launchURL(String url) async {
var uri = Uri.parse(url);
try {
await launchUrl(uri);
} catch (e) {
throw 'Could not launch $uri: $e';
}
}
Color colorFromCssString(String color, {Color? defaultColor}) {
try {
return fromCssColor(color);
} catch (_) {}
return defaultColor ?? Colors.black;
}
enum FormatType {
decimal,
percent,
scientific,
compact,
compactLong,
custom,
}
enum DecimalType {
automatic,
periodDecimal,
commaDecimal,
}
String formatNumber(
num? value, {
required FormatType formatType,
DecimalType? decimalType,
String? currency,
bool toLowerCase = false,
String? format,
String? locale,
}) {
if (value == null) {
return '';
}
var formattedValue = '';
switch (formatType) {
case FormatType.decimal:
switch (decimalType!) {
case DecimalType.automatic:
formattedValue = NumberFormat.decimalPattern().format(value);
break;
case DecimalType.periodDecimal:
if (currency != null) {
formattedValue = NumberFormat('#,##0.00', 'en_US').format(value);
} else {
formattedValue = NumberFormat.decimalPattern('en_US').format(value);
}
break;
case DecimalType.commaDecimal:
if (currency != null) {
formattedValue = NumberFormat('#,##0.00', 'es_PA').format(value);
} else {
formattedValue = NumberFormat.decimalPattern('es_PA').format(value);
}
break;
}
break;
case FormatType.percent:
formattedValue = NumberFormat.percentPattern().format(value);
break;
case FormatType.scientific:
formattedValue = NumberFormat.scientificPattern().format(value);
if (toLowerCase) {
formattedValue = formattedValue.toLowerCase();
}
break;
case FormatType.compact:
formattedValue = NumberFormat.compact().format(value);
break;
case FormatType.compactLong:
formattedValue = NumberFormat.compactLong().format(value);
break;
case FormatType.custom:
final hasLocale = locale != null && locale.isNotEmpty;
formattedValue =
NumberFormat(format, hasLocale ? locale : null).format(value);
}
if (formattedValue.isEmpty) {
return value.toString();
}
if (currency != null) {
final currencySymbol = currency.isNotEmpty
? currency
: NumberFormat.simpleCurrency().format(0.0).substring(0, 1);
formattedValue = '$currencySymbol$formattedValue';
}
return formattedValue;
}
DateTime get getCurrentTimestamp => DateTime.now();
DateTime dateTimeFromSecondsSinceEpoch(int seconds) {
return DateTime.fromMillisecondsSinceEpoch(seconds * 1000);
}
extension DateTimeConversionExtension on DateTime {
int get secondsSinceEpoch => (millisecondsSinceEpoch / 1000).round();
}
extension DateTimeComparisonOperators on DateTime {
bool operator <(DateTime other) => isBefore(other);
bool operator >(DateTime other) => isAfter(other);
bool operator <=(DateTime other) => this < other || isAtSameMomentAs(other);
bool operator >=(DateTime other) => this > other || isAtSameMomentAs(other);
}
T? castToType<T>(dynamic value) {
if (value == null) {
return null;
}
switch (T) {
case double:
// Doubles may be stored as ints in some cases.
return value.toDouble() as T;
case int:
// Likewise, ints may be stored as doubles. If this is the case
// (i.e. no decimal value), return the value as an int.
if (value is num && value.toInt() == value) {
return value.toInt() as T;
}
break;
default:
break;
}
return value as T;
}
dynamic getJsonField(
dynamic response,
String jsonPath, [
bool isForList = false,
]) {
final field = JsonPath(jsonPath).read(response);
if (field.isEmpty) {
return null;
}
if (field.length > 1) {
return field.map((f) => f.value).toList();
}
final value = field.first.value;
if (isForList) {
return value is! Iterable
? [value]
: (value is List ? value : value.toList());
}
return value;
}
Rect? getWidgetBoundingBox(BuildContext context) {
try {
final renderBox = context.findRenderObject() as RenderBox?;
return renderBox!.localToGlobal(Offset.zero) & renderBox.size;
} catch (_) {
return null;
}
}
bool get isAndroid => !kIsWeb && Platform.isAndroid;
bool get isiOS => !kIsWeb && Platform.isIOS;
bool get isWeb => kIsWeb;
const kBreakpointSmall = 479.0;
const kBreakpointMedium = 767.0;
const kBreakpointLarge = 991.0;
bool isMobileWidth(BuildContext context) =>
MediaQuery.sizeOf(context).width < kBreakpointSmall;
bool responsiveVisibility({
required BuildContext context,
bool phone = true,
bool tablet = true,
bool tabletLandscape = true,
bool desktop = true,
}) {
final width = MediaQuery.sizeOf(context).width;
if (width < kBreakpointSmall) {
return phone;
} else if (width < kBreakpointMedium) {
return tablet;
} else if (width < kBreakpointLarge) {
return tabletLandscape;
} else {
return desktop;
}
}
const kTextValidatorUsernameRegex = r'^[a-zA-Z][a-zA-Z0-9_-]{2,16}$';
// https://stackoverflow.com/a/201378
const kTextValidatorEmailRegex =
"^(?:[a-zA-Z0-9!#\$%&\'*+/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#\$%&\'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])\$";
const kTextValidatorWebsiteRegex =
r'(https?:\/\/)?(www\.)[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,10}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)|(https?:\/\/)?(www\.)?(?!ww)[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,10}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)';
extension FFTextEditingControllerExt on TextEditingController? {
String get text => this == null ? '' : this!.text;
set text(String newText) => this?.text = newText;
}
extension IterableExt<T> on Iterable<T> {
List<T> sortedList<S extends Comparable>(
{S Function(T)? keyOf, bool desc = false}) {
final sortedAscending = toList()
..sort(keyOf == null ? null : ((a, b) => keyOf(a).compareTo(keyOf(b))));
if (desc) {
return sortedAscending.reversed.toList();
}
return sortedAscending;
}
List<S> mapIndexed<S>(S Function(int, T) func) => toList()
.asMap()
.map((index, value) => MapEntry(index, func(index, value)))
.values
.toList();
}
void setDarkModeSetting(BuildContext context, ThemeMode themeMode) =>
MyApp.of(context).setThemeMode(themeMode);
void showSnackbar(
BuildContext context,
String message, {
bool loading = false,
int duration = 4,
}) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Row(
children: [
if (loading)
Padding(
padding: EdgeInsetsDirectional.only(end: 10.0),
child: Container(
height: 20,
width: 20,
child: const CircularProgressIndicator(
color: Colors.white,
),
),
),
Text(message),
],
),
duration: Duration(seconds: duration),
),
);
}
extension FFStringExt on String {
String maybeHandleOverflow({int? maxChars, String replacement = ''}) =>
maxChars != null && length > maxChars
? replaceRange(maxChars, null, replacement)
: this;
}
extension ListFilterExt<T> on Iterable<T?> {
List<T> get withoutNulls => where((s) => s != null).map((e) => e!).toList();
}
extension MapFilterExtensions<T> on Map<String, T?> {
Map<String, T> get withoutNulls => Map.fromEntries(
entries
.where((e) => e.value != null)
.map((e) => MapEntry(e.key, e.value as T)),
);
}
extension MapListContainsExt on List<dynamic> {
bool containsMap(dynamic map) => map is Map
? any((e) => e is Map && const DeepCollectionEquality().equals(e, map))
: contains(map);
}
extension ListDivideExt<T extends Widget> on Iterable<T> {
Iterable<MapEntry<int, Widget>> get enumerate => toList().asMap().entries;
List<Widget> divide(Widget t, {bool Function(int)? filterFn}) => isEmpty
? []
: (enumerate
.map((e) => [e.value, if (filterFn == null || filterFn(e.key)) t])
.expand((i) => i)
.toList()
..removeLast());
List<Widget> around(Widget t) => addToStart(t).addToEnd(t);
List<Widget> addToStart(Widget t) =>
enumerate.map((e) => e.value).toList()..insert(0, t);
List<Widget> addToEnd(Widget t) =>
enumerate.map((e) => e.value).toList()..add(t);
List<Padding> paddingTopEach(double val) =>
map((w) => Padding(padding: EdgeInsets.only(top: val), child: w))
.toList();
}
extension StatefulWidgetExtensions on State<StatefulWidget> {
/// Check if the widget exist before safely setting state.
void safeSetState(VoidCallback fn) {
if (mounted) {
// ignore: invalid_use_of_protected_member
setState(fn);
}
}
}
// For iOS 16 and below, set the status bar color to match the app's theme.
// https://github.com/flutter/flutter/issues/41067
Brightness? _lastBrightness;
void fixStatusBarOniOS16AndBelow(BuildContext context) {
if (!isiOS) {
return;
}
final brightness = Theme.of(context).brightness;
if (_lastBrightness != brightness) {
_lastBrightness = brightness;
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarBrightness: brightness,
systemStatusBarContrastEnforced: true,
),
);
}
}
extension ListUniqueExt<T> on Iterable<T> {
List<T> unique(dynamic Function(T) getKey) {
var distinctSet = <dynamic>{};
var distinctList = <T>[];
for (var item in this) {
if (distinctSet.add(getKey(item))) {
distinctList.add(item);
}
}
return distinctList;
}
}
String roundTo(double value, int decimalPoints) {
final power = pow(10, decimalPoints);
return ((value * power).round() / power).toString();
}
double computeGradientAlignmentX(double evaluatedAngle) {
evaluatedAngle %= 360;
final rads = evaluatedAngle * pi / 180;
double x;
if (evaluatedAngle < 45 || evaluatedAngle > 315) {
x = sin(2 * rads);
} else if (45 <= evaluatedAngle && evaluatedAngle <= 135) {
x = 1;
} else if (135 <= evaluatedAngle && evaluatedAngle <= 225) {
x = sin(-2 * rads);
} else {
x = -1;
}
return double.parse(roundTo(x, 2));
}
double computeGradientAlignmentY(double evaluatedAngle) {
evaluatedAngle %= 360;
final rads = evaluatedAngle * pi / 180;
double y;
if (evaluatedAngle < 45 || evaluatedAngle > 315) {
y = -1;
} else if (45 <= evaluatedAngle && evaluatedAngle <= 135) {
y = sin(-2 * rads);
} else if (135 <= evaluatedAngle && evaluatedAngle <= 225) {
y = 1;
} else {
y = sin(2 * rads);
}
return double.parse(roundTo(y, 2));
}

View File

@@ -0,0 +1,119 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart' hide NavigationDecision;
import 'package:webview_flutter_android/webview_flutter_android.dart';
import 'package:webviewx_plus/webviewx_plus.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:file_picker/file_picker.dart';
import 'flutter_flow_util.dart';
class FlutterFlowWebView extends StatefulWidget {
const FlutterFlowWebView({
Key? key,
required this.content,
this.width,
this.height,
this.bypass = false,
this.horizontalScroll = false,
this.verticalScroll = false,
this.html = false,
}) : super(key: key);
final String content;
final double? height;
final double? width;
final bool bypass;
final bool horizontalScroll;
final bool verticalScroll;
final bool html;
@override
_FlutterFlowWebViewState createState() => _FlutterFlowWebViewState();
}
class _FlutterFlowWebViewState extends State<FlutterFlowWebView> {
@override
Widget build(BuildContext context) => WebViewX(
key: webviewKey,
width: widget.width ?? MediaQuery.sizeOf(context).width,
height: widget.height ?? MediaQuery.sizeOf(context).height,
ignoreAllGestures: false,
initialContent: widget.content,
initialMediaPlaybackPolicy:
AutoMediaPlaybackPolicy.requireUserActionForAllMediaTypes,
initialSourceType: widget.html
? SourceType.html
: widget.bypass
? SourceType.urlBypass
: SourceType.url,
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (controller) async {
if (controller.connector is WebViewController && isAndroid) {
final androidController =
controller.connector.platform as AndroidWebViewController;
await androidController.setOnShowFileSelector(_androidFilePicker);
}
},
navigationDelegate: (request) async {
if (isAndroid) {
if (request.content.source
.startsWith('https://api.whatsapp.com/send?phone')) {
String url = request.content.source;
await launchUrl(
Uri.parse(url),
mode: LaunchMode.externalApplication,
);
return NavigationDecision.prevent;
}
}
return NavigationDecision.navigate;
},
webSpecificParams: const WebSpecificParams(
webAllowFullscreenContent: true,
),
mobileSpecificParams: MobileSpecificParams(
debuggingEnabled: false,
gestureNavigationEnabled: true,
mobileGestureRecognizers: {
if (widget.verticalScroll)
Factory<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer(),
),
if (widget.horizontalScroll)
Factory<HorizontalDragGestureRecognizer>(
() => HorizontalDragGestureRecognizer(),
),
},
androidEnableHybridComposition: true,
),
);
Key get webviewKey => Key(
[
widget.content,
widget.width,
widget.height,
widget.bypass,
widget.horizontalScroll,
widget.verticalScroll,
widget.html,
].map((s) => s?.toString() ?? '').join(),
);
Future<List<String>> _androidFilePicker(
final FileSelectorParams params,
) async {
final result = await FilePicker.platform.pickFiles();
if (result != null && result.files.single.path != null) {
final file = File(result.files.single.path!);
return [file.uri.toString()];
}
return [];
}
}

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