@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "one-ai-mobile"]
|
||||||
|
path = one-ai-mobile
|
||||||
|
url = https://github.com/quaxlyqueen/one-ai-mobile
|
||||||
@@ -1,7 +1,20 @@
|
|||||||
Dependencies:
|
<h1>One AI</h1>
|
||||||
|
|
||||||
|
<h2>Description:</h2>
|
||||||
|
End-to-end solution for self-deploying a secure and private AI. Ideally, always using the latest and greatest open-source technologies available and optimizing the connection between them.
|
||||||
|
|
||||||
|
<h3>Dependencies:</h3>
|
||||||
|
|
||||||
|
```
|
||||||
pip install scipy pydub torch torchaudio wavio silero sounddevice;
|
pip install scipy pydub torch torchaudio wavio silero sounddevice;
|
||||||
|
```
|
||||||
|
|
||||||
Create output.txt file, TODO: Implement error handling.
|
<h3>Usage:</h3>
|
||||||
touch output.txt;
|
|
||||||
|
|
||||||
Currently, you have 5 seconds to record a prompt. It will automatically place "in 50 words or less" at the start of your prompt for faster testing. The Text To Speech (TTS) engine is not great quality, at least at first. Just getting the basic structure together, more to come...
|
<p>Currently, you have 5 seconds to record a prompt. It will automatically place "in 50 words or less" at the start of your prompt for faster testing. The Text To Speech (TTS) engine is not great quality, at least at first. Just getting the basic structure together, more to come...</p>
|
||||||
|
|
||||||
|
<h3>TODO:</h3>
|
||||||
|
|
||||||
|
- [ ] Installation script, preferably need some kind of pipeline to auto-inject dependencies into the install script.
|
||||||
|
- [ ] Send and receive text files over USB
|
||||||
|
- [ ] GUI in flutter
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
migrate_working_dir/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
**/ios/Flutter/.last_build_id
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
/build/
|
||||||
|
|
||||||
|
# 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
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
# 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: "761747bfc538b5af34aa0d3fac380f1bc331ec49"
|
||||||
|
channel: "stable"
|
||||||
|
|
||||||
|
project_type: app
|
||||||
|
|
||||||
|
# Tracks metadata for the flutter migrate command
|
||||||
|
migration:
|
||||||
|
platforms:
|
||||||
|
- platform: root
|
||||||
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
- platform: android
|
||||||
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
- platform: ios
|
||||||
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
- platform: linux
|
||||||
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
- platform: macos
|
||||||
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
- platform: web
|
||||||
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
- platform: windows
|
||||||
|
create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49
|
||||||
|
|
||||||
|
# User provided section
|
||||||
|
|
||||||
|
# List of Local paths (relative to this file) that should be
|
||||||
|
# ignored by the migrate tool.
|
||||||
|
#
|
||||||
|
# Files that are not part of the templates will be ignored by default.
|
||||||
|
unmanaged_files:
|
||||||
|
- 'lib/main.dart'
|
||||||
|
- 'ios/Runner.xcodeproj/project.pbxproj'
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# app
|
||||||
|
|
||||||
|
A new Flutter project.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
This project is a starting point for a Flutter application.
|
||||||
|
|
||||||
|
A few resources to get you started if this is your first Flutter project:
|
||||||
|
|
||||||
|
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||||
|
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||||
|
|
||||||
|
For help getting started with Flutter development, view the
|
||||||
|
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||||
|
samples, guidance on mobile development, and a full API reference.
|
||||||
|
|
||||||
|
# TODO
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# This file configures the analyzer, which statically analyzes Dart code to
|
||||||
|
# check for errors, warnings, and lints.
|
||||||
|
#
|
||||||
|
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||||
|
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||||
|
# invoked from the command line by running `flutter analyze`.
|
||||||
|
|
||||||
|
# The following line activates a set of recommended lints for Flutter apps,
|
||||||
|
# packages, and plugins designed to encourage good coding practices.
|
||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
linter:
|
||||||
|
# The lint rules applied to this project can be customized in the
|
||||||
|
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||||
|
# included above or to enable additional rules. A list of all available lints
|
||||||
|
# and their documentation is published at https://dart.dev/lints.
|
||||||
|
#
|
||||||
|
# Instead of disabling a lint rule for the entire project in the
|
||||||
|
# section below, it can also be suppressed for a single line of code
|
||||||
|
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||||
|
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||||
|
# producing the lint.
|
||||||
|
rules:
|
||||||
|
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||||
|
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||||
|
|
||||||
|
# Additional information about this file can be found at
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
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
|
||||||
|
**/*.keystore
|
||||||
|
**/*.jks
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
plugins {
|
||||||
|
id "com.android.application"
|
||||||
|
id "kotlin-android"
|
||||||
|
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||||
|
id "dev.flutter.flutter-gradle-plugin"
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "quaxlyqueen.dev.oneai"
|
||||||
|
compileSdk = flutter.compileSdkVersion
|
||||||
|
ndkVersion = flutter.ndkVersion
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
|
applicationId = "quaxlyqueen.dev.oneai"
|
||||||
|
// You can update the following values to match your application needs.
|
||||||
|
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||||
|
minSdk = flutter.minSdkVersion
|
||||||
|
targetSdk = flutter.targetSdkVersion
|
||||||
|
versionCode = flutterVersionCode.toInteger()
|
||||||
|
versionName = flutterVersionName
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = "../.."
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- The INTERNET permission is required for development. Specifically,
|
||||||
|
the Flutter tool needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<application
|
||||||
|
android:label="app"
|
||||||
|
android:name="${applicationName}"
|
||||||
|
android:icon="@mipmap/ic_launcher">
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:launchMode="singleTop"
|
||||||
|
android:taskAffinity=""
|
||||||
|
android:theme="@style/LaunchTheme"
|
||||||
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
|
android:hardwareAccelerated="true"
|
||||||
|
android:windowSoftInputMode="adjustResize">
|
||||||
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
|
the Android process has started. This theme is visible to the user
|
||||||
|
while the Flutter UI initializes. After that, this theme continues
|
||||||
|
to determine the Window background behind the Flutter UI. -->
|
||||||
|
<meta-data
|
||||||
|
android:name="io.flutter.embedding.android.NormalTheme"
|
||||||
|
android:resource="@style/NormalTheme"
|
||||||
|
/>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<!-- Don't delete the meta-data below.
|
||||||
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
|
<meta-data
|
||||||
|
android:name="flutterEmbedding"
|
||||||
|
android:value="2" />
|
||||||
|
</application>
|
||||||
|
<!-- Required to query activities that can process text, see:
|
||||||
|
https://developer.android.com/training/package-visibility and
|
||||||
|
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||||
|
|
||||||
|
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||||
|
<queries>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||||
|
<data android:mimeType="text/plain"/>
|
||||||
|
</intent>
|
||||||
|
</queries>
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.example.app
|
||||||
|
|
||||||
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
class MainActivity: FlutterActivity()
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Modify this file to customize your launch splash screen -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="?android:colorBackground" />
|
||||||
|
|
||||||
|
<!-- You can insert your own image assets here -->
|
||||||
|
<!-- <item>
|
||||||
|
<bitmap
|
||||||
|
android:gravity="center"
|
||||||
|
android:src="@mipmap/launch_image" />
|
||||||
|
</item> -->
|
||||||
|
</layer-list>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Modify this file to customize your launch splash screen -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@android:color/white" />
|
||||||
|
|
||||||
|
<!-- You can insert your own image assets here -->
|
||||||
|
<!-- <item>
|
||||||
|
<bitmap
|
||||||
|
android:gravity="center"
|
||||||
|
android:src="@mipmap/launch_image" />
|
||||||
|
</item> -->
|
||||||
|
</layer-list>
|
||||||
|
After Width: | Height: | Size: 544 B |
|
After Width: | Height: | Size: 442 B |
|
After Width: | Height: | Size: 721 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
|
the Flutter engine draws its first frame -->
|
||||||
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
</style>
|
||||||
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
|
This theme determines the color of the Android Window while your
|
||||||
|
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||||
|
running.
|
||||||
|
|
||||||
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
|
the Flutter engine draws its first frame -->
|
||||||
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
</style>
|
||||||
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
|
This theme determines the color of the Android Window while your
|
||||||
|
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||||
|
running.
|
||||||
|
|
||||||
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
|
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<!-- The INTERNET permission is required for development. Specifically,
|
||||||
|
the Flutter tool needs it to communicate with the running application
|
||||||
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
|
-->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.buildDir = "../build"
|
||||||
|
subprojects {
|
||||||
|
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||||
|
}
|
||||||
|
subprojects {
|
||||||
|
project.evaluationDependsOn(":app")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("clean", Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.enableJetifier=true
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
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.7.10" apply false
|
||||||
|
}
|
||||||
|
|
||||||
|
include ":app"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
description: This file stores settings for Dart & Flutter DevTools.
|
||||||
|
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||||
|
extensions:
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
**/dgph
|
||||||
|
*.mode1v3
|
||||||
|
*.mode2v3
|
||||||
|
*.moved-aside
|
||||||
|
*.pbxuser
|
||||||
|
*.perspectivev3
|
||||||
|
**/*sync/
|
||||||
|
.sconsign.dblite
|
||||||
|
.tags*
|
||||||
|
**/.vagrant/
|
||||||
|
**/DerivedData/
|
||||||
|
Icon?
|
||||||
|
**/Pods/
|
||||||
|
**/.symlinks/
|
||||||
|
profile
|
||||||
|
xcuserdata
|
||||||
|
**/.generated/
|
||||||
|
Flutter/App.framework
|
||||||
|
Flutter/Flutter.framework
|
||||||
|
Flutter/Flutter.podspec
|
||||||
|
Flutter/Generated.xcconfig
|
||||||
|
Flutter/ephemeral/
|
||||||
|
Flutter/app.flx
|
||||||
|
Flutter/app.zip
|
||||||
|
Flutter/flutter_assets/
|
||||||
|
Flutter/flutter_export_environment.sh
|
||||||
|
ServiceDefinitions.json
|
||||||
|
Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!default.mode1v3
|
||||||
|
!default.mode2v3
|
||||||
|
!default.pbxuser
|
||||||
|
!default.perspectivev3
|
||||||
@@ -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>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>App</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>io.flutter.flutter.app</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>App</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>MinimumOSVersion</key>
|
||||||
|
<string>12.0</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||||
|
#include "Generated.xcconfig"
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||||
|
#include "Generated.xcconfig"
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Uncomment this line to define a global platform for your project
|
||||||
|
# platform :ios, '12.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!
|
||||||
|
use_modular_headers!
|
||||||
|
|
||||||
|
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||||
|
target 'RunnerTests' do
|
||||||
|
inherit! :search_paths
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
post_install do |installer|
|
||||||
|
installer.pods_project.targets.each do |target|
|
||||||
|
flutter_additional_ios_build_settings(target)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
PODS:
|
||||||
|
- apivideo_live_stream (0.0.1):
|
||||||
|
- ApiVideoLiveStream (= 1.2.2)
|
||||||
|
- Flutter
|
||||||
|
- HaishinKit (= 1.3.0)
|
||||||
|
- ApiVideoLiveStream (1.2.2):
|
||||||
|
- HaishinKit (= 1.3.0)
|
||||||
|
- camera_avfoundation (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- DKImagePickerController/Core (4.3.9):
|
||||||
|
- DKImagePickerController/ImageDataManager
|
||||||
|
- DKImagePickerController/Resource
|
||||||
|
- DKImagePickerController/ImageDataManager (4.3.9)
|
||||||
|
- DKImagePickerController/PhotoGallery (4.3.9):
|
||||||
|
- DKImagePickerController/Core
|
||||||
|
- DKPhotoGallery
|
||||||
|
- DKImagePickerController/Resource (4.3.9)
|
||||||
|
- DKPhotoGallery (0.0.19):
|
||||||
|
- DKPhotoGallery/Core (= 0.0.19)
|
||||||
|
- DKPhotoGallery/Model (= 0.0.19)
|
||||||
|
- DKPhotoGallery/Preview (= 0.0.19)
|
||||||
|
- DKPhotoGallery/Resource (= 0.0.19)
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Core (0.0.19):
|
||||||
|
- DKPhotoGallery/Model
|
||||||
|
- DKPhotoGallery/Preview
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Model (0.0.19):
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Preview (0.0.19):
|
||||||
|
- DKPhotoGallery/Model
|
||||||
|
- DKPhotoGallery/Resource
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- DKPhotoGallery/Resource (0.0.19):
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- file_picker (0.0.1):
|
||||||
|
- DKImagePickerController/PhotoGallery
|
||||||
|
- Flutter
|
||||||
|
- Flutter (1.0.0)
|
||||||
|
- flutter_credit_card (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- HaishinKit (1.3.0):
|
||||||
|
- Logboard (~> 2.3.0)
|
||||||
|
- image_picker_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- Logboard (2.3.1)
|
||||||
|
- native_device_orientation (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- path_provider_foundation (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- pointer_interceptor_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- rive_common (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- SDWebImage (5.19.4):
|
||||||
|
- SDWebImage/Core (= 5.19.4)
|
||||||
|
- SDWebImage/Core (5.19.4)
|
||||||
|
- shared_preferences_foundation (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- speech_to_text (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- Try
|
||||||
|
- sqflite (0.0.3):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- SwiftyGif (5.4.5)
|
||||||
|
- Try (2.1.1)
|
||||||
|
- url_launcher_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- video_player_avfoundation (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- webview_flutter_wkwebview (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
|
||||||
|
DEPENDENCIES:
|
||||||
|
- apivideo_live_stream (from `.symlinks/plugins/apivideo_live_stream/ios`)
|
||||||
|
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
|
||||||
|
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||||
|
- Flutter (from `Flutter`)
|
||||||
|
- flutter_credit_card (from `.symlinks/plugins/flutter_credit_card/ios`)
|
||||||
|
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||||
|
- native_device_orientation (from `.symlinks/plugins/native_device_orientation/ios`)
|
||||||
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
|
- pointer_interceptor_ios (from `.symlinks/plugins/pointer_interceptor_ios/ios`)
|
||||||
|
- rive_common (from `.symlinks/plugins/rive_common/ios`)
|
||||||
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
|
- speech_to_text (from `.symlinks/plugins/speech_to_text/ios`)
|
||||||
|
- sqflite (from `.symlinks/plugins/sqflite/darwin`)
|
||||||
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
|
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
|
||||||
|
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`)
|
||||||
|
|
||||||
|
SPEC REPOS:
|
||||||
|
trunk:
|
||||||
|
- ApiVideoLiveStream
|
||||||
|
- DKImagePickerController
|
||||||
|
- DKPhotoGallery
|
||||||
|
- HaishinKit
|
||||||
|
- Logboard
|
||||||
|
- SDWebImage
|
||||||
|
- SwiftyGif
|
||||||
|
- Try
|
||||||
|
|
||||||
|
EXTERNAL SOURCES:
|
||||||
|
apivideo_live_stream:
|
||||||
|
:path: ".symlinks/plugins/apivideo_live_stream/ios"
|
||||||
|
camera_avfoundation:
|
||||||
|
:path: ".symlinks/plugins/camera_avfoundation/ios"
|
||||||
|
file_picker:
|
||||||
|
:path: ".symlinks/plugins/file_picker/ios"
|
||||||
|
Flutter:
|
||||||
|
:path: Flutter
|
||||||
|
flutter_credit_card:
|
||||||
|
:path: ".symlinks/plugins/flutter_credit_card/ios"
|
||||||
|
image_picker_ios:
|
||||||
|
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||||
|
native_device_orientation:
|
||||||
|
:path: ".symlinks/plugins/native_device_orientation/ios"
|
||||||
|
path_provider_foundation:
|
||||||
|
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||||
|
pointer_interceptor_ios:
|
||||||
|
:path: ".symlinks/plugins/pointer_interceptor_ios/ios"
|
||||||
|
rive_common:
|
||||||
|
:path: ".symlinks/plugins/rive_common/ios"
|
||||||
|
shared_preferences_foundation:
|
||||||
|
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||||
|
speech_to_text:
|
||||||
|
:path: ".symlinks/plugins/speech_to_text/ios"
|
||||||
|
sqflite:
|
||||||
|
:path: ".symlinks/plugins/sqflite/darwin"
|
||||||
|
url_launcher_ios:
|
||||||
|
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||||
|
video_player_avfoundation:
|
||||||
|
:path: ".symlinks/plugins/video_player_avfoundation/darwin"
|
||||||
|
webview_flutter_wkwebview:
|
||||||
|
:path: ".symlinks/plugins/webview_flutter_wkwebview/ios"
|
||||||
|
|
||||||
|
SPEC CHECKSUMS:
|
||||||
|
apivideo_live_stream: 64fa696699cfc531e07f5d5d701c7e3cd5ce5e9d
|
||||||
|
ApiVideoLiveStream: 5842571806a2ed26671597dadd370ec38d9b9ba4
|
||||||
|
camera_avfoundation: dd002b0330f4981e1bbcb46ae9b62829237459a4
|
||||||
|
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||||
|
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||||
|
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||||
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
|
flutter_credit_card: 48fb35065294868bc6a3e7f18a42f28929b84f48
|
||||||
|
HaishinKit: 013229683accc4abe46630b04629da3ff90428b7
|
||||||
|
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||||
|
Logboard: 3d98bb85de6a36b255ab637e8178eb5671c5c3a6
|
||||||
|
native_device_orientation: 3b4cfc9565a7b879cc4fde282b3e27745e852d0d
|
||||||
|
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
||||||
|
pointer_interceptor_ios: 508241697ff0947f853c061945a8b822463947c1
|
||||||
|
rive_common: 3a4c254c6e4db7e4b9e05daeb3d1f47ae4f7bf76
|
||||||
|
SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d
|
||||||
|
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
|
||||||
|
speech_to_text: b43a7d99aef037bd758ed8e45d79bbac035d2dfe
|
||||||
|
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||||
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
|
Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96
|
||||||
|
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||||
|
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
|
||||||
|
webview_flutter_wkwebview: be0f0d33777f1bfd0c9fdcb594786704dbf65f36
|
||||||
|
|
||||||
|
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796
|
||||||
|
|
||||||
|
COCOAPODS: 1.15.2
|
||||||
@@ -0,0 +1,730 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 54;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
|
1A842A08FCF2E60F2DC38967 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72D644A2E498C9BA5622C54F /* Pods_RunnerTests.framework */; };
|
||||||
|
23394E45189304C0C8B7B28E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 56C8C7368AE78ACE8607CD9E /* Pods_Runner.framework */; };
|
||||||
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||||
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
||||||
|
remoteInfo = Runner;
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 10;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
name = "Embed Frameworks";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
0151E46117D4D747AD6AC5CA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
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>"; };
|
||||||
|
2B088EE7CCB52F9F9F771147 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
|
4A35B625628A126CB966D9D3 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
55D68109A360AC60F8F453F3 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
56C8C7368AE78ACE8607CD9E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
72D644A2E498C9BA5622C54F /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
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>"; };
|
||||||
|
85190F9D33FFEE471AA1BBDF /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
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>"; };
|
||||||
|
E93E580DD876AE87CAF169F7 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
23394E45189304C0C8B7B28E /* Pods_Runner.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
F46E2B0305A6E6E475DD5131 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
1A842A08FCF2E60F2DC38967 /* Pods_RunnerTests.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
1DADEF4AA78CE7076F315AFE /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
0151E46117D4D747AD6AC5CA /* Pods-Runner.debug.xcconfig */,
|
||||||
|
2B088EE7CCB52F9F9F771147 /* Pods-Runner.release.xcconfig */,
|
||||||
|
85190F9D33FFEE471AA1BBDF /* Pods-Runner.profile.xcconfig */,
|
||||||
|
4A35B625628A126CB966D9D3 /* Pods-RunnerTests.debug.xcconfig */,
|
||||||
|
E93E580DD876AE87CAF169F7 /* Pods-RunnerTests.release.xcconfig */,
|
||||||
|
55D68109A360AC60F8F453F3 /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
|
);
|
||||||
|
path = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
331C807B294A618700263BE5 /* RunnerTests.swift */,
|
||||||
|
);
|
||||||
|
path = RunnerTests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||||
|
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||||
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||||
|
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Flutter;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146E51CF9000F007C117D = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
|
1DADEF4AA78CE7076F315AFE /* Pods */,
|
||||||
|
A3D098F5CC733F52B6D01ACB /* Frameworks */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146EF1CF9000F007C117D /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||||
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146F01CF9000F007C117D /* Runner */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||||
|
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||||
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||||
|
97C147021CF9000F007C117D /* Info.plist */,
|
||||||
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||||
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||||
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||||
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||||
|
);
|
||||||
|
path = Runner;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
A3D098F5CC733F52B6D01ACB /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
56C8C7368AE78ACE8607CD9E /* Pods_Runner.framework */,
|
||||||
|
72D644A2E498C9BA5622C54F /* Pods_RunnerTests.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
331C8080294A63A400263BE5 /* RunnerTests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||||
|
buildPhases = (
|
||||||
|
CF8C5EF2CFE445B8DBBA7041 /* [CP] Check Pods Manifest.lock */,
|
||||||
|
331C807D294A63A400263BE5 /* Sources */,
|
||||||
|
331C807F294A63A400263BE5 /* Resources */,
|
||||||
|
F46E2B0305A6E6E475DD5131 /* Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
331C8086294A63A400263BE5 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = RunnerTests;
|
||||||
|
productName = RunnerTests;
|
||||||
|
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
|
};
|
||||||
|
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
|
buildPhases = (
|
||||||
|
46398C21E369343F3454DAF3 /* [CP] Check Pods Manifest.lock */,
|
||||||
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
|
86B1E22AB537DC186C27C01C /* [CP] Embed Pods Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = Runner;
|
||||||
|
productName = Runner;
|
||||||
|
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
97C146E61CF9000F007C117D /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
BuildIndependentTargetsInParallel = YES;
|
||||||
|
LastUpgradeCheck = 1510;
|
||||||
|
ORGANIZATIONNAME = "";
|
||||||
|
TargetAttributes = {
|
||||||
|
331C8080294A63A400263BE5 = {
|
||||||
|
CreatedOnToolsVersion = 14.0;
|
||||||
|
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||||
|
};
|
||||||
|
97C146ED1CF9000F007C117D = {
|
||||||
|
CreatedOnToolsVersion = 7.3.1;
|
||||||
|
LastSwiftMigration = 1100;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||||
|
compatibilityVersion = "Xcode 9.3";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 97C146E51CF9000F007C117D;
|
||||||
|
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
97C146ED1CF9000F007C117D /* Runner */,
|
||||||
|
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
331C807F294A63A400263BE5 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||||
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||||
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||||
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
alwaysOutOfDate = 1;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||||
|
);
|
||||||
|
name = "Thin Binary";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||||
|
};
|
||||||
|
46398C21E369343F3454DAF3 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
86B1E22AB537DC186C27C01C /* [CP] Embed Pods Frameworks */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Embed Pods Frameworks";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
alwaysOutOfDate = 1;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "Run Script";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
|
};
|
||||||
|
CF8C5EF2CFE445B8DBBA7041 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
331C807D294A63A400263BE5 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||||
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||||
|
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
97C146FB1CF9000F007C117D /* Base */,
|
||||||
|
);
|
||||||
|
name = Main.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
97C147001CF9000F007C117D /* Base */,
|
||||||
|
);
|
||||||
|
name = LaunchScreen.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = 6G5TWS2YU7;
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = quaxlyqueen.dev.oneai;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
331C8088294A63A400263BE5 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 4A35B625628A126CB966D9D3 /* Pods-RunnerTests.debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.example.app.RunnerTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
331C8089294A63A400263BE5 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = E93E580DD876AE87CAF169F7 /* Pods-RunnerTests.release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.example.app.RunnerTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
331C808A294A63A400263BE5 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 55D68109A360AC60F8F453F3 /* Pods-RunnerTests.profile.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.example.app.RunnerTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
97C147031CF9000F007C117D /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
97C147041CF9000F007C117D /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
97C147061CF9000F007C117D /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = 6G5TWS2YU7;
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = quaxlyqueen.dev.oneai;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
97C147071CF9000F007C117D /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = 6G5TWS2YU7;
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = quaxlyqueen.dev.oneai;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
331C8088294A63A400263BE5 /* Debug */,
|
||||||
|
331C8089294A63A400263BE5 /* Release */,
|
||||||
|
331C808A294A63A400263BE5 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
97C147031CF9000F007C117D /* Debug */,
|
||||||
|
97C147041CF9000F007C117D /* Release */,
|
||||||
|
249021D3217E4FDB00AE95B9 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
97C147061CF9000F007C117D /* Debug */,
|
||||||
|
97C147071CF9000F007C117D /* Release */,
|
||||||
|
249021D4217E4FDB00AE95B9 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1510"
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "331C8080294A63A400263BE5"
|
||||||
|
BuildableName = "RunnerTests.xctest"
|
||||||
|
BlueprintName = "RunnerTests"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
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>
|
||||||
|
</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>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "group:Runner.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import Flutter
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@main
|
||||||
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
|
override func application(
|
||||||
|
_ application: UIApplication,
|
||||||
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
|
) -> Bool {
|
||||||
|
GeneratedPluginRegistrant.register(with: self)
|
||||||
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-20x20@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-20x20@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-29x29@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-29x29@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-29x29@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-40x40@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-40x40@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-60x60@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "Icon-App-60x60@3x.png",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-20x20@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-20x20@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-29x29@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-29x29@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-40x40@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-40x40@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-76x76@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-76x76@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "83.5x83.5",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "1024x1024",
|
||||||
|
"idiom" : "ios-marketing",
|
||||||
|
"filename" : "Icon-App-1024x1024@1x.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 295 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 450 B |
|
After Width: | Height: | Size: 282 B |
|
After Width: | Height: | Size: 462 B |
|
After Width: | Height: | Size: 704 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 586 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 762 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 68 B |
|
After Width: | Height: | Size: 68 B |
|
After Width: | Height: | Size: 68 B |
@@ -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.
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<?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>NSCameraUsageDescription</key>
|
||||||
|
<string>This app needs access to camera when used</string>
|
||||||
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
|
<string>TODO: Better description</string>
|
||||||
|
<key>LSApplicationCategoryType</key>
|
||||||
|
<string>Productivity</string>
|
||||||
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
|
<string>Required for on-device speech recognition.</string>
|
||||||
|
<key>NSSpeechRecognitionUsageDescription</key>
|
||||||
|
<string>On-device speech-to-text.</string>
|
||||||
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
|
<true/>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>App</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>app</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
|
<true/>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIMainStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#import "GeneratedPluginRegistrant.h"
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import Flutter
|
||||||
|
import UIKit
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class RunnerTests: XCTestCase {
|
||||||
|
|
||||||
|
func testExample() {
|
||||||
|
// If you add code to the Runner application, consider adding tests here.
|
||||||
|
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import '/components/options_dialog/options_dialog_widget.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'conversation_details_overlay_widget.dart'
|
||||||
|
show ConversationDetailsOverlayWidget;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class ConversationDetailsOverlayModel
|
||||||
|
extends FlutterFlowModel<ConversationDetailsOverlayWidget> {
|
||||||
|
/// State fields for stateful widgets in this component.
|
||||||
|
|
||||||
|
// Model for OptionsDialog component.
|
||||||
|
late PopupModel optionsDialogModel;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {
|
||||||
|
optionsDialogModel = createModel(context, () => PopupModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
optionsDialogModel.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,208 @@
|
|||||||
|
import '/components/options_dialog/options_dialog_widget.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'dart:ui';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
|
||||||
|
import 'conversation_details_overlay_model.dart';
|
||||||
|
export 'conversation_details_overlay_model.dart';
|
||||||
|
|
||||||
|
class ConversationDetailsOverlayWidget extends StatefulWidget {
|
||||||
|
const ConversationDetailsOverlayWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ConversationDetailsOverlayWidget> createState() =>
|
||||||
|
_ConversationDetailsOverlayWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ConversationDetailsOverlayWidgetState
|
||||||
|
extends State<ConversationDetailsOverlayWidget> {
|
||||||
|
late ConversationDetailsOverlayModel _model;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setState(VoidCallback callback) {
|
||||||
|
super.setState(callback);
|
||||||
|
_model.onUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_model = createModel(context, () => ConversationDetailsOverlayModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_model.maybeDispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(0),
|
||||||
|
child: BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(
|
||||||
|
sigmaX: 4,
|
||||||
|
sigmaY: 4,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
decoration: const BoxDecoration(),
|
||||||
|
child: Align(
|
||||||
|
alignment: const AlignmentDirectional(0, -1),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 700,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(0),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 70, 0, 0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(16, 0, 0, 0),
|
||||||
|
child: Text(
|
||||||
|
'Chat Details',
|
||||||
|
style: AppTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 0, 16, 0),
|
||||||
|
child: FlutterFlowIconButton(
|
||||||
|
borderColor: AppTheme.alternate,
|
||||||
|
borderRadius: 12,
|
||||||
|
borderWidth: 1,
|
||||||
|
buttonSize: 40,
|
||||||
|
fillColor: AppTheme.accent4,
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.close_rounded,
|
||||||
|
color: AppTheme.primaryTextColor,
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(16, 4, 0, 4),
|
||||||
|
child: RichText(
|
||||||
|
textScaler: MediaQuery.of(context).textScaler,
|
||||||
|
text: const TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: 'Group Chat ID: ',
|
||||||
|
style: TextStyle(),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: 'Hello World ',
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppTheme.primary,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
style: AppTheme.labelMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Expanded(
|
||||||
|
child: Align(
|
||||||
|
alignment: AlignmentDirectional(0, 0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Divider(
|
||||||
|
thickness: 1,
|
||||||
|
color: AppTheme.tertiary,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Align(
|
||||||
|
alignment: const AlignmentDirectional(0, -1),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(16, 0, 16, 0),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppTheme
|
||||||
|
.secondaryBackground,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppTheme.alternate,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: wrapWithModel(
|
||||||
|
model: _model.optionsDialogModel,
|
||||||
|
updateCallback: () => setState(() {}),
|
||||||
|
updateOnChange: true,
|
||||||
|
child: const PopupWidget(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(16, 16, 16, 44),
|
||||||
|
child: FFButtonWidget(
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
text: 'Close',
|
||||||
|
options: FFButtonOptions(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 52,
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(44, 0, 44, 0),
|
||||||
|
iconPadding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
color:
|
||||||
|
AppTheme.secondaryBackground,
|
||||||
|
textStyle: AppTheme.titleLarge,
|
||||||
|
elevation: 0,
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.alternate,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
hoverColor: AppTheme.alternate,
|
||||||
|
hoverBorderSide: const BorderSide(
|
||||||
|
color: AppTheme.alternate,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
hoverTextColor: AppTheme.primaryTextColor,
|
||||||
|
hoverElevation: 3,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import 'package:app/components/conversation_thread/conversation.dart';
|
||||||
|
|
||||||
|
import '/components/conversation_thread/conversation_thread_widget.dart';
|
||||||
|
import '/components/model_item/model_item_widget.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'conversation_widget.dart' show ConversationWidget;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ConversationModel extends FlutterFlowModel<ConversationWidget> {
|
||||||
|
/// State fields for stateful widgets in this page.
|
||||||
|
|
||||||
|
final unfocusNode = FocusNode();
|
||||||
|
// Model for ConversationThread component.
|
||||||
|
late ConversationThreadModel conversationThreadModel;
|
||||||
|
// Model for ModelItem component.
|
||||||
|
late ModelItemModel modelItemModel;
|
||||||
|
|
||||||
|
late Conversation conversation;
|
||||||
|
|
||||||
|
ConversationModel(this.conversation);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {
|
||||||
|
conversationThreadModel = createModel(context, () => ConversationThreadModel(conversation)); // TODO
|
||||||
|
modelItemModel = createModel(context, () => ModelItemModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
unfocusNode.dispose();
|
||||||
|
conversationThreadModel.dispose();
|
||||||
|
modelItemModel.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'conversation_options_widget.dart' show ConversationOptionsWidget;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class ConversationOptionsModel
|
||||||
|
extends FlutterFlowModel<ConversationOptionsWidget> {
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
|
||||||
|
import 'conversation_options_model.dart';
|
||||||
|
export 'conversation_options_model.dart';
|
||||||
|
|
||||||
|
class ConversationOptionsWidget extends StatefulWidget {
|
||||||
|
const ConversationOptionsWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ConversationOptionsWidget> createState() =>
|
||||||
|
_ConversationOptionsWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ConversationOptionsWidgetState extends State<ConversationOptionsWidget> {
|
||||||
|
late ConversationOptionsModel _model;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setState(VoidCallback callback) {
|
||||||
|
super.setState(callback);
|
||||||
|
_model.onUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_model = createModel(context, () => ConversationOptionsModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_model.maybeDispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: AppTheme.secondaryBackground,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 12, 0, 24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 60,
|
||||||
|
decoration: const BoxDecoration(),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(12, 8, 12, 8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||||
|
color: AppTheme.primaryBackground,
|
||||||
|
elevation: 0,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(40),
|
||||||
|
),
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
child: Icon(
|
||||||
|
Icons.share_rounded,
|
||||||
|
color: AppTheme.secondaryText,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(12, 0, 0, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Share',
|
||||||
|
style: AppTheme.labelLarge,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 60,
|
||||||
|
decoration: const BoxDecoration(),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(12, 8, 12, 8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||||
|
color: AppTheme.primaryBackground,
|
||||||
|
elevation: 0,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(40),
|
||||||
|
),
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
child: Icon(
|
||||||
|
Icons.insert_link,
|
||||||
|
color: AppTheme.secondaryText,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(12, 0, 0, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Get Link',
|
||||||
|
style: AppTheme.labelLarge,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 60,
|
||||||
|
decoration: const BoxDecoration(),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(12, 8, 12, 8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||||
|
color: AppTheme.primaryBackground,
|
||||||
|
elevation: 0,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(40),
|
||||||
|
),
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
child: Icon(
|
||||||
|
Icons.mode_edit,
|
||||||
|
color: AppTheme.secondaryText,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(12, 0, 0, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Model selection',
|
||||||
|
style: AppTheme.labelLarge,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 60,
|
||||||
|
decoration: const BoxDecoration(),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(12, 8, 12, 8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Card(
|
||||||
|
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||||
|
color: AppTheme.primaryBackground,
|
||||||
|
elevation: 0,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(40),
|
||||||
|
),
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
child: Icon(
|
||||||
|
Icons.hide_source,
|
||||||
|
color: AppTheme.secondaryText,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(12, 0, 0, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Private',
|
||||||
|
style: AppTheme.labelLarge,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
class Chat {
|
||||||
|
final String content;
|
||||||
|
final bool role;
|
||||||
|
int chatType = 0;
|
||||||
|
|
||||||
|
// Most basic chat, text from server or from user.
|
||||||
|
Chat(this.content, this.role, this.chatType);
|
||||||
|
|
||||||
|
// A chat with an included image.
|
||||||
|
Chat.image(this.content, this.role, this.chatType);
|
||||||
|
|
||||||
|
// A chat with an included file.
|
||||||
|
Chat.file(this.content, this.role, this.chatType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add proper filetype support. File should either be parsed on-device, or uploaded to the server.
|
||||||
|
// TODO: See https://github.com/adithya-s-k/omniparse
|
||||||
|
// TODO: Implement dynamic pathing based upon filetypes.
|
||||||
|
enum Filetype {
|
||||||
|
pdf,
|
||||||
|
doc,
|
||||||
|
docx,
|
||||||
|
pages,
|
||||||
|
note,
|
||||||
|
todo,
|
||||||
|
cal,
|
||||||
|
calendar,
|
||||||
|
event,
|
||||||
|
contact,
|
||||||
|
mp3,
|
||||||
|
mp4,
|
||||||
|
wav,
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import 'chat_bubble_widget.dart';
|
||||||
|
import 'chat.dart';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class ChatBubbleModel extends FlutterFlowModel<ChatBubbleWidget>{
|
||||||
|
late final Chat c;
|
||||||
|
|
||||||
|
ChatBubbleModel(this.c);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {} // TODO: Need to implement for prompt/response deletion.
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {} // TODO: Need to implement for loading in media and editing.
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:app/components/util/backend.dart';
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'chat.dart';
|
||||||
|
|
||||||
|
class ChatBubbleWidget extends StatelessWidget{
|
||||||
|
late Chat c;
|
||||||
|
|
||||||
|
ChatBubbleWidget({super.key, required this.c});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
double max_width = MediaQuery.of(context).size.width*0.65;
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: c.role ? MainAxisAlignment.end : MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: max_width,
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
margin: const EdgeInsets.all(8.0),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: const Radius.circular(12.0),
|
||||||
|
topRight: const Radius.circular(12.0),
|
||||||
|
bottomLeft: c.role ? const Radius.circular(12.0) : const Radius
|
||||||
|
.circular(0.0),
|
||||||
|
bottomRight: c.role ? const Radius.circular(12.0) : const Radius
|
||||||
|
.circular(0.0),
|
||||||
|
),
|
||||||
|
color: c.role ? AppTheme.darkest : AppTheme.dark,
|
||||||
|
),
|
||||||
|
child:
|
||||||
|
// TODO: Properly display filetypes in the thread.
|
||||||
|
c.chatType == 0 ? Text(
|
||||||
|
c.content,
|
||||||
|
style: AppTheme.bodyMedium,
|
||||||
|
)
|
||||||
|
: c.chatType == 1 ? Image(image: Backend.convertFromBase64(c.content))
|
||||||
|
: c.chatType == 2 ? const Icon(
|
||||||
|
Icons.file_copy,
|
||||||
|
) : const Text("null"),
|
||||||
|
// Text(
|
||||||
|
// c.content,
|
||||||
|
// style: AppTheme.bodyMedium,
|
||||||
|
// ),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import 'package:app/components/util/backend.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'chat.dart';
|
||||||
|
|
||||||
|
class Conversation with ChangeNotifier {
|
||||||
|
int conversationID;
|
||||||
|
String conversationLabel;
|
||||||
|
String conversationSubLabel;
|
||||||
|
// TODO: Fix history, very, verry strange behavior when disabled.
|
||||||
|
bool history = true; // History is disabled by default. This means chats are auto-deleted once the user exits that conversation.\
|
||||||
|
bool conversationContext = true; // The prior prompts and responses are used as additional context for the next prompt and response.
|
||||||
|
late bool stream = false; // Update the UI with a stream of characters as received from the server, or as one text.
|
||||||
|
var lastAccessTime = DateTime.timestamp(); // Used to sort conversations based on most recent usage.
|
||||||
|
|
||||||
|
List<Chat> chats = [];
|
||||||
|
|
||||||
|
Conversation(this.conversationID, this.conversationLabel, this.conversationSubLabel);
|
||||||
|
|
||||||
|
Conversation.completeConversation(this.conversationID, this.conversationLabel, this.conversationSubLabel, this.chats);
|
||||||
|
|
||||||
|
void toggleHistory() => history = !history;
|
||||||
|
|
||||||
|
void toggleConversationContext() => conversationContext = !conversationContext;
|
||||||
|
|
||||||
|
void toggleStream() => stream = !stream;
|
||||||
|
|
||||||
|
void add(Chat message) {
|
||||||
|
lastAccessTime = DateTime.timestamp();
|
||||||
|
chats.add(message);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadChats() {
|
||||||
|
lastAccessTime = DateTime.timestamp();
|
||||||
|
Backend.loadConversation;
|
||||||
|
chats = Backend.loadedChats;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLabel() {
|
||||||
|
// TODO: Need to implement
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSubLabel() {
|
||||||
|
// TODO: Need to implement
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Chat> getChats() {
|
||||||
|
lastAccessTime = DateTime.timestamp();
|
||||||
|
return chats;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLabels(String cLabel, String cSubLabel) {
|
||||||
|
lastAccessTime = DateTime.timestamp();
|
||||||
|
conversationLabel = cLabel;
|
||||||
|
conversationSubLabel = cSubLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import 'package:app/components/conversation_thread/chat_bubble_model.dart';
|
||||||
|
import 'package:app/components/conversation_thread/chat.dart';
|
||||||
|
import 'package:app/components/conversation_thread/conversation.dart';
|
||||||
|
import 'package:app/components/util/backend.dart';
|
||||||
|
|
||||||
|
import 'package:app/components/prompt_box/prompt_box_widget.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'conversation_thread_widget.dart' show ConversationThreadWidget;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
|
||||||
|
class ConversationThreadModel extends FlutterFlowModel<ConversationThreadWidget> {
|
||||||
|
final formKey = GlobalKey<FormState>();
|
||||||
|
late PromptBoxModel promptBoxModel;
|
||||||
|
Conversation conversation;
|
||||||
|
|
||||||
|
ConversationThreadModel(this.conversation);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {
|
||||||
|
conversation = Backend.getLoadedConversation();
|
||||||
|
promptBoxModel = createModel(context, () => PromptBoxModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
promptBoxModel.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
import 'package:app/components/conversation_thread/conversation.dart';
|
||||||
|
import 'package:app/components/util/backend.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '/components/conversation_thread/chat_bubble_widget.dart';
|
||||||
|
import 'package:app/components/conversation_thread/conversation_thread_model.dart';
|
||||||
|
import '/components/prompt_box/prompt_box_widget.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
|
||||||
|
import 'conversation_thread_model.dart';
|
||||||
|
export 'conversation_thread_model.dart';
|
||||||
|
|
||||||
|
class ConversationThreadWidget extends StatefulWidget {
|
||||||
|
final Conversation conversation;
|
||||||
|
const ConversationThreadWidget({super.key, required this.conversation});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ConversationThreadWidget> createState() =>
|
||||||
|
_ConversationThreadWidgetState(conversation);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ConversationThreadWidgetState extends State<ConversationThreadWidget> {
|
||||||
|
late ConversationThreadModel _model;
|
||||||
|
Conversation conversation;
|
||||||
|
|
||||||
|
_ConversationThreadWidgetState(this.conversation);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setState(VoidCallback callback) {
|
||||||
|
super.setState(callback);
|
||||||
|
_model.onUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_model = createModel(context, () => ConversationThreadModel(conversation));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_model.maybeDispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// TODO: Add a scrollbar
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ListenableBuilder(
|
||||||
|
listenable: _model.conversation,
|
||||||
|
builder: (BuildContext context, Widget? child) {
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: Backend.getLoadedConversation().chats.length,
|
||||||
|
padding: const EdgeInsets.fromLTRB(0, 12, 0, 24,),
|
||||||
|
reverse: false,
|
||||||
|
scrollDirection: Axis.vertical,
|
||||||
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
return ChatBubbleWidget(c: Backend.getLoadedConversation().chats[index]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: AppTheme.medium,
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
blurRadius: 3,
|
||||||
|
color: Color(0x33000000),
|
||||||
|
offset: Offset(
|
||||||
|
0,
|
||||||
|
-2,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// TODO
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
// Row(
|
||||||
|
// mainAxisSize: MainAxisSize.max,
|
||||||
|
// children: [
|
||||||
|
// Expanded(
|
||||||
|
// child: Padding(
|
||||||
|
// padding: const EdgeInsetsDirectional.fromSTEB(0, 12, 0, 0),
|
||||||
|
// child: SingleChildScrollView(
|
||||||
|
// scrollDirection: Axis.horizontal,
|
||||||
|
// child: Row(
|
||||||
|
// mainAxisSize: MainAxisSize.max,
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
// children: [
|
||||||
|
// FlutterFlowMediaDisplay(
|
||||||
|
// path: '',
|
||||||
|
// imageBuilder: (path) => ClipRRect(
|
||||||
|
// borderRadius: BorderRadius.circular(8),
|
||||||
|
// child: CachedNetworkImage(
|
||||||
|
// fadeInDuration: const Duration(milliseconds: 500),
|
||||||
|
// fadeOutDuration:
|
||||||
|
// const Duration(milliseconds: 500),
|
||||||
|
// imageUrl: path,
|
||||||
|
// width: 120,
|
||||||
|
// height: 100,
|
||||||
|
// fit: BoxFit.cover,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// // TODO
|
||||||
|
// videoPlayerBuilder: (path) =>
|
||||||
|
// FlutterFlowVideoPlayer(
|
||||||
|
// path: path,
|
||||||
|
// width: 300,
|
||||||
|
// autoPlay: false,
|
||||||
|
// looping: true,
|
||||||
|
// showControls: true,
|
||||||
|
// allowFullScreen: true,
|
||||||
|
// allowPlaybackSpeedMenu: false,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// Align(
|
||||||
|
// alignment: const AlignmentDirectional(-1, -1),
|
||||||
|
// // TODO: Make the delete button conditional upon media upload.
|
||||||
|
// child: FlutterFlowIconButton(
|
||||||
|
// borderColor:
|
||||||
|
// AppTheme.error,
|
||||||
|
// borderRadius: 20,
|
||||||
|
// borderWidth: 2,
|
||||||
|
// buttonSize: 40,
|
||||||
|
// fillColor: AppTheme.primaryBackground,
|
||||||
|
// icon: const Icon(
|
||||||
|
// Icons.delete_outline_rounded,
|
||||||
|
// color: AppTheme.error,
|
||||||
|
// size: 24,
|
||||||
|
// ),
|
||||||
|
// onPressed: () {
|
||||||
|
// print('IconButton pressed ...');
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ]
|
||||||
|
// .divide(const SizedBox(width: 8))
|
||||||
|
// .addToStart(const SizedBox(width: 16))
|
||||||
|
// .addToEnd(const SizedBox(width: 16)),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
Form(
|
||||||
|
key: _model.formKey,
|
||||||
|
autovalidateMode: AutovalidateMode.disabled,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 8),
|
||||||
|
child: wrapWithModel(
|
||||||
|
model: _model.promptBoxModel,
|
||||||
|
updateCallback: () => setState(() {}),
|
||||||
|
child: const PromptBoxWidget(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
import 'package:app/components/conversation_thread/conversation.dart';
|
||||||
|
|
||||||
|
import '/components/conversation_details_overlay/conversation_details_overlay_widget.dart';
|
||||||
|
import '/components/conversation_thread/conversation_thread_widget.dart';
|
||||||
|
import '/components/model_item/model_item_widget.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
|
||||||
|
import '../components/conversation_model.dart';
|
||||||
|
export '../components/conversation_model.dart';
|
||||||
|
|
||||||
|
class ConversationWidget extends StatefulWidget {
|
||||||
|
final Conversation conversation;
|
||||||
|
const ConversationWidget({super.key, required this.conversation});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ConversationWidget> createState() => _ConversationWidgetState(conversation);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ConversationWidgetState extends State<ConversationWidget> {
|
||||||
|
late ConversationModel _model;
|
||||||
|
Conversation conversation;
|
||||||
|
|
||||||
|
_ConversationWidgetState(this.conversation);
|
||||||
|
|
||||||
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_model = createModel(context, () => ConversationModel(conversation));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_model.dispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => _model.unfocusNode.canRequestFocus
|
||||||
|
? FocusScope.of(context).requestFocus(_model.unfocusNode)
|
||||||
|
: FocusScope.of(context).unfocus(),
|
||||||
|
child: Scaffold(
|
||||||
|
key: scaffoldKey,
|
||||||
|
backgroundColor: AppTheme.secondaryBackground,
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: AppTheme.primaryBackground,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
// ---------- Back Button
|
||||||
|
leading: FlutterFlowIconButton(
|
||||||
|
borderColor: Colors.transparent,
|
||||||
|
borderRadius: 30,
|
||||||
|
borderWidth: 1,
|
||||||
|
buttonSize: 60,
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.arrow_back_rounded,
|
||||||
|
color: AppTheme.lighterest,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
// TODO: Smooth out the animation to prevent the conversations list from loading half-way up the screen.
|
||||||
|
// Note: that only applies if the input was already selected.
|
||||||
|
SystemChannels.textInput.invokeMethod('TextInput.hide');
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
title: wrapWithModel(
|
||||||
|
model: _model.modelItemModel,
|
||||||
|
updateCallback: () => setState(() {}),
|
||||||
|
child: ModelItemWidget(conversation: conversation,),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 8, 16, 8),
|
||||||
|
// ---------- Options Button
|
||||||
|
child: FlutterFlowIconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.more_vert,
|
||||||
|
color: AppTheme.lighterest,
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
await showModalBottomSheet(
|
||||||
|
isScrollControlled: true,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
enableDrag: false,
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => _model.unfocusNode.canRequestFocus
|
||||||
|
? FocusScope.of(context)
|
||||||
|
.requestFocus(_model.unfocusNode)
|
||||||
|
: FocusScope.of(context).unfocus(),
|
||||||
|
child: Padding(
|
||||||
|
padding: MediaQuery.viewInsetsOf(context),
|
||||||
|
child: const ConversationDetailsOverlayWidget(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).then((value) => safeSetState(() {}));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
centerTitle: false,
|
||||||
|
elevation: 0,
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
top: true,
|
||||||
|
child: wrapWithModel(
|
||||||
|
model: _model.conversationThreadModel,
|
||||||
|
updateCallback: () => setState(() {}),
|
||||||
|
child: ConversationThreadWidget(conversation: conversation),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'conversations_list_widget.dart' show ConversationsListWidget;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class ConversationsListModel extends FlutterFlowModel<ConversationsListWidget> {
|
||||||
|
|
||||||
|
final unfocusNode = FocusNode();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
unfocusNode.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
import 'package:app/components/conversation_thread/conversation.dart';
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
|
||||||
|
import 'package:app/components/conversation_widget.dart';
|
||||||
|
import 'package:app/components/util/backend.dart';
|
||||||
|
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:app/components/options_dialog/options_dialog_widget.dart';
|
||||||
|
import '../components/conversations_list_model.dart';
|
||||||
|
export '../components/conversations_list_model.dart';
|
||||||
|
|
||||||
|
class ConversationsListWidget extends StatefulWidget {
|
||||||
|
const ConversationsListWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ConversationsListWidget> createState() =>
|
||||||
|
_ConversationsListWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ConversationsListWidgetState extends State<ConversationsListWidget> {
|
||||||
|
late ConversationsListModel _model;
|
||||||
|
|
||||||
|
static List<ConversationWidget> conversations = [];
|
||||||
|
|
||||||
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
Backend().init();
|
||||||
|
|
||||||
|
if(conversations.isEmpty) {
|
||||||
|
List<Conversation> convoys = Backend.conversations;
|
||||||
|
for(Conversation c in convoys) {
|
||||||
|
conversations.add(ConversationWidget(conversation: c,));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_model = createModel(context, () => ConversationsListModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_model.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// Clean conversation list prior to building widgets, to prevent bloating UI with empty conversations.
|
||||||
|
// Additionally, delete conversations that have history disabled.
|
||||||
|
for(int i = 0; i < conversations.length; i++) {
|
||||||
|
if(
|
||||||
|
conversations[i].conversation.getChats().isEmpty ||
|
||||||
|
!conversations[i].conversation.history
|
||||||
|
) {
|
||||||
|
Backend.conversations.removeAt(i);
|
||||||
|
conversations.removeAt(i);
|
||||||
|
Backend.maxConversationID--; // maxConversationID will eventually be deprecated with better ID system.
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => _model.unfocusNode.canRequestFocus
|
||||||
|
? FocusScope.of(context).requestFocus(_model.unfocusNode)
|
||||||
|
: FocusScope.of(context).unfocus(),
|
||||||
|
child: SafeArea(
|
||||||
|
top: true,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Align(
|
||||||
|
alignment: const AlignmentDirectional(0, 0),
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: conversations.length,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
reverse: true,
|
||||||
|
scrollDirection: Axis.vertical,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Align(
|
||||||
|
alignment: const AlignmentDirectional(0, 0),
|
||||||
|
child: InkWell(
|
||||||
|
// TODO
|
||||||
|
// onTap: () async {
|
||||||
|
// context.pushNamed('Conversation');
|
||||||
|
// },
|
||||||
|
child: Container(
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
//color: AppTheme.darkest,
|
||||||
|
border: Border(
|
||||||
|
top: BorderSide(width: 2.0, color: AppTheme.darkest),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
decoration: const BoxDecoration(color: AppTheme.medium,),
|
||||||
|
child: const Align(
|
||||||
|
alignment: AlignmentDirectional(0, 0),
|
||||||
|
child: Icon(
|
||||||
|
Icons.settings_outlined, // TODO: Dynamically generate or allow users to color code/tag conversations.
|
||||||
|
color: AppTheme.secondaryText,
|
||||||
|
size: 48,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Align(
|
||||||
|
alignment: const AlignmentDirectional(-1, 0),
|
||||||
|
child: Container(
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: MediaQuery.sizeOf(context).width,
|
||||||
|
),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: AppTheme.medium,
|
||||||
|
shape: BoxShape.rectangle,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Align(
|
||||||
|
alignment: const AlignmentDirectional(-1, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
conversations[index].conversation.conversationLabel,
|
||||||
|
style: AppTheme.labelLarge,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Align(
|
||||||
|
alignment:
|
||||||
|
const AlignmentDirectional(-1, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
conversations[index].conversation.conversationSubLabel,
|
||||||
|
style: AppTheme.labelSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: AppTheme.medium,
|
||||||
|
),
|
||||||
|
child: const Icon(
|
||||||
|
Icons.chevron_right_rounded,
|
||||||
|
color: AppTheme.secondaryText,
|
||||||
|
size: 48,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onTap: () => {
|
||||||
|
Backend.loadConversation(index),
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => ConversationWidget(conversation: Backend.getLoadedConversation(),),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onLongPress: () => {
|
||||||
|
showModalBottomSheet(
|
||||||
|
isScrollControlled: true,
|
||||||
|
backgroundColor:
|
||||||
|
Colors.transparent,
|
||||||
|
enableDrag: false,
|
||||||
|
useSafeArea: true,
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return Padding(
|
||||||
|
padding:
|
||||||
|
MediaQuery.viewInsetsOf(
|
||||||
|
context),
|
||||||
|
child: const PopupWidget(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).then((value) =>
|
||||||
|
safeSetState(() {})),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 20.0, // Adjust positioning as needed
|
||||||
|
right: 20.0, // Adjust positioning as needed
|
||||||
|
child: FloatingActionButton(
|
||||||
|
onPressed: () => {
|
||||||
|
Backend.loadConversation(Backend.createConversation()), // TODO: Dynamically get the next ID
|
||||||
|
conversations.add(ConversationWidget(conversation: Backend.getLoadedConversation())),
|
||||||
|
Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => ConversationWidget(conversation: Backend.loadedConversation,),
|
||||||
|
),
|
||||||
|
), // Handle the button press
|
||||||
|
},
|
||||||
|
backgroundColor: AppTheme.accent,
|
||||||
|
child: const Icon(
|
||||||
|
Icons.bubble_chart,
|
||||||
|
color: AppTheme.light,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'image_details_widget.dart' show ImageDetailsWidget;
|
||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class ImageDetailsModel extends FlutterFlowModel<ImageDetailsWidget> {
|
||||||
|
/// State fields for stateful widgets in this page.
|
||||||
|
|
||||||
|
final unfocusNode = FocusNode();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
unfocusNode.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,243 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
import 'image_details_model.dart';
|
||||||
|
export 'image_details_model.dart';
|
||||||
|
|
||||||
|
class ImageDetailsWidget extends StatefulWidget {
|
||||||
|
const ImageDetailsWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ImageDetailsWidget> createState() => _ImageDetailsWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ImageDetailsWidgetState extends State<ImageDetailsWidget>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
|
late ImageDetailsModel _model;
|
||||||
|
|
||||||
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
|
||||||
|
final animationsMap = <String, AnimationInfo>{};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_model = createModel(context, () => ImageDetailsModel());
|
||||||
|
|
||||||
|
animationsMap.addAll({
|
||||||
|
'imageOnPageLoadAnimation': AnimationInfo(
|
||||||
|
trigger: AnimationTrigger.onPageLoad,
|
||||||
|
effectsBuilder: () => [
|
||||||
|
VisibilityEffect(duration: 1.ms),
|
||||||
|
FadeEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 300.0.ms,
|
||||||
|
begin: 0.0,
|
||||||
|
end: 1.0,
|
||||||
|
),
|
||||||
|
MoveEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 300.0.ms,
|
||||||
|
begin: const Offset(0.0, 30.0),
|
||||||
|
end: const Offset(0.0, 0.0),
|
||||||
|
),
|
||||||
|
ScaleEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 300.0.ms,
|
||||||
|
begin: const Offset(0.7, 0.7),
|
||||||
|
end: const Offset(1.0, 1.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
'rowOnPageLoadAnimation': AnimationInfo(
|
||||||
|
trigger: AnimationTrigger.onPageLoad,
|
||||||
|
effectsBuilder: () => [
|
||||||
|
VisibilityEffect(duration: 1.ms),
|
||||||
|
FadeEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 300.0.ms,
|
||||||
|
begin: 0.0,
|
||||||
|
end: 1.0,
|
||||||
|
),
|
||||||
|
MoveEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 300.0.ms,
|
||||||
|
begin: const Offset(0.0, 30.0),
|
||||||
|
end: const Offset(0.0, 0.0),
|
||||||
|
),
|
||||||
|
TiltEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 300.0.ms,
|
||||||
|
begin: const Offset(-0.698, 0),
|
||||||
|
end: const Offset(0, 0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_model.dispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => _model.unfocusNode.canRequestFocus
|
||||||
|
? FocusScope.of(context).requestFocus(_model.unfocusNode)
|
||||||
|
: FocusScope.of(context).unfocus(),
|
||||||
|
child: Scaffold(
|
||||||
|
key: scaffoldKey,
|
||||||
|
backgroundColor: AppTheme.secondaryBackground,
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: AppTheme.secondaryBackground,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
leading: const FlutterFlowIconButton(
|
||||||
|
borderColor: Colors.transparent,
|
||||||
|
borderRadius: 30,
|
||||||
|
borderWidth: 1,
|
||||||
|
buttonSize: 60,
|
||||||
|
icon: Icon(
|
||||||
|
Icons.arrow_back_rounded,
|
||||||
|
color: AppTheme.primaryTextColor,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
// TODO
|
||||||
|
// onPressed: () async {
|
||||||
|
// context.pop();
|
||||||
|
// },
|
||||||
|
),
|
||||||
|
actions: const [],
|
||||||
|
centerTitle: false,
|
||||||
|
elevation: 0,
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
top: true,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: Hero(
|
||||||
|
tag: 'hero',
|
||||||
|
transitionOnUserGestures: true,
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: CachedNetworkImage(
|
||||||
|
fadeInDuration: const Duration(milliseconds: 500),
|
||||||
|
fadeOutDuration: const Duration(milliseconds: 500),
|
||||||
|
imageUrl: 'https://picsum.photos/seed/150/600',
|
||||||
|
width: double.infinity,
|
||||||
|
fit: BoxFit.fitWidth,
|
||||||
|
memCacheWidth: 1200,
|
||||||
|
memCacheHeight: 1200,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).animateOnPageLoad(
|
||||||
|
animationsMap['imageOnPageLoadAnimation']!),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(12, 12, 12, 32),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 4, 8, 16),
|
||||||
|
child: Container(
|
||||||
|
width: 36,
|
||||||
|
height: 36,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppTheme.accent1,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
shape: BoxShape.rectangle,
|
||||||
|
border: Border.all(
|
||||||
|
color: AppTheme.primary,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: CachedNetworkImage(
|
||||||
|
fadeInDuration: const Duration(milliseconds: 200),
|
||||||
|
fadeOutDuration: const Duration(milliseconds: 200),
|
||||||
|
imageUrl:
|
||||||
|
'https://images.unsplash.com/photo-1521572267360-ee0c2909d518?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w0NTYyMDF8MHwxfHNlYXJjaHwyMHx8cHJvZmlsZXxlbnwwfHx8fDE2OTU4MjQ5OTN8MA&ixlib=rb-4.0.3&q=80&w=1080',
|
||||||
|
width: 44,
|
||||||
|
height: 44,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 8),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
const SelectionArea(
|
||||||
|
child: AutoSizeText(
|
||||||
|
'Thanks so much! We really do appreciate it!',
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
style: AppTheme.bodyMedium,
|
||||||
|
)),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
0, 4, 0, 0),
|
||||||
|
child: Text(
|
||||||
|
'Just Now',
|
||||||
|
style: AppTheme.labelSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(const SizedBox(width: 4)),
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(0, 4, 0, 0),
|
||||||
|
child: SelectionArea(
|
||||||
|
child: AutoSizeText(
|
||||||
|
'Thanks so much! We really do appreciate it!',
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
style: AppTheme.labelLarge,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).animateOnPageLoad(animationsMap['rowOnPageLoadAnimation']!),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'model_item_widget.dart' show ModelItemWidget;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class ModelItemModel extends FlutterFlowModel<ModelItemWidget> {
|
||||||
|
/// State fields for stateful widgets in this component.
|
||||||
|
|
||||||
|
// State field(s) for iuser widget.
|
||||||
|
bool iuserHovered = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
import 'package:app/components/conversation_thread/conversation.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
|
||||||
|
import 'model_item_model.dart';
|
||||||
|
export 'model_item_model.dart';
|
||||||
|
|
||||||
|
class ModelItemWidget extends StatefulWidget {
|
||||||
|
final Conversation conversation;
|
||||||
|
const ModelItemWidget({super.key, required this.conversation});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ModelItemWidget> createState() => _ModelItemWidgetState(conversation);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ModelItemWidgetState extends State<ModelItemWidget> {
|
||||||
|
late ModelItemModel _model;
|
||||||
|
late Conversation conversation;
|
||||||
|
|
||||||
|
_ModelItemWidgetState(this.conversation);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setState(VoidCallback callback) {
|
||||||
|
super.setState(callback);
|
||||||
|
_model.onUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_model = createModel(context, () => ModelItemModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_model.maybeDispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MouseRegion(
|
||||||
|
opaque: false,
|
||||||
|
cursor: MouseCursor.defer ?? MouseCursor.defer,
|
||||||
|
onEnter: ((event) async {
|
||||||
|
setState(() => _model.iuserHovered = true);
|
||||||
|
}),
|
||||||
|
onExit: ((event) async {
|
||||||
|
setState(() => _model.iuserHovered = false);
|
||||||
|
}),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppTheme.primaryBackground,
|
||||||
|
borderRadius: BorderRadius.circular(0),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(12, 8, 12, 8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppTheme.accent1,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppTheme.primary,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Align(
|
||||||
|
alignment: AlignmentDirectional(0, 0),
|
||||||
|
child: Text(
|
||||||
|
'A',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(12, 0, 8, 0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text( // Label
|
||||||
|
conversation.conversationLabel,
|
||||||
|
style: AppTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 4, 0, 0),
|
||||||
|
child: Text( // Sub-label
|
||||||
|
conversation.conversationSubLabel,
|
||||||
|
style: AppTheme.bodySmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
|
||||||
|
class NoChatsWidget extends StatefulWidget {
|
||||||
|
const NoChatsWidget({
|
||||||
|
super.key,
|
||||||
|
this.icon,
|
||||||
|
String? title,
|
||||||
|
String? body,
|
||||||
|
}) : title = title ?? 'No Comments',
|
||||||
|
body = body ?? 'There are no comments associated with this post.';
|
||||||
|
|
||||||
|
final Widget? icon;
|
||||||
|
final String title;
|
||||||
|
final String body;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<NoChatsWidget> createState() => _NoChatsWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NoChatsWidgetState extends State<NoChatsWidget> {
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setState(VoidCallback callback) {
|
||||||
|
super.setState(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Align(
|
||||||
|
alignment: const AlignmentDirectional(0, -1),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
widget.icon!,
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 16, 0, 0),
|
||||||
|
child: Text(
|
||||||
|
widget.title,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppTheme.headlineSmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(16, 8, 16, 0),
|
||||||
|
child: Text(
|
||||||
|
widget.body,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppTheme.labelMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'options_dialog_widget.dart' show PopupWidget;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class OptionsDialogModel extends FlutterFlowModel<PopupWidget> {
|
||||||
|
/// State fields for stateful widgets in this component.
|
||||||
|
|
||||||
|
// State field(s) for MouseRegion widget.
|
||||||
|
bool mouseRegionHovered1 = false;
|
||||||
|
// State field(s) for MouseRegion widget.
|
||||||
|
bool mouseRegionHovered2 = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
|
||||||
|
import '/components/popup/popup_model.dart';
|
||||||
|
export '/components/popup/popup_model.dart';
|
||||||
|
|
||||||
|
class PopupWidget extends StatefulWidget {
|
||||||
|
const PopupWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PopupWidget> createState() => _PopupWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PopupWidgetState extends State<PopupWidget> {
|
||||||
|
late PopupModel _model;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setState(VoidCallback callback) {
|
||||||
|
super.setState(callback);
|
||||||
|
_model.onUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_model = createModel(context, () => PopupModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_model.maybeDispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Visibility(
|
||||||
|
visible: true,
|
||||||
|
child: Align(
|
||||||
|
alignment: const AlignmentDirectional(0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 570,
|
||||||
|
maxHeight: 375,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
blurRadius: 64,
|
||||||
|
color: Color(0xB2000000),
|
||||||
|
offset: Offset(
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
spreadRadius: 225,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(
|
||||||
|
color: const Color(0xFFE0E3E7),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
alignment: const AlignmentDirectional(0, 0),
|
||||||
|
child: Align(
|
||||||
|
alignment: const AlignmentDirectional(0, 0),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
const Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 12, 0),
|
||||||
|
child: Text(
|
||||||
|
'Refine the components modal.',
|
||||||
|
style: AppTheme.headlineMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
FlutterFlowIconButton(
|
||||||
|
borderColor: const Color(0xFFF1F4F8),
|
||||||
|
borderRadius: 30,
|
||||||
|
borderWidth: 2,
|
||||||
|
buttonSize: 44,
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.close_rounded,
|
||||||
|
color: Color(0xFF57636C),
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const Divider(
|
||||||
|
height: 24,
|
||||||
|
thickness: 2,
|
||||||
|
color: Color(0xFFF1F4F8),
|
||||||
|
),
|
||||||
|
const Text(
|
||||||
|
'FlutterFlow is a visual development platform that allows you to easily create beautiful and responsive user interfaces for your mobile and web applications. With its drag-and-drop interface and pre-built components, you can quickly prototype and build your app without writing any code. \nAdditionally, FlutterFlow\'s real-time preview feature allows you to see your changes in real-time and make adjustments on the fly.',
|
||||||
|
style: AppTheme.labelMedium,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 16, 0, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
FFButtonWidget(
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
text: 'Cancel',
|
||||||
|
options: FFButtonOptions(
|
||||||
|
height: 40,
|
||||||
|
padding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(24, 0, 24, 0),
|
||||||
|
iconPadding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
color: Colors.white,
|
||||||
|
textStyle: AppTheme.bodySmall,
|
||||||
|
elevation: 0,
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: Color(0xFFF1F4F8),
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
hoverColor: const Color(0xFFF1F4F8),
|
||||||
|
hoverTextColor: const Color(0xFF14181B),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
FFButtonWidget(
|
||||||
|
onPressed: () {
|
||||||
|
print('Button pressed ...');
|
||||||
|
},
|
||||||
|
text: 'Create Task',
|
||||||
|
options: FFButtonOptions(
|
||||||
|
width: 130,
|
||||||
|
height: 40,
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
iconPadding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
color: const Color(0xFF4B39EF),
|
||||||
|
textStyle: AppTheme.titleSmall,
|
||||||
|
elevation: 3,
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: Colors.transparent,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
hoverColor: const Color(0xFF2B16ED),
|
||||||
|
hoverTextColor: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'popup_widget.dart' show PopupWidget;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class PopupModel extends FlutterFlowModel<PopupWidget> {
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
|
||||||
|
import 'popup_model.dart';
|
||||||
|
export 'popup_model.dart';
|
||||||
|
|
||||||
|
class PopupWidget extends StatefulWidget {
|
||||||
|
const PopupWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PopupWidget> createState() => _PopupWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PopupWidgetState extends State<PopupWidget> {
|
||||||
|
late PopupModel _model;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setState(VoidCallback callback) {
|
||||||
|
super.setState(callback);
|
||||||
|
_model.onUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_model = createModel(context, () => PopupModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_model.maybeDispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Visibility(
|
||||||
|
visible: true,
|
||||||
|
child: Align(
|
||||||
|
alignment: const AlignmentDirectional(0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 570,
|
||||||
|
maxHeight: 375,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
blurRadius: 64,
|
||||||
|
color: Color(0xB2000000),
|
||||||
|
offset: Offset(
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
spreadRadius: 225,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(
|
||||||
|
color: const Color(0xFFE0E3E7),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
alignment: const AlignmentDirectional(0, 0),
|
||||||
|
child: Align(
|
||||||
|
alignment: const AlignmentDirectional(0, 0),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(24),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
const Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(0, 0, 12, 0),
|
||||||
|
child: Text(
|
||||||
|
'A popup',
|
||||||
|
style: AppTheme.headlineMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
FlutterFlowIconButton(
|
||||||
|
borderColor: const Color(0xFFF1F4F8),
|
||||||
|
borderRadius: 30,
|
||||||
|
borderWidth: 2,
|
||||||
|
buttonSize: 44,
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.close_rounded,
|
||||||
|
color: Color(0xFF57636C),
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const Divider(
|
||||||
|
height: 12,
|
||||||
|
thickness: 2,
|
||||||
|
color: Color(0xFFF1F4F8),
|
||||||
|
),
|
||||||
|
const Text(
|
||||||
|
'Test',
|
||||||
|
style: AppTheme.labelMedium,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 16, 0, 0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
FFButtonWidget(
|
||||||
|
onPressed: () async {
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
text: 'Cancel',
|
||||||
|
options: FFButtonOptions(
|
||||||
|
height: 40,
|
||||||
|
padding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(24, 0, 24, 0),
|
||||||
|
iconPadding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
color: Colors.white,
|
||||||
|
textStyle: AppTheme.bodySmall,
|
||||||
|
elevation: 0,
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: Color(0xFFF1F4F8),
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
hoverColor: const Color(0xFFF1F4F8),
|
||||||
|
hoverTextColor: const Color(0xFF14181B),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
FFButtonWidget(
|
||||||
|
onPressed: () {
|
||||||
|
print('Button pressed ...');
|
||||||
|
},
|
||||||
|
text: 'Action',
|
||||||
|
options: FFButtonOptions(
|
||||||
|
width: 130,
|
||||||
|
height: 40,
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
iconPadding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
color: const Color(0xFF4B39EF),
|
||||||
|
textStyle: AppTheme.titleSmall,
|
||||||
|
elevation: 3,
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: Colors.transparent,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
hoverColor: const Color(0xFF2B16ED),
|
||||||
|
hoverTextColor: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'prompt_box_widget.dart' show PromptBoxWidget;
|
||||||
|
import 'package:easy_debounce/easy_debounce.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class PromptBoxModel extends FlutterFlowModel<PromptBoxWidget> {
|
||||||
|
/// State fields for stateful widgets in this component.
|
||||||
|
|
||||||
|
// State field(s) for TextField widget.
|
||||||
|
FocusNode? textFieldFocusNode;
|
||||||
|
TextEditingController? textController;
|
||||||
|
String? Function(BuildContext, String?)? textControllerValidator;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
textFieldFocusNode?.dispose();
|
||||||
|
textController?.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,285 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:app/components/util/backend.dart';
|
||||||
|
import 'package:camera/camera.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:easy_debounce/easy_debounce.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
|
||||||
|
import '../conversation_thread/chat.dart';
|
||||||
|
import 'prompt_box_model.dart';
|
||||||
|
export 'prompt_box_model.dart';
|
||||||
|
|
||||||
|
class PromptBoxWidget extends StatefulWidget {
|
||||||
|
const PromptBoxWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PromptBoxWidget> createState() => _PromptBoxWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PromptBoxWidgetState extends State<PromptBoxWidget> {
|
||||||
|
late PromptBoxModel _model;
|
||||||
|
String entryText = "";
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setState(VoidCallback callback) {
|
||||||
|
super.setState(callback);
|
||||||
|
_model.onUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_model = createModel(context, () => PromptBoxModel());
|
||||||
|
|
||||||
|
_model.textController ??= TextEditingController();
|
||||||
|
_model.textFieldFocusNode ??= FocusNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_model.maybeDispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
const double buttonPadding = 4;
|
||||||
|
return SafeArea(
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppTheme.secondaryBackground,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
alignment: const AlignmentDirectional(0, 0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
// TODO: Implement the context upload buttons
|
||||||
|
children: [
|
||||||
|
Expanded( // TODO: Video context upload
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(buttonPadding),
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.videocam_outlined,
|
||||||
|
color: AppTheme.accent2,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
print('IconButton pressed ...');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded( // TODO: Gallery context upload
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(buttonPadding),
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.photo_outlined,
|
||||||
|
color: AppTheme.accent2,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
final picker = ImagePicker();
|
||||||
|
final image = await picker.pickImage(source: ImageSource.gallery);
|
||||||
|
|
||||||
|
// TODO: Allow for multiple pictures/photos to be selected.
|
||||||
|
// final images = await picker.pickMultiImage();
|
||||||
|
if (image != null) {
|
||||||
|
|
||||||
|
// TODO: Upload to server and add to conversation.chats
|
||||||
|
String i = Backend.convertToBase64(File(image.path)).toString();
|
||||||
|
Backend.loadedConversation.add(Chat.image(i, true, 1));
|
||||||
|
} else {
|
||||||
|
print('User canceled image selection');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded( // TODO: File context upload
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(buttonPadding),
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.file_upload_outlined,
|
||||||
|
color: AppTheme.accent2,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
final picker = FilePicker.platform;
|
||||||
|
final result = await picker.pickFiles(allowMultiple: true); // Allow multiple files
|
||||||
|
if (result != null) {
|
||||||
|
for (final platformFile in result.files) {
|
||||||
|
// TODO: Upload file to server
|
||||||
|
final file = File(platformFile.path!);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print('User canceled file selection');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(buttonPadding),
|
||||||
|
child: IconButton(
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.camera_alt_outlined,
|
||||||
|
color: AppTheme.accent2,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
final picker = ImagePicker();
|
||||||
|
final image = await picker.pickImage(source: ImageSource.camera);
|
||||||
|
|
||||||
|
if (image != null) {
|
||||||
|
final i = Backend.convertToBase64(File(image.path));
|
||||||
|
|
||||||
|
// TODO: Add to widget rather than display in conversation thread.
|
||||||
|
Backend.loadedConversation.add(Chat.image(i.toString(), true, 1));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(buttonPadding),
|
||||||
|
child: IconButton(
|
||||||
|
icon: Icon(
|
||||||
|
Backend.stt.speechToText.isNotListening ? Icons.mic_off_outlined : Icons.mic_none,
|
||||||
|
color: AppTheme.accent2,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
// TODO: Audio input is still buggy, it appears to only enter the text field once the button is pressed again to stop.
|
||||||
|
if(Backend.stt.speechToText.isNotListening) {
|
||||||
|
print('STT engine starting ...');
|
||||||
|
Backend.stt.startListening();
|
||||||
|
updateText();
|
||||||
|
} else {
|
||||||
|
print('STT engine stopping');
|
||||||
|
Backend.stt.stopListening();
|
||||||
|
updateText();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 7,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(12, 0, 12, 0),
|
||||||
|
child: TextFormField(
|
||||||
|
keyboardAppearance: Brightness.dark,
|
||||||
|
controller: _model.textController,
|
||||||
|
focusNode: _model.textFieldFocusNode,
|
||||||
|
onChanged: (_) => EasyDebounce.debounce(
|
||||||
|
'_model.textController',
|
||||||
|
const Duration(milliseconds: 2000),
|
||||||
|
() => setState(() {}),
|
||||||
|
),
|
||||||
|
autofocus: true,
|
||||||
|
textCapitalization: TextCapitalization.none,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: false,
|
||||||
|
counterStyle: AppTheme.bodyMedium,
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.secondaryText,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: Color(0x00000000),
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
errorBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: Color(0x00000000),
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
focusedErrorBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: Color(0x00000000),
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
filled: true,
|
||||||
|
fillColor: AppTheme.alternate,
|
||||||
|
suffixIcon: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
if(_model.textController.text != "") {
|
||||||
|
// TODO: Connect with multimedia
|
||||||
|
entryText = _model.textController.text;
|
||||||
|
Backend.respondWhenReady(entryText);
|
||||||
|
_model.textController?.clear(); // Clear the text field
|
||||||
|
SystemChannels.textInput.invokeMethod('TextInput.hide');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Icon(
|
||||||
|
Icons.send,
|
||||||
|
color: AppTheme.accent,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
style: AppTheme.displayMedium,
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
maxLines: 5,
|
||||||
|
minLines: 1,
|
||||||
|
textInputAction: TextInputAction.send, // "Send" on keyboard
|
||||||
|
onFieldSubmitted: (text) {
|
||||||
|
// Don't take any action unless there's an actual input.
|
||||||
|
if(_model.textController.text != "") {
|
||||||
|
entryText = _model.textController.text;
|
||||||
|
Backend.respondWhenReady(entryText); // TODO: Connect with multimedia
|
||||||
|
_model.textController?.clear(); // Clear the text field
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateText() {
|
||||||
|
_model.textController.text = Backend.stt.text;
|
||||||
|
entryText = _model.textController.text;
|
||||||
|
print(entryText);
|
||||||
|
print(_model.textController.text);
|
||||||
|
Backend.stt.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import '/components/popup/popup_widget.dart';
|
||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'settings_widget.dart' show SettingsWidget;
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class SettingsModel extends FlutterFlowModel<SettingsWidget> {
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'setup_widget.dart' show SetupWidget;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class SetupModel extends FlutterFlowModel<SetupWidget> {
|
||||||
|
/// State fields for stateful widgets in this page.
|
||||||
|
|
||||||
|
final unfocusNode = FocusNode();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
unfocusNode.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,303 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
|
||||||
|
import 'setup_model.dart';
|
||||||
|
export 'setup_model.dart';
|
||||||
|
|
||||||
|
class SetupWidget extends StatefulWidget {
|
||||||
|
const SetupWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SetupWidget> createState() => _SetupWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SetupWidgetState extends State<SetupWidget>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
|
late SetupModel _model;
|
||||||
|
|
||||||
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
|
||||||
|
final animationsMap = <String, AnimationInfo>{};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_model = createModel(context, () => SetupModel());
|
||||||
|
|
||||||
|
animationsMap.addAll({
|
||||||
|
'containerOnPageLoadAnimation1': AnimationInfo(
|
||||||
|
trigger: AnimationTrigger.onPageLoad,
|
||||||
|
effectsBuilder: () => [
|
||||||
|
VisibilityEffect(duration: 1.ms),
|
||||||
|
FadeEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 400.0.ms,
|
||||||
|
begin: 0.0,
|
||||||
|
end: 1.0,
|
||||||
|
),
|
||||||
|
ScaleEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 400.0.ms,
|
||||||
|
begin: const Offset(3.0, 3.0),
|
||||||
|
end: const Offset(1.0, 1.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
'containerOnPageLoadAnimation2': AnimationInfo(
|
||||||
|
trigger: AnimationTrigger.onPageLoad,
|
||||||
|
effectsBuilder: () => [
|
||||||
|
VisibilityEffect(duration: 300.ms),
|
||||||
|
FadeEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 300.0.ms,
|
||||||
|
duration: 300.0.ms,
|
||||||
|
begin: 0.0,
|
||||||
|
end: 1.0,
|
||||||
|
),
|
||||||
|
ScaleEffect(
|
||||||
|
curve: Curves.bounceOut,
|
||||||
|
delay: 300.0.ms,
|
||||||
|
duration: 300.0.ms,
|
||||||
|
begin: const Offset(0.6, 0.6),
|
||||||
|
end: const Offset(1.0, 1.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
'textOnPageLoadAnimation1': AnimationInfo(
|
||||||
|
trigger: AnimationTrigger.onPageLoad,
|
||||||
|
effectsBuilder: () => [
|
||||||
|
VisibilityEffect(duration: 350.ms),
|
||||||
|
FadeEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 350.0.ms,
|
||||||
|
duration: 400.0.ms,
|
||||||
|
begin: 0.0,
|
||||||
|
end: 1.0,
|
||||||
|
),
|
||||||
|
MoveEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 350.0.ms,
|
||||||
|
duration: 400.0.ms,
|
||||||
|
begin: const Offset(0.0, 30.0),
|
||||||
|
end: const Offset(0.0, 0.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
'textOnPageLoadAnimation2': AnimationInfo(
|
||||||
|
trigger: AnimationTrigger.onPageLoad,
|
||||||
|
effectsBuilder: () => [
|
||||||
|
VisibilityEffect(duration: 400.ms),
|
||||||
|
FadeEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 400.0.ms,
|
||||||
|
duration: 400.0.ms,
|
||||||
|
begin: 0.0,
|
||||||
|
end: 1.0,
|
||||||
|
),
|
||||||
|
MoveEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 400.0.ms,
|
||||||
|
duration: 400.0.ms,
|
||||||
|
begin: const Offset(0.0, 30.0),
|
||||||
|
end: const Offset(0.0, 0.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
'rowOnPageLoadAnimation': AnimationInfo(
|
||||||
|
trigger: AnimationTrigger.onPageLoad,
|
||||||
|
effectsBuilder: () => [
|
||||||
|
VisibilityEffect(duration: 300.ms),
|
||||||
|
FadeEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 300.0.ms,
|
||||||
|
duration: 600.0.ms,
|
||||||
|
begin: 0.0,
|
||||||
|
end: 1.0,
|
||||||
|
),
|
||||||
|
ScaleEffect(
|
||||||
|
curve: Curves.bounceOut,
|
||||||
|
delay: 300.0.ms,
|
||||||
|
duration: 600.0.ms,
|
||||||
|
begin: const Offset(0.6, 0.6),
|
||||||
|
end: const Offset(1.0, 1.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_model.dispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => _model.unfocusNode.canRequestFocus
|
||||||
|
? FocusScope.of(context).requestFocus(_model.unfocusNode)
|
||||||
|
: FocusScope.of(context).unfocus(),
|
||||||
|
child: Scaffold(
|
||||||
|
key: scaffoldKey,
|
||||||
|
backgroundColor: AppTheme.secondaryBackground,
|
||||||
|
body: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 500,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: [
|
||||||
|
AppTheme.primary,
|
||||||
|
AppTheme.error,
|
||||||
|
AppTheme.tertiary
|
||||||
|
],
|
||||||
|
stops: [0, 0.5, 1],
|
||||||
|
begin: AlignmentDirectional(-1, -1),
|
||||||
|
end: AlignmentDirectional(1, 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: [
|
||||||
|
Color(0x00FFFFFF),
|
||||||
|
AppTheme.secondaryBackground
|
||||||
|
],
|
||||||
|
stops: [0, 1],
|
||||||
|
begin: AlignmentDirectional(0, -1),
|
||||||
|
end: AlignmentDirectional(0, 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 120,
|
||||||
|
height: 120,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: AppTheme.accent4,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Image.network(
|
||||||
|
'https://storage.googleapis.com/flutterflow-io-6f20.appspot.com/projects/f-f-templates-q1-23-fbcr63/assets/ax4fvwjz7awx/@4xff_badgeDesign_dark_small.png',
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).animateOnPageLoad(
|
||||||
|
animationsMap['containerOnPageLoadAnimation2']!),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 44, 0, 0),
|
||||||
|
child: const Text(
|
||||||
|
'Welcome!',
|
||||||
|
style: AppTheme.displaySmall,
|
||||||
|
).animateOnPageLoad(
|
||||||
|
animationsMap['textOnPageLoadAnimation1']!),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(44, 8, 44, 0),
|
||||||
|
child: const Text(
|
||||||
|
'Thanks for joining! Access or create your account below, and get started on your journey!',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppTheme.labelMedium,
|
||||||
|
).animateOnPageLoad(
|
||||||
|
animationsMap['textOnPageLoadAnimation2']!),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).animateOnPageLoad(
|
||||||
|
animationsMap['containerOnPageLoadAnimation1']!),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(16, 24, 16, 44),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Align(
|
||||||
|
alignment: const AlignmentDirectional(0, 0),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 0, 8, 16),
|
||||||
|
child: FFButtonWidget(
|
||||||
|
onPressed: () {
|
||||||
|
print('Button pressed ...');
|
||||||
|
},
|
||||||
|
text: 'Get Started',
|
||||||
|
options: FFButtonOptions(
|
||||||
|
width: 230,
|
||||||
|
height: 52,
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
iconPadding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
color: AppTheme
|
||||||
|
.secondaryBackground,
|
||||||
|
textStyle: AppTheme.bodyLarge,
|
||||||
|
elevation: 0,
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.alternate,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Align(
|
||||||
|
alignment: const AlignmentDirectional(0, 0),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(8, 0, 0, 16),
|
||||||
|
child: FFButtonWidget(
|
||||||
|
onPressed: () {
|
||||||
|
print('Button pressed ...');
|
||||||
|
},
|
||||||
|
text: 'My Account',
|
||||||
|
options: FFButtonOptions(
|
||||||
|
width: 230,
|
||||||
|
height: 52,
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
iconPadding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
color: AppTheme.primary,
|
||||||
|
textStyle: AppTheme.titleSmall,
|
||||||
|
elevation: 3,
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: Colors.transparent,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
).animateOnPageLoad(animationsMap['rowOnPageLoadAnimation']!),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'support_form_widget.dart' show SupportFormWidget;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
class SupportFormModel extends FlutterFlowModel<SupportFormWidget> {
|
||||||
|
/// State fields for stateful widgets in this page.
|
||||||
|
|
||||||
|
final unfocusNode = FocusNode();
|
||||||
|
// State field(s) for TextField widget.
|
||||||
|
FocusNode? textFieldFocusNode1;
|
||||||
|
TextEditingController? textController1;
|
||||||
|
String? Function(BuildContext, String?)? textController1Validator;
|
||||||
|
// State field(s) for TextField widget.
|
||||||
|
FocusNode? textFieldFocusNode2;
|
||||||
|
TextEditingController? textController2;
|
||||||
|
String? Function(BuildContext, String?)? textController2Validator;
|
||||||
|
// State field(s) for TextField widget.
|
||||||
|
FocusNode? textFieldFocusNode3;
|
||||||
|
TextEditingController? textController3;
|
||||||
|
String? Function(BuildContext, String?)? textController3Validator;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState(BuildContext context) {}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
unfocusNode.dispose();
|
||||||
|
textFieldFocusNode1?.dispose();
|
||||||
|
textController1?.dispose();
|
||||||
|
|
||||||
|
textFieldFocusNode2?.dispose();
|
||||||
|
textController2?.dispose();
|
||||||
|
|
||||||
|
textFieldFocusNode3?.dispose();
|
||||||
|
textController3?.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,496 @@
|
|||||||
|
import 'package:flutterflow_ui/flutterflow_ui.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../components/support_form_model.dart';
|
||||||
|
export '../components/support_form_model.dart';
|
||||||
|
|
||||||
|
import 'package:app/theme.dart';
|
||||||
|
|
||||||
|
class SupportFormWidget extends StatefulWidget {
|
||||||
|
const SupportFormWidget({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SupportFormWidget> createState() => _SupportFormWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SupportFormWidgetState extends State<SupportFormWidget>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
|
late SupportFormModel _model;
|
||||||
|
|
||||||
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
|
|
||||||
|
final animationsMap = <String, AnimationInfo>{};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_model = createModel(context, () => SupportFormModel());
|
||||||
|
|
||||||
|
_model.textController1 ??= TextEditingController();
|
||||||
|
_model.textFieldFocusNode1 ??= FocusNode();
|
||||||
|
|
||||||
|
_model.textController2 ??= TextEditingController();
|
||||||
|
_model.textFieldFocusNode2 ??= FocusNode();
|
||||||
|
|
||||||
|
_model.textController3 ??= TextEditingController();
|
||||||
|
_model.textFieldFocusNode3 ??= FocusNode();
|
||||||
|
|
||||||
|
animationsMap.addAll({
|
||||||
|
'containerOnPageLoadAnimation1': AnimationInfo(
|
||||||
|
trigger: AnimationTrigger.onPageLoad,
|
||||||
|
effectsBuilder: () => [
|
||||||
|
FadeEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 600.0.ms,
|
||||||
|
begin: 0.0,
|
||||||
|
end: 1.0,
|
||||||
|
),
|
||||||
|
MoveEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 600.0.ms,
|
||||||
|
begin: const Offset(0.0, 110.0),
|
||||||
|
end: const Offset(0.0, 0.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
'containerOnPageLoadAnimation2': AnimationInfo(
|
||||||
|
trigger: AnimationTrigger.onPageLoad,
|
||||||
|
effectsBuilder: () => [
|
||||||
|
FadeEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 600.0.ms,
|
||||||
|
begin: 0.0,
|
||||||
|
end: 1.0,
|
||||||
|
),
|
||||||
|
MoveEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 600.0.ms,
|
||||||
|
begin: const Offset(0.0, 110.0),
|
||||||
|
end: const Offset(0.0, 0.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
'containerOnPageLoadAnimation3': AnimationInfo(
|
||||||
|
trigger: AnimationTrigger.onPageLoad,
|
||||||
|
effectsBuilder: () => [
|
||||||
|
FadeEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 600.0.ms,
|
||||||
|
begin: 0.0,
|
||||||
|
end: 1.0,
|
||||||
|
),
|
||||||
|
MoveEffect(
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
delay: 0.0.ms,
|
||||||
|
duration: 600.0.ms,
|
||||||
|
begin: const Offset(0.0, 110.0),
|
||||||
|
end: const Offset(0.0, 0.0),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
});
|
||||||
|
setupAnimations(
|
||||||
|
animationsMap.values.where((anim) =>
|
||||||
|
anim.trigger == AnimationTrigger.onActionTrigger ||
|
||||||
|
!anim.applyInitialState),
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_model.dispose();
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () => _model.unfocusNode.canRequestFocus
|
||||||
|
? FocusScope.of(context).requestFocus(_model.unfocusNode)
|
||||||
|
: FocusScope.of(context).unfocus(),
|
||||||
|
child: Scaffold(
|
||||||
|
key: scaffoldKey,
|
||||||
|
backgroundColor: AppTheme.secondaryBackground,
|
||||||
|
appBar: AppBar(
|
||||||
|
backgroundColor: AppTheme.secondaryBackground,
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
leading: FlutterFlowIconButton(
|
||||||
|
borderColor: Colors.transparent,
|
||||||
|
borderRadius: 30,
|
||||||
|
borderWidth: 1,
|
||||||
|
buttonSize: 60,
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.arrow_back_rounded,
|
||||||
|
color: AppTheme.primaryTextColor,
|
||||||
|
size: 30,
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
//TODO: context.pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
title: const Text(
|
||||||
|
'Submit Ticket',
|
||||||
|
style: AppTheme.titleLarge,
|
||||||
|
),
|
||||||
|
actions: const [],
|
||||||
|
centerTitle: false,
|
||||||
|
elevation: 0,
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
top: true,
|
||||||
|
child: Align(
|
||||||
|
alignment: const AlignmentDirectional(0, 1),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(16, 12, 16, 0),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
'Welcome to support',
|
||||||
|
style: AppTheme.labelLarge,
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(0, 4, 0, 0),
|
||||||
|
child: Text(
|
||||||
|
'Submit a bug',
|
||||||
|
style: AppTheme.headlineMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(0, 16, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: 120,
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 500,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppTheme
|
||||||
|
.secondaryBackground,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppTheme.alternate,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
8, 16, 8, 16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.email_outlined,
|
||||||
|
color:
|
||||||
|
AppTheme.primary,
|
||||||
|
size: 36,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
0, 12, 0, 0),
|
||||||
|
child: Text(
|
||||||
|
'Email Us',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).animateOnPageLoad(animationsMap[
|
||||||
|
'containerOnPageLoadAnimation1']!),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(0, 16, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: 120,
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 500,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppTheme
|
||||||
|
.secondaryBackground,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppTheme.alternate,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
8, 16, 8, 16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.search_rounded,
|
||||||
|
color:
|
||||||
|
AppTheme.primary,
|
||||||
|
size: 36,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsDirectional.fromSTEB(
|
||||||
|
0, 12, 0, 0),
|
||||||
|
child: Text(
|
||||||
|
'Search FAQs',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).animateOnPageLoad(animationsMap[
|
||||||
|
'containerOnPageLoadAnimation2']!),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
].divide(const SizedBox(width: 12)),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 16, 0, 0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
TextFormField(
|
||||||
|
controller: _model.textController1,
|
||||||
|
focusNode: _model.textFieldFocusNode1,
|
||||||
|
autofocus: true,
|
||||||
|
obscureText: false,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'Channel Name',
|
||||||
|
labelStyle: AppTheme.labelMedium,
|
||||||
|
hintStyle: AppTheme.labelMedium,
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.alternate,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.primary,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
errorBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.error,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
focusedErrorBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.error,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsetsDirectional.fromSTEB(
|
||||||
|
16, 12, 16, 12),
|
||||||
|
),
|
||||||
|
style: AppTheme.bodyMedium,
|
||||||
|
cursorColor: AppTheme.primary,
|
||||||
|
validator: _model.textController1Validator
|
||||||
|
.asValidator(context),
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
controller: _model.textController2,
|
||||||
|
focusNode: _model.textFieldFocusNode2,
|
||||||
|
autofocus: true,
|
||||||
|
obscureText: false,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: 'Channel ID',
|
||||||
|
labelStyle: AppTheme.labelMedium,
|
||||||
|
hintStyle: AppTheme.labelMedium,
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.alternate,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.primary,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
errorBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.error,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
focusedErrorBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.error,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsetsDirectional.fromSTEB(
|
||||||
|
16, 12, 16, 12),
|
||||||
|
),
|
||||||
|
style: AppTheme.bodyMedium,
|
||||||
|
cursorColor: AppTheme.primary,
|
||||||
|
validator: _model.textController2Validator
|
||||||
|
.asValidator(context),
|
||||||
|
),
|
||||||
|
TextFormField(
|
||||||
|
controller: _model.textController3,
|
||||||
|
focusNode: _model.textFieldFocusNode3,
|
||||||
|
autofocus: true,
|
||||||
|
obscureText: false,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelStyle: AppTheme.labelMedium,
|
||||||
|
hintText:
|
||||||
|
'Short Description of what is going on...',
|
||||||
|
hintStyle: AppTheme.labelMedium,
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.alternate,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.primary,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
errorBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.error,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
focusedErrorBorder: OutlineInputBorder(
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: AppTheme.error,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsetsDirectional.fromSTEB(
|
||||||
|
16, 24, 16, 12),
|
||||||
|
),
|
||||||
|
style: AppTheme.bodyMedium,
|
||||||
|
maxLines: 16,
|
||||||
|
minLines: 6,
|
||||||
|
cursorColor: AppTheme.primary,
|
||||||
|
validator: _model.textController3Validator
|
||||||
|
.asValidator(context),
|
||||||
|
),
|
||||||
|
].divide(const SizedBox(height: 12)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 16, 0, 0),
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 500,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color:
|
||||||
|
AppTheme.secondaryBackground,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppTheme.alternate,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.all(8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.add_a_photo_rounded,
|
||||||
|
color: AppTheme.primary,
|
||||||
|
size: 32,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding:
|
||||||
|
EdgeInsetsDirectional.fromSTEB(16, 0, 0, 0),
|
||||||
|
child: Text(
|
||||||
|
'Upload Screenshot',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: AppTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
).animateOnPageLoad(
|
||||||
|
animationsMap['containerOnPageLoadAnimation3']!),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsetsDirectional.fromSTEB(0, 24, 0, 12),
|
||||||
|
child: FFButtonWidget(
|
||||||
|
onPressed: () {
|
||||||
|
print('Button pressed ...');
|
||||||
|
},
|
||||||
|
text: 'Submit Ticket',
|
||||||
|
icon: const Icon(
|
||||||
|
Icons.receipt_long,
|
||||||
|
size: 15,
|
||||||
|
),
|
||||||
|
options: FFButtonOptions(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 48,
|
||||||
|
padding: const EdgeInsets.all(0),
|
||||||
|
iconPadding:
|
||||||
|
const EdgeInsetsDirectional.fromSTEB(0, 0, 0, 0),
|
||||||
|
color: AppTheme.primary,
|
||||||
|
textStyle: AppTheme.titleSmall,
|
||||||
|
elevation: 4,
|
||||||
|
borderSide: const BorderSide(
|
||||||
|
color: Colors.transparent,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(60),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,253 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:app/components/conversation_thread/conversation.dart';
|
||||||
|
import 'package:camera/camera.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
import 'package:app/components/conversation_thread/chat.dart';
|
||||||
|
|
||||||
|
import 'package:app/components/util/speech_to_text.dart';
|
||||||
|
|
||||||
|
import 'model.dart';
|
||||||
|
|
||||||
|
// Uses Singleton design pattern to ensure that any server references across the app are using the same instance.
|
||||||
|
class Backend {
|
||||||
|
// SERVER VARIABLES
|
||||||
|
static final Backend singleBackend = Backend._internal();
|
||||||
|
Backend._internal();
|
||||||
|
// TODO: One-time process to establish server connection is required for easy setup/maintenance.
|
||||||
|
static const url = "http://10.0.2.2:11434/api/"; // For emulated device in testing
|
||||||
|
//static final url = "http://192.168.1.68:11434/api"; // For local access to home server
|
||||||
|
static String endpoint = "";
|
||||||
|
static final Map<String, String> headers = {'Content-Type': 'application/json'};
|
||||||
|
static final bool UI_TESTING = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// AI VARIABLES
|
||||||
|
static final SpeechToText stt = SpeechToText();
|
||||||
|
static late bool _speechEnabled;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// PRIVACY-NECESSARY VARIABLES
|
||||||
|
// TODO: Reorder based on most recent usage.
|
||||||
|
static List<Conversation> conversations = [];
|
||||||
|
static List<Chat> loadedChats = [];
|
||||||
|
static late Conversation loadedConversation;
|
||||||
|
static late List<CameraDescription> cameras;
|
||||||
|
static late CameraController controller;
|
||||||
|
|
||||||
|
|
||||||
|
// RUNTIME & STATUS VARIABLES
|
||||||
|
static late int conversationID;
|
||||||
|
static late int maxConversationID;
|
||||||
|
static late Model model;
|
||||||
|
static String prompt = "";
|
||||||
|
static String response = "";
|
||||||
|
static bool initiated = false;
|
||||||
|
|
||||||
|
// TODO: Verify all different components of STT, TTS, LLM, etc have been initialized.
|
||||||
|
// TODO: Handshake w/ server to validate identity
|
||||||
|
factory Backend() {
|
||||||
|
|
||||||
|
|
||||||
|
return singleBackend;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() async {
|
||||||
|
// Prevent multiple initiations
|
||||||
|
if(!initiated) {
|
||||||
|
initiated = true;
|
||||||
|
// Speech-To-Text engine activation.
|
||||||
|
_speechEnabled = stt.isSpeechEnabled();
|
||||||
|
|
||||||
|
model = Model("llama3"); // Primarily used llama3, testing gemma2
|
||||||
|
maxConversationID = conversations.length;
|
||||||
|
|
||||||
|
cameras = await availableCameras();
|
||||||
|
controller = CameraController(cameras[0], ResolutionPreset.max);
|
||||||
|
controller.initialize(); // TODO: Add error catching on camera
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Dynamically get available models and models that can be pulled.
|
||||||
|
// TODO: Dynamically get the user's default model
|
||||||
|
// TODO: Dynamically obtain conversations.
|
||||||
|
// TODO: Obtain all user permissions at once.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// PRIMARY INTERFACES
|
||||||
|
@Deprecated("Use STT interface directly and use respondWhenReady().")
|
||||||
|
static Future<String> sttGetResponseWhenReady() async {
|
||||||
|
// TODO: In case on-device STT is unavailable, use server-side STT service.
|
||||||
|
if (!_speechEnabled) {
|
||||||
|
return "Unable to process Speech-To-Text on-device.";
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt = stt.getTextWhenReady() as String;
|
||||||
|
conversations[conversationID].add(Chat(prompt, true, 0));
|
||||||
|
if(!UI_TESTING) {
|
||||||
|
httpSendRequest();
|
||||||
|
}
|
||||||
|
conversations[conversationID].add(Chat(response, false, 0));
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void respondWhenReady(String p) async {
|
||||||
|
prompt = p;
|
||||||
|
conversations[conversationID].add(Chat(prompt, true, 0));
|
||||||
|
if(!UI_TESTING) {
|
||||||
|
httpSendRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ImageProvider convertFromBase64(img) {
|
||||||
|
Uint8List imageBytes = base64Decode(img);
|
||||||
|
|
||||||
|
return Image.memory(imageBytes).image;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts image to base64 encoded string for data transfer.
|
||||||
|
static String convertToBase64(f) {
|
||||||
|
List<int> imageBytes = f.readAsBytesSync();
|
||||||
|
String img = base64Encode(imageBytes);
|
||||||
|
|
||||||
|
// TODO: Add special handling for images included in prompts.
|
||||||
|
conversations[conversationID].add(Chat.image(img, true, 1));
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// CONVERSATION MANAGEMENT
|
||||||
|
@Deprecated("")
|
||||||
|
static List<Conversation> getConversationsList() { return conversations; }
|
||||||
|
|
||||||
|
static Conversation getLoadedConversation() { return loadedConversation; }
|
||||||
|
|
||||||
|
// Load conversation should be called prior to any other server requests.
|
||||||
|
static void loadConversation(id) {
|
||||||
|
conversationID = id;
|
||||||
|
|
||||||
|
loadedConversation = conversations[id];
|
||||||
|
loadedChats = loadedConversation.chats;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Better conversation ID management is needed. Preferably randomized IDs to not indicate the number of conversations.
|
||||||
|
static int createConversation() {
|
||||||
|
int id = conversations.length;
|
||||||
|
conversations.add(Conversation(id, "Conversation $id", "Another AI conversation"));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deleteConversation(id) {
|
||||||
|
loadedChats = conversations[conversationID].chats; // TODO: Temporarily saving the chats for "undo" popup.
|
||||||
|
conversations.removeAt(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated('Just directly get loadedChats list. Unless multiple chats can be opened simultaneously?')
|
||||||
|
static List<Chat> getChatsByConversationID(id) { return conversations[id].chats; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// SERVER UTILS
|
||||||
|
static List<Map<String, String>> convertMessages() {
|
||||||
|
// TODO: Integrate with getConversationByID()
|
||||||
|
List<Map<String, String>> messageList = [];
|
||||||
|
for (Chat c in loadedChats) {
|
||||||
|
messageList.add({
|
||||||
|
"role": c.role ? "user" : "assistant",
|
||||||
|
"content": c.content,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formats the prompt in JSON.
|
||||||
|
static String constructPrompt() {
|
||||||
|
// TODO: Allow for additional flags, ie. continuous conversation, images, etc.
|
||||||
|
// TODO: Allow for toggleable states between stream
|
||||||
|
// TODO: Allow for different models to be dynamically selected.
|
||||||
|
|
||||||
|
// TODO: Further adaption of API calls to allow for images to/from the AI model
|
||||||
|
// Example API call for image recognition
|
||||||
|
// curl http://localhost:11434/api/generate -d '{
|
||||||
|
// "model": "llava",
|
||||||
|
// "prompt":"What is in this picture?",
|
||||||
|
// "stream": false,
|
||||||
|
// "images": ["iVBORw0KGgoAAAANSUhEUgAAAG0AAABmCAYAAADBPx+VAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAA3VSURBVHgB7Z27r0zdG8fX743i1bi1ikMoFMQloXRpKFFIqI7LH4BEQ+NWIkjQuSWCRIEoULk0gsK1kCBI0IhrQVT7tz/7zZo888yz1r7MnDl7z5xvsjkzs2fP3uu71nNfa7lkAsm7d++Sffv2JbNmzUqcc8m0adOSzZs3Z+/XES4ZckAWJEGWPiCxjsQNLWmQsWjRIpMseaxcuTKpG/7HP27I8P79e7dq1ars/yL4/v27S0ejqwv+cUOGEGGpKHR37tzJCEpHV9tnT58+dXXCJDdECBE2Ojrqjh071hpNECjx4cMHVycM1Uhbv359B2F79+51586daxN/+pyRkRFXKyRDAqxEp4yMlDDzXG1NPnnyJKkThoK0VFd1ELZu3TrzXKxKfW7dMBQ6bcuWLW2v0VlHjx41z717927ba22U9APcw7Nnz1oGEPeL3m3p2mTAYYnFmMOMXybPPXv2bNIPpFZr1NHn4HMw0KRBjg9NuRw95s8PEcz/6DZELQd/09C9QGq5RsmSRybqkwHGjh07OsJSsYYm3ijPpyHzoiacg35MLdDSIS/O1yM778jOTwYUkKNHWUzUWaOsylE00MyI0fcnOwIdjvtNdW/HZwNLGg+sR1kMepSNJXmIwxBZiG8tDTpEZzKg0GItNsosY8USkxDhD0Rinuiko2gfL/RbiD2LZAjU9zKQJj8RDR0vJBR1/Phx9+PHj9Z7REF4nTZkxzX4LCXHrV271qXkBAPGfP/atWvu/PnzHe4C97F48eIsRLZ9+3a3f/9+87dwP1JxaF7/3r17ba+5l4EcaVo0lj3SBq5kGTJSQmLWMjgYNei2GPT1MuMqGTDEFHzeQSP2wi/jGnkmPJ/nhccs44jvDAxpVcxnq0F6eT8h4ni/iIWpR5lPyA6ETkNXoSukvpJAD3AsXLiwpZs49+fPn5ke4j10TqYvegSfn0OnafC+Tv9ooA/JPkgQysqQNBzagXY55nO/oa1F7qvIPWkRL12WRpMWUvpVDYmxAPehxWSe8ZEXL20sadYIozfmNch4QJPAfeJgW3rNsnzphBKNJM2KKODo1rVOMRYik5ETy3ix4qWNI81qAAirizgMIc+yhTytx0JWZuNI03qsrgWlGtwjoS9XwgUhWGyhUaRZZQNNIEwCiXD16tXcAHUs79co0vSD8rrJCIW98pzvxpAWyyo3HYwqS0+H0BjStClcZJT5coMm6D2LOF8TolGJtK9fvyZpyiC5ePFi9nc/oJU4eiEP0jVoAnHa9wyJycITMP78+eMeP37sXrx44d6+fdt6f82aNdkx1pg9e3Zb5W+RSRE+n+VjksQWifvVaTKFhn5O8my63K8Qabdv33b379/PiAP//vuvW7BggZszZ072/+TJk91YgkafPn166zXB1rQHFvouAWHq9z3SEevSUerqCn2/dDCeta2jxYbr69evk4MHDyY7d+7MjhMnTiTPnz9Pfv/+nfQT2ggpO2dMF8cghuoM7Ygj5iWCqRlGFml0QC/ftGmTmzt3rmsaKDsgBSPh0/8yPeLLBihLkOKJc0jp8H8vUzcxIA1k6QJ/c78tWEyj5P3o4u9+jywNPdJi5rAH9x0KHcl4Hg570eQp3+vHXGyrmEeigzQsQsjavXt38ujRo44LQuDDhw+TW7duRS1HGgMxhNXHgflaNTOsHyKvHK5Ijo2jbFjJBQK9YwFd6RVMzfgRBmEfP37suBBm/p49e1qjEP2mwTViNRo0VJWH1deMXcNK08uUjVUu7s/zRaL+oLNxz1bpANco4npUgX4G2eFbpDFyQoQxojBCpEGSytmOH8qrH5Q9vuzD6ofQylkCUmh8DBAr+q8JCyVNtWQIidKQE9wNtLSQnS4jDSsxNHogzFuQBw4cyM61UKVsjfr3ooBkPSqqQHesUPWVtzi9/vQi1T+rJj7WiTz4Pt/l3LxUkr5P2VYZaZ4URpsE+st/dujQoaBBYokbrz/8TJNQYLSonrPS9kUaSkPeZyj1AWSj+d+VBoy1pIWVNed8P0Ll/ee5HdGRhrHhR5GGN0r4LGZBaj8oFDJitBTJzIZgFcmU0Y8ytWMZMzJOaXUSrUs5RxKnrxmbb5YXO9VGUhtpXldhEUogFr3IzIsvlpmdosVcGVGXFWp2oU9kLFL3dEkSz6NHEY1sjSRdIuDFWEhd8KxFqsRi1uM/nz9/zpxnwlESONdg6dKlbsaMGS4EHFHtjFIDHwKOo46l4TxSuxgDzi+rE2jg+BaFruOX4HXa0Nnf1lwAPufZeF8/r6zD97WK2qFnGjBxTw5qNGPxT+5T/r7/7RawFC3j4vTp09koCxkeHjqbHJqArmH5UrFKKksnxrK7FuRIs8STfBZv+luugXZ2pR/pP9Ois4z+TiMzUUkUjD0iEi1fzX8GmXyuxUBRcaUfykV0YZnlJGKQpOiGB76x5GeWkWWJc3mOrK6S7xdND+W5N6XyaRgtWJFe13GkaZnKOsYqGdOVVVbGupsyA/l7emTLHi7vwTdirNEt0qxnzAvBFcnQF16xh/TMpUuXHDowhlA9vQVraQhkudRdzOnK+04ZSP3DUhVSP61YsaLtd/ks7ZgtPcXqPqEafHkdqa84X6aCeL7YWlv6edGFHb+ZFICPlljHhg0bKuk0CSvVznWsotRu433alNdFrqG45ejoaPCaUkWERpLXjzFL2Rpllp7PJU2a/v7Ab8N05/9t27Z16KUqoFGsxnI9EosS2niSYg9SpU6B4JgTrvVW1flt1sT+0ADIJU2maXzcUTraGCRaL1Wp9rUMk16PMom8QhruxzvZIegJjFU7LLCePfS8uaQdPny4jTTL0dbee5mYokQsXTIWNY46kuMbnt8Kmec+LGWtOVIl9cT1rCB0V8WqkjAsRwta93TbwNYoGKsUSChN44lgBNCoHLHzquYKrU6qZ8lolCIN0Rh6cP0Q3U6I6IXILYOQI513hJaSKAorFpuHXJNfVlpRtmYBk1Su1obZr5dnKAO+L10Hrj3WZW+E3qh6IszE37F6EB+68mGpvKm4eb9bFrlzrok7fvr0Kfv727dvWRmdVTJHw0qiiCUSZ6wCK+7XL/AcsgNyL74DQQ730sv78Su7+t/A36MdY0sW5o40ahslXr58aZ5HtZB8GH64m9EmMZ7FpYw4T6QnrZfgenrhFxaSiSGXtPnz57e9TkNZLvTjeqhr734CNtrK41L40sUQckmj1lGKQ0rC37x544r8eNXRpnVE3ZZY7zXo8NomiO0ZUCj2uHz58rbXoZ6gc0uA+F6ZeKS/jhRDUq8MKrTho9fEkihMmhxtBI1DxKFY9XLpVcSkfoi8JGnToZO5sU5aiDQIW716ddt7ZLYtMQlhECdBGXZZMWldY5BHm5xgAroWj4C0hbYkSc/jBmggIrXJWlZM6pSETsEPGqZOndr2uuuR5rF169a2HoHPdurUKZM4CO1WTPqaDaAd+GFGKdIQkxAn9RuEWcTRyN2KSUgiSgF5aWzPTeA/lN5rZubMmR2bE4SIC4nJoltgAV/dVefZm72AtctUCJU2CMJ327hxY9t7EHbkyJFseq+EJSY16RPo3Dkq1kkr7+q0bNmyDuLQcZBEPYmHVdOBiJyIlrRDq41YPWfXOxUysi5fvtyaj+2BpcnsUV/oSoEMOk2CQGlr4ckhBwaetBhjCwH0ZHtJROPJkyc7UjcYLDjmrH7ADTEBXFfOYmB0k9oYBOjJ8b4aOYSe7QkKcYhFlq3QYLQhSidNmtS2RATwy8YOM3EQJsUjKiaWZ+vZToUQgzhkHXudb/PW5YMHD9yZM2faPsMwoc7RciYJXbGuBqJ1UIGKKLv915jsvgtJxCZDubdXr165mzdvtr1Hz5LONA8jrUwKPqsmVesKa49S3Q4WxmRPUEYdTjgiUcfUwLx589ySJUva3oMkP6IYddq6HMS4o55xBJBUeRjzfa4Zdeg56QZ43LhxoyPo7Lf1kNt7oO8wWAbNwaYjIv5lhyS7kRf96dvm5Jah8vfvX3flyhX35cuX6HfzFHOToS1H4BenCaHvO8pr8iDuwoUL7tevX+b5ZdbBair0xkFIlFDlW4ZknEClsp/TzXyAKVOmmHWFVSbDNw1l1+4f90U6IY/q4V27dpnE9bJ+v87QEydjqx/UamVVPRG+mwkNTYN+9tjkwzEx+atCm/X9WvWtDtAb68Wy9LXa1UmvCDDIpPkyOQ5ZwSzJ4jMrvFcr0rSjOUh+GcT4LSg5ugkW1Io0/SCDQBojh0hPlaJdah+tkVYrnTZowP8iq1F1TgMBBauufyB33x1v+NWFYmT5KmppgHC+NkAgbmRkpD3yn9QIseXymoTQFGQmIOKTxiZIWpvAatenVqRVXf2nTrAWMsPnKrMZHz6bJq5jvce6QK8J1cQNgKxlJapMPdZSR64/UivS9NztpkVEdKcrs5alhhWP9NeqlfWopzhZScI6QxseegZRGeg5a8C3Re1Mfl1ScP36ddcUaMuv24iOJtz7sbUjTS4qBvKmstYJoUauiuD3k5qhyr7QdUHMeCgLa1Ear9NquemdXgmum4fvJ6w1lqsuDhNrg1qSpleJK7K3TF0Q2jSd94uSZ60kK1e3qyVpQK6PVWXp2/FC3mp6jBhKKOiY2h3gtUV64TWM6wDETRPLDfSakXmH3w8g9Jlug8ZtTt4kVF0kLUYYmCCtD/DrQ5YhMGbA9L3ucdjh0y8kOHW5gU/VEEmJTcL4Pz/f7mgoAbYkAAAAAElFTkSuQmCC"]
|
||||||
|
// }'
|
||||||
|
|
||||||
|
Map<String, dynamic> data;
|
||||||
|
|
||||||
|
if(loadedConversation.conversationContext) {
|
||||||
|
loadedChats = [...loadedChats, Chat(prompt, true, 0)];
|
||||||
|
endpoint = "chat";
|
||||||
|
|
||||||
|
List<Map<String, String>> messageList = convertMessages();
|
||||||
|
|
||||||
|
// Last prompt was text
|
||||||
|
if(loadedChats.last.chatType == 0) {
|
||||||
|
data = {
|
||||||
|
"model": model.name,
|
||||||
|
"messages": messageList,
|
||||||
|
"stream": loadedConversation.stream,
|
||||||
|
};
|
||||||
|
// Last prompt was image
|
||||||
|
} else { //if (loadedChats.last.chatType == 1) {
|
||||||
|
// TODO: Do some wizardry to pipe the output of llava as additional context for the user's actual prompt or something.
|
||||||
|
data = {
|
||||||
|
"model": "llava",
|
||||||
|
"prompt": "What is in this picture?",
|
||||||
|
"stream": loadedConversation.stream,
|
||||||
|
"images" : [loadedChats.last.content],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
endpoint = "generate";
|
||||||
|
data = {
|
||||||
|
"model": model.name,
|
||||||
|
"prompt": prompt,
|
||||||
|
"stream": loadedConversation.stream,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode the JSON payload
|
||||||
|
return json.encode(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the HTTP request to the server.
|
||||||
|
static void httpSendRequest() async {
|
||||||
|
// TODO: Add AES256 encryption to the prompt/messages thread.
|
||||||
|
// TODO: Add SHA256 checksum to be sent and verified to prevent/notify in case of data loss.
|
||||||
|
String json = constructPrompt();
|
||||||
|
|
||||||
|
// Send the HTTP POST request
|
||||||
|
final serverResponse = await http.post(
|
||||||
|
Uri.parse('$url$endpoint'),
|
||||||
|
headers: headers,
|
||||||
|
body: json,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (serverResponse.statusCode == 200) {
|
||||||
|
Map<String, dynamic> re = jsonDecode(serverResponse.body);
|
||||||
|
if(conversations[conversationID].conversationContext) {
|
||||||
|
response = re["message"]["content"];
|
||||||
|
// TODO: Modify in case of different response types.
|
||||||
|
loadedChats = [...loadedChats, Chat(response, false, 0)];
|
||||||
|
} else {
|
||||||
|
response = re["response"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conversations[conversationID].add(Chat(response, false, 0));
|
||||||
|
|
||||||
|
prompt = "";
|
||||||
|
response = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class Model {
|
||||||
|
late String name;
|
||||||
|
|
||||||
|
Model(this.name);
|
||||||
|
}
|
||||||