Showing preview only (200K chars total). Download the full file or copy to clipboard to get everything.
Repository: davefaliskie/travel_treasury
Branch: master
Commit: 72149e3bb1bb
Files: 83
Total size: 179.4 KB
Directory structure:
gitextract_mhc07qrs/
├── .github/
│ └── FUNDING.yml
├── .gitignore
├── .metadata
├── LICENSE
├── README.md
├── android/
│ ├── app/
│ │ ├── build.gradle
│ │ └── src/
│ │ ├── debug/
│ │ │ └── AndroidManifest.xml
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin/
│ │ │ │ └── com/
│ │ │ │ └── a1manstartup/
│ │ │ │ └── travel_budget/
│ │ │ │ └── MainActivity.kt
│ │ │ └── res/
│ │ │ ├── drawable/
│ │ │ │ └── launch_background.xml
│ │ │ ├── mipmap-anydpi-v26/
│ │ │ │ └── ic_launcher.xml
│ │ │ └── values/
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ │ └── profile/
│ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ ├── settings.gradle
│ └── settings_aar.gradle
├── assets/
│ └── sun_clouds.flr
├── ios/
│ ├── Flutter/
│ │ ├── .last_build_id
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ ├── Flutter.podspec
│ │ ├── Release.xcconfig
│ │ └── flutter_export_environment.sh
│ ├── Podfile
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── LaunchImage.imageset/
│ │ │ ├── Contents.json
│ │ │ └── README.md
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ ├── Runner-Bridging-Header.h
│ │ └── Runner.entitlements
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ └── Runner.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ └── IDEWorkspaceChecks.plist
├── lib/
│ ├── classes/
│ │ └── progress_painter.dart
│ ├── generated/
│ │ └── i18n.dart
│ ├── main.dart
│ ├── models/
│ │ ├── Place.dart
│ │ ├── Trip.dart
│ │ └── User.dart
│ ├── services/
│ │ ├── admob_service.dart
│ │ ├── auth_service.dart
│ │ ├── custom_colors.dart
│ │ └── firebase_service.dart
│ ├── views/
│ │ ├── deposit_view.dart
│ │ ├── detail_trip_view.dart
│ │ ├── edit_notes_view.dart
│ │ ├── first_view.dart
│ │ ├── home_view.dart
│ │ ├── home_widgets/
│ │ │ ├── current_daily_budget.dart
│ │ │ ├── days_until_trip.dart
│ │ │ ├── home_header.dart
│ │ │ ├── notes.dart
│ │ │ ├── percent_saved.dart
│ │ │ ├── saved_vs_needed.dart
│ │ │ ├── travel_type.dart
│ │ │ └── trip_details_card.dart
│ │ ├── navigation_view.dart
│ │ ├── new_trips/
│ │ │ ├── budget_view.dart
│ │ │ ├── date_view.dart
│ │ │ ├── location_view.dart
│ │ │ └── summary_view.dart
│ │ ├── past_trips_view.dart
│ │ ├── profile_view.dart
│ │ └── sign_up_view.dart
│ └── widgets/
│ ├── calculator_widget.dart
│ ├── custom_dialog.dart
│ ├── divider_with_text_widget.dart
│ ├── money_text_field.dart
│ ├── provider_widget.dart
│ ├── rounded_button.dart
│ └── trip_card.dart
├── pubspec.yaml
├── res/
│ └── values/
│ └── strings_en.arb
└── test/
└── widget_test.dart
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
custom: ['https://1manstartup.com/donate']
================================================
FILE: .gitignore
================================================
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# Visual Studio Code related
.vscode/
# Flutter/Dart/Pub related
**/doc/api/
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Android related
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
**/android/key.properties
# iOS/XCode related
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
# Exceptions to above rules.
!**/ios/**/default.mode1v3
!**/ios/**/default.mode2v3
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
*google-services.json
*GoogleService-Info.plist
*lib/credentials.dart
================================================
FILE: .metadata
================================================
# 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: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b
channel: stable
project_type: app
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 Dave Faliskie
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Travel Treasury
[Download The Live App](https://traveltreasury.app)

This repository contains all the code written throughout the 1ManStartup YouTube tutorials for building a travel budget app using Flutter
[View the channel on YouTube](https://www.youtube.com/channel/UC8xcnxN4CyXdPCeUN1eURPg)
## How To Use This Resource
Each episode where code is created or modified will have an associated branch
in this repo. The code in each episode's branch will contain the completed code from that episode
and the branch will remain in that state.
The master branch will contain the most recent version of code, and be considered the "production" version.
This means the master branch will always be the most up to date.
Any questions should be asked in the comments of the relevant video on YouTube.
## Setup Firebase Database
After Episode 15 you will need to configure your own Firebase project. Most importantly you will need to generate and include your own google-services.json file for Android and GoogleServices-Info.plist file for iOS. Full instructions on how to configure Firebase for this project can be found in [Episode 15 on YouTube](https://youtu.be/8L0YWmVYIqU)
================================================
FILE: android/app/build.gradle
================================================
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply plugin: 'com.google.firebase.crashlytics'
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
compileSdkVersion 28
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
applicationId "com.a1manstartup.travel_budget"
minSdkVersion 21
targetSdkVersion 29
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// TODO: find a better solution to the DEX reference limit https://developer.android.com/studio/build/multidex
multiDexEnabled true
}
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:multidex:1.0.3'
}
apply plugin: 'com.google.gms.google-services'
================================================
FILE: android/app/src/debug/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.a1manstartup.travel_budget">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
================================================
FILE: android/app/src/main/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.a1manstartup.travel_budget">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="Travel Treasury"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in @style/LaunchTheme). -->
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-2334510780816542~7385148076"/>
</application>
<uses-permission android:name="android.permission.INTERNET" android:maxSdkVersion="28" />
</manifest>
================================================
FILE: android/app/src/main/kotlin/com/a1manstartup/travel_budget/MainActivity.kt
================================================
package com.a1manstartup.travel_budget
import android.os.Bundle
import io.flutter.app.FlutterActivity
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
}
}
================================================
FILE: android/app/src/main/res/drawable/launch_background.xml
================================================
<?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" /> -->
<item>
<bitmap
android:gravity="center"
android:src="@drawable/launch_screen" />
</item>
</layer-list>
================================================
FILE: android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
</adaptive-icon>
================================================
FILE: android/app/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#57AEAF</color>
</resources>
================================================
FILE: android/app/src/main/res/values/styles.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
Flutter draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
</resources>
================================================
FILE: android/app/src/profile/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.a1manstartup.travel_budget">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
================================================
FILE: android/build.gradle
================================================
buildscript {
ext.kotlin_version = '1.3.21'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.3'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.2.0'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}
================================================
FILE: android/gradle/wrapper/gradle-wrapper.properties
================================================
#Fri Jun 23 08:50:38 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
================================================
FILE: android/gradle.properties
================================================
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
android.enableR8=true
================================================
FILE: android/settings.gradle
================================================
include ':app'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}
================================================
FILE: android/settings_aar.gradle
================================================
include ':app'
================================================
FILE: ios/Flutter/.last_build_id
================================================
ff43a8078c18a80d1d983aec4895d6ad
================================================
FILE: ios/Flutter/AppFrameworkInfo.plist
================================================
<?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>8.0</string>
</dict>
</plist>
================================================
FILE: ios/Flutter/Debug.xcconfig
================================================
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
================================================
FILE: ios/Flutter/Flutter.podspec
================================================
#
# NOTE: This podspec is NOT to be published. It is only used as a local source!
#
Pod::Spec.new do |s|
s.name = 'Flutter'
s.version = '1.0.0'
s.summary = 'High-performance, high-fidelity mobile apps.'
s.description = <<-DESC
Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS.
DESC
s.homepage = 'https://flutter.io'
s.license = { :type => 'MIT' }
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
s.ios.deployment_target = '8.0'
s.vendored_frameworks = 'Flutter.framework'
end
================================================
FILE: ios/Flutter/Release.xcconfig
================================================
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
================================================
FILE: ios/Flutter/flutter_export_environment.sh
================================================
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=/Users/davefaliskie/flutter"
export "FLUTTER_APPLICATION_PATH=/Users/davefaliskie/Code/travel_budget"
export "FLUTTER_TARGET=/Users/davefaliskie/Code/travel_budget/lib/main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
export "OTHER_LDFLAGS=$(inherited) -framework Flutter"
export "FLUTTER_FRAMEWORK_DIR=/Users/davefaliskie/flutter/bin/cache/artifacts/engine/ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "DART_DEFINES=flutter.inspector.structuredErrors%3Dtrue"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.packages"
================================================
FILE: ios/Podfile
================================================
# Uncomment this line to define a global platform for your project
# platform :ios, '9.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__))
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
================================================
FILE: ios/Runner/AppDelegate.swift
================================================
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
================================================
FILE: ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"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"
}
}
================================================
FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
================================================
{
"images" : [
{
"filename" : "launch_screen.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "launch_screen@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "launch_screen@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
================================================
FILE: ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
================================================
# 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.
================================================
FILE: ios/Runner/Base.lproj/LaunchScreen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</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">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<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">
<rect key="frame" x="-113" y="-120" width="640" height="1136"/>
</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="76.811594202898561" y="251.11607142857142"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="640" height="1136"/>
</resources>
</document>
================================================
FILE: ios/Runner/Base.lproj/Main.storyboard
================================================
<?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>
================================================
FILE: ios/Runner/Info.plist
================================================
<?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>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Travel Treasury</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.635382246089-feadgcif5jb704jtq2nir0d6cnh8fu02</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.635382246089-egv2iuv19s1e0gjiq7rqvngu4c7e7su0</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-2334510780816542~6726672523</string>
<key>LSApplicationCategoryType</key>
<string></string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>io.flutter.embedded_views_preview</key>
<true/>
</dict>
</plist>
================================================
FILE: ios/Runner/Runner-Bridging-Header.h
================================================
#import "GeneratedPluginRegistrant.h"
================================================
FILE: ios/Runner/Runner.entitlements
================================================
<?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>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
</dict>
</plist>
================================================
FILE: ios/Runner.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
79B7BE68738E518A2180EBC1 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A2C587E9A5CE2029DC627BB1 /* Pods_Runner.framework */; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
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 */; };
F661854B22D2FB7A00F470E2 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = F661854A22D2FB7900F470E2 /* GoogleService-Info.plist */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
4B222A4CE387272255EFF8F4 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
585F8E30EE2A7E3719072D33 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
6D26CDADDD27BBED144A21CE /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
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>"; };
A2C587E9A5CE2029DC627BB1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F60F054123AED29C00A7CBC4 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
F661854A22D2FB7900F470E2 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
79B7BE68738E518A2180EBC1 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
7AEB469C9BCC6CEA8F744F18 /* Pods */ = {
isa = PBXGroup;
children = (
585F8E30EE2A7E3719072D33 /* Pods-Runner.debug.xcconfig */,
6D26CDADDD27BBED144A21CE /* Pods-Runner.release.xcconfig */,
4B222A4CE387272255EFF8F4 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
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 */,
7AEB469C9BCC6CEA8F744F18 /* Pods */,
D77848A49B74BD0A44544A5F /* Frameworks */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
F60F054123AED29C00A7CBC4 /* Runner.entitlements */,
F661854A22D2FB7900F470E2 /* GoogleService-Info.plist */,
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
);
name = "Supporting Files";
sourceTree = "<group>";
};
D77848A49B74BD0A44544A5F /* Frameworks */ = {
isa = PBXGroup;
children = (
A2C587E9A5CE2029DC627BB1 /* Pods_Runner.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
55FBF33E8A6D71BEB6B19B9A /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
68376A1452E274003D21895A /* [CP] Embed Pods Frameworks */,
9CFF9FF5EF81DF04E13A03E3 /* [CP] Copy Pods Resources */,
F61820892586ED4B007F31CA /* Run Script Crashlytics */,
);
buildRules = (
);
dependencies = (
);
name = Runner;
productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0910;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
DevelopmentTeam = 8V4XE9BJVC;
LastSwiftMigration = 0910;
ProvisioningStyle = Automatic;
SystemCapabilities = {
com.apple.BackgroundModes = {
enabled = 1;
};
};
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
F661854B22D2FB7A00F470E2 /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
55FBF33E8A6D71BEB6B19B9A /* [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;
};
68376A1452E274003D21895A /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/AppAuth/AppAuth.framework",
"${BUILT_PRODUCTS_DIR}/BoringSSL-GRPC/openssl_grpc.framework",
"${PODS_ROOT}/../Flutter/Flutter.framework",
"${BUILT_PRODUCTS_DIR}/GTMAppAuth/GTMAppAuth.framework",
"${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework",
"${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework",
"${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework",
"${BUILT_PRODUCTS_DIR}/abseil/absl.framework",
"${BUILT_PRODUCTS_DIR}/apple_sign_in/apple_sign_in.framework",
"${BUILT_PRODUCTS_DIR}/device_info/device_info.framework",
"${BUILT_PRODUCTS_DIR}/gRPC-C++/grpcpp.framework",
"${BUILT_PRODUCTS_DIR}/gRPC-Core/grpc.framework",
"${BUILT_PRODUCTS_DIR}/leveldb-library/leveldb.framework",
"${BUILT_PRODUCTS_DIR}/libPhoneNumber-iOS/libPhoneNumber_iOS.framework",
"${BUILT_PRODUCTS_DIR}/libphonenumber/libphonenumber.framework",
"${BUILT_PRODUCTS_DIR}/nanopb/nanopb.framework",
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AppAuth.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/openssl_grpc.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMAppAuth.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBLPromises.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/absl.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/apple_sign_in.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/device_info.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/grpcpp.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/grpc.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/leveldb.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libPhoneNumber_iOS.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libphonenumber.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/nanopb.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
);
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;
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";
};
9CFF9FF5EF81DF04E13A03E3 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh",
"${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleSignIn.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
F61820892586ED4B007F31CA /* Run Script Crashlytics */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Run Script Crashlytics";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n${PODS_ROOT}/FirebaseCrashlytics/run\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_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_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = 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;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 8V4XE9BJVC;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.a1manstartup.travelBudget1;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_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_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_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_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
97C147061CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 8V4XE9BJVC;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.a1manstartup.travelBudget1;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = On;
SWIFT_VERSION = 4.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;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 8V4XE9BJVC;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.a1manstartup.travelBudget1;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_SWIFT3_OBJC_INFERENCE = On;
SWIFT_VERSION = 4.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147031CF9000F007C117D /* Debug */,
97C147041CF9000F007C117D /* Release */,
249021D3217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
isa = XCConfigurationList;
buildConfigurations = (
97C147061CF9000F007C117D /* Debug */,
97C147071CF9000F007C117D /* Release */,
249021D4217E4FDB00AE95B9 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 97C146E61CF9000F007C117D /* Project object */;
}
================================================
FILE: ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?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>
================================================
FILE: ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
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"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
================================================
FILE: ios/Runner.xcworkspace/contents.xcworkspacedata
================================================
<?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>
================================================
FILE: ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?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>
================================================
FILE: lib/classes/progress_painter.dart
================================================
import 'package:flutter/material.dart';
import 'dart:math';
class ProgressPainter extends CustomPainter {
Color defaultCircleColor;
Color percentageCompletedCircleColor;
double completedPercentage;
double circleWidth;
ProgressPainter(
{this.defaultCircleColor,
this.percentageCompletedCircleColor,
this.completedPercentage,
this.circleWidth});
getPaint(Color color) {
return Paint()
..color = color
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = circleWidth;
}
@override
void paint(Canvas canvas, Size size) {
Paint defaultCirclePaint = getPaint(defaultCircleColor);
Paint progressCirclePaint = getPaint(percentageCompletedCircleColor);
Offset center = Offset(size.width / 2, size.height / 2);
double radius = min(size.width / 2, size.height / 2);
canvas.drawCircle(center, radius, defaultCirclePaint);
double arcAngle = 2 * pi * (completedPercentage / 100);
canvas.drawArc(Rect.fromCircle(center: center, radius: radius), -pi / 2,
arcAngle, false, progressCirclePaint);
}
@override
bool shouldRepaint(CustomPainter painter) {
return true;
}
}
================================================
FILE: lib/generated/i18n.dart
================================================
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
// ignore_for_file: non_constant_identifier_names
// ignore_for_file: camel_case_types
// ignore_for_file: prefer_single_quotes
// This file is automatically generated. DO NOT EDIT, all your changes would be lost.
class S implements WidgetsLocalizations {
const S();
static S current;
static const GeneratedLocalizationsDelegate delegate =
GeneratedLocalizationsDelegate();
static S of(BuildContext context) => Localizations.of<S>(context, S);
@override
TextDirection get textDirection => TextDirection.ltr;
}
class $en extends S {
const $en();
}
class GeneratedLocalizationsDelegate extends LocalizationsDelegate<S> {
const GeneratedLocalizationsDelegate();
List<Locale> get supportedLocales {
return const <Locale>[
Locale("en", ""),
];
}
LocaleListResolutionCallback listResolution({Locale fallback, bool withCountry = true}) {
return (List<Locale> locales, Iterable<Locale> supported) {
if (locales == null || locales.isEmpty) {
return fallback ?? supported.first;
} else {
return _resolve(locales.first, fallback, supported, withCountry);
}
};
}
LocaleResolutionCallback resolution({Locale fallback, bool withCountry = true}) {
return (Locale locale, Iterable<Locale> supported) {
return _resolve(locale, fallback, supported, withCountry);
};
}
@override
Future<S> load(Locale locale) {
final String lang = getLang(locale);
if (lang != null) {
switch (lang) {
case "en":
S.current = const $en();
return SynchronousFuture<S>(S.current);
default:
// NO-OP.
}
}
S.current = const S();
return SynchronousFuture<S>(S.current);
}
@override
bool isSupported(Locale locale) => _isSupported(locale, true);
@override
bool shouldReload(GeneratedLocalizationsDelegate old) => false;
///
/// Internal method to resolve a locale from a list of locales.
///
Locale _resolve(Locale locale, Locale fallback, Iterable<Locale> supported, bool withCountry) {
if (locale == null || !_isSupported(locale, withCountry)) {
return fallback ?? supported.first;
}
final Locale languageLocale = Locale(locale.languageCode, "");
if (supported.contains(locale)) {
return locale;
} else if (supported.contains(languageLocale)) {
return languageLocale;
} else {
final Locale fallbackLocale = fallback ?? supported.first;
return fallbackLocale;
}
}
///
/// Returns true if the specified locale is supported, false otherwise.
///
bool _isSupported(Locale locale, bool withCountry) {
if (locale != null) {
for (Locale supportedLocale in supportedLocales) {
// Language must always match both locales.
if (supportedLocale.languageCode != locale.languageCode) {
continue;
}
// If country code matches, return this locale.
if (supportedLocale.countryCode == locale.countryCode) {
return true;
}
// If no country requirement is requested, check if this locale has no country.
if (true != withCountry && (supportedLocale.countryCode == null || supportedLocale.countryCode.isEmpty)) {
return true;
}
}
}
return false;
}
}
String getLang(Locale l) => l == null
? null
: l.countryCode != null && l.countryCode.isEmpty
? l.languageCode
: l.toString();
================================================
FILE: lib/main.dart
================================================
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:travel_budget/services/custom_colors.dart';
import 'package:travel_budget/views/navigation_view.dart';
import 'package:travel_budget/views/first_view.dart';
import 'package:travel_budget/views/sign_up_view.dart';
import 'package:travel_budget/widgets/provider_widget.dart';
import 'package:travel_budget/services/auth_service.dart';
import 'package:firebase_admob/firebase_admob.dart';
import 'package:travel_budget/services/admob_service.dart';
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseAdMob.instance.initialize(appId: AdMobService().getAdMobAppId());
FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterError;
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
var colors = CustomColors(WidgetsBinding.instance.window.platformBrightness);
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangePlatformBrightness() {
setState(() {
colors = CustomColors(WidgetsBinding.instance.window.platformBrightness);
});
}
@override
Widget build(BuildContext context) {
return Provider(
auth: AuthService(),
db: FirebaseFirestore.instance,
colors: colors,
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: "Travel Budget App",
theme: ThemeData(
brightness: Brightness.light,
primarySwatch: Colors.blue,
textTheme: TextTheme(bodyText2: GoogleFonts.quicksand(fontSize: 14.0))),
darkTheme: ThemeData(
brightness: Brightness.dark,
primarySwatch: Colors.blue,
textTheme: TextTheme(bodyText2: GoogleFonts.bitter(fontSize: 14.0))),
home: HomeController(),
routes: <String, WidgetBuilder>{
'/home': (BuildContext context) => HomeController(),
'/signUp': (BuildContext context) => SignUpView(authFormType: AuthFormType.signUp),
'/signIn': (BuildContext context) => SignUpView(authFormType: AuthFormType.signIn),
'/anonymousSignIn': (BuildContext context) => SignUpView(authFormType: AuthFormType.anonymous),
'/convertUser': (BuildContext context) => SignUpView(authFormType: AuthFormType.convert),
},
),
);
}
}
class HomeController extends StatelessWidget {
@override
Widget build(BuildContext context) {
final AuthService auth = Provider.of(context).auth;
return StreamBuilder<String>(
stream: auth.onAuthStateChanged,
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
final bool signedIn = snapshot.hasData;
return signedIn ? NavigationView() : FirstView();
}
return Container();
},
);
}
}
================================================
FILE: lib/models/Place.dart
================================================
class Place {
String name;
double averageBudget;
String placeId;
Place(
this.name,
this.averageBudget,
this.placeId,
);
}
================================================
FILE: lib/models/Trip.dart
================================================
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:travel_budget/credentials.dart';
class Trip {
String title;
DateTime startDate;
DateTime endDate;
double budget;
Map budgetTypes;
String travelType;
String photoReference;
String notes;
String documentId;
double saved;
List ledger;
Trip(
this.title,
this.startDate,
this.endDate,
this.budget,
this.budgetTypes,
this.travelType
);
// formatting for upload to Firbase when creating the trip
Map<String, dynamic> toJson() => {
'title': title,
'startDate': startDate,
'endDate': endDate,
'budget': budget,
'budgetTypes': budgetTypes,
'travelType': travelType,
'photoReference': photoReference,
};
// creating a Trip object from a firebase snapshot
Trip.fromSnapshot(DocumentSnapshot snapshot) :
title = snapshot.data()['title'],
startDate = snapshot.data()['startDate'].toDate(),
endDate = snapshot.data()['endDate'].toDate(),
budget = snapshot.data()['budget'],
budgetTypes = snapshot.data()['budgetTypes'],
travelType = snapshot.data()['travelType'],
photoReference = snapshot.data()['photoReference'],
notes = snapshot.data()['notes'],
documentId = snapshot.id,
saved = snapshot.data()['saved'],
ledger = snapshot.data()['ledger'];
Map<String, Icon> types({color = Colors.black}) => {
"car": Icon(Icons.directions_car, size: 50, color: color),
"bus": Icon(Icons.directions_bus, size: 50, color: color),
"train": Icon(Icons.train, size: 50, color: color),
"plane": Icon(Icons.airplanemode_active, size: 50, color: color),
"ship": Icon(Icons.directions_boat, size: 50, color: color),
"other": Icon(Icons.directions, size: 50, color: color),
};
// return the google places image
Image getLocationImage() {
final baseUrl = "https://maps.googleapis.com/maps/api/place/photo";
final maxWidth = "1000";
final url = "$baseUrl?maxwidth=$maxWidth&photoreference=$photoReference&key=$PLACES_API_KEY";
return Image.network(url, fit: BoxFit.cover);
}
int getTotalTripDays() {
int total = endDate.difference(startDate).inDays;
if (total < 1) {
total = 1;
}
return total;
}
int getDaysUntilTrip() {
int diff = startDate.difference(DateTime.now()).inDays;
if (diff < 0) {
diff = 0;
}
return diff;
}
int getCurrentDailyBudget() {
if (saved == 0 || saved == null) {
return 0;
} else {
return (saved / getTotalTripDays()).floor();
}
}
Map<String, dynamic> ledgerItem(String amount, String type) {
var amountDouble = double.parse(amount);
if (type == "spent") {
amountDouble = double.parse("-" + amount);
}
return {
'ledger': FieldValue.arrayUnion([
{
"date": DateTime.now(),
"amount": amountDouble,
},
]),
'saved': FieldValue.increment(amountDouble)
};
}
}
================================================
FILE: lib/models/User.dart
================================================
class User {
String homeCountry;
bool admin;
User(this.homeCountry);
Map<String, dynamic> toJson() => {
'homeCountry': homeCountry,
'admin': admin,
};
}
================================================
FILE: lib/services/admob_service.dart
================================================
import 'dart:io';
import 'package:firebase_admob/firebase_admob.dart';
import 'package:flutter/material.dart';
class AdMobService {
String getAdMobAppId() {
if (Platform.isIOS) {
return 'ca-app-pub-2334510780816542~6726672523';
} else if (Platform.isAndroid) {
return 'ca-app-pub-2334510780816542~7385148076';
}
return null;
}
static String _getBannerAdId() {
if (Platform.isIOS) {
// return 'ca-app-pub-2334510780816542/6833456062';
return 'ca-app-pub-3940256099942544/2934735716';
} else if (Platform.isAndroid) {
// return 'ca-app-pub-2334510780816542/2993163849';
return "ca-app-pub-3940256099942544/6300978111";
}
return null;
}
String getInterstitialAdId() {
if (Platform.isIOS) {
// return '';
return 'ca-app-pub-3940256099942544/4411468910';
} else if (Platform.isAndroid) {
// return '';
return "ca-app-pub-3940256099942544/1033173712";
}
return null;
}
InterstitialAd getNewTripInterstitial() {
return InterstitialAd(
adUnitId: getInterstitialAdId(),
listener: (MobileAdEvent event) {
print("InterstitialAd event is $event");
},
);
}
static BannerAd _homeBannerAd;
static BannerAd _getHomePageBannerAd() {
return BannerAd(
adUnitId: _getBannerAdId(),
size: AdSize.smartBanner
);
}
static void showHomeBannerAd() {
if ( _homeBannerAd == null ) _homeBannerAd = _getHomePageBannerAd();
_homeBannerAd
..load()
..show(anchorType: AnchorType.bottom, anchorOffset: kBottomNavigationBarHeight);
}
static void hideHomeBannerAd() async {
await _homeBannerAd.dispose();
_homeBannerAd = null;
}
}
================================================
FILE: lib/services/auth_service.dart
================================================
import 'package:apple_sign_in/apple_sign_in.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AuthService {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final GoogleSignIn _googleSignIn = GoogleSignIn();
Stream<String> get onAuthStateChanged => _firebaseAuth.authStateChanges().map(
(User user) => user?.uid,
);
// GET UID
String getCurrentUID() {
return _firebaseAuth.currentUser.uid;
}
// GET CURRENT USER
Future getCurrentUser() async {
return _firebaseAuth.currentUser;
}
getProfileImage() {
if(_firebaseAuth.currentUser.photoURL != null) {
return Image.network(_firebaseAuth.currentUser.photoURL, height: 100, width: 100);
} else {
return Icon(Icons.account_circle, size: 100);
}
}
// Email & Password Sign Up
Future<String> createUserWithEmailAndPassword(
String email, String password, String name) async {
final authResult = await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
// Update the username
await updateUserName(name, authResult.user);
return authResult.user.uid;
}
Future updateUserName(String name, User currentUser) async {
await currentUser.updateProfile(displayName: name);
await currentUser.reload();
}
// Email & Password Sign In
Future<String> signInWithEmailAndPassword(
String email, String password) async {
return (await _firebaseAuth.signInWithEmailAndPassword(
email: email, password: password))
.user
.uid;
}
// Sign Out
signOut() async {
return await _firebaseAuth.signOut();
}
// Reset Password
Future sendPasswordResetEmail(String email) async {
return _firebaseAuth.sendPasswordResetEmail(email: email);
}
// Create Anonymous User
Future singInAnonymously() {
return _firebaseAuth.signInAnonymously();
}
Future convertUserWithEmail(
String email, String password, String name) async {
final currentUser = _firebaseAuth.currentUser;
final credential =
EmailAuthProvider.credential(email: email, password: password);
await currentUser.linkWithCredential(credential);
await updateUserName(name, currentUser);
}
Future convertWithGoogle() async {
final currentUser = _firebaseAuth.currentUser;
final GoogleSignInAccount account = await _googleSignIn.signIn();
final GoogleSignInAuthentication _googleAuth = await account.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
idToken: _googleAuth.idToken,
accessToken: _googleAuth.accessToken,
);
await currentUser.linkWithCredential(credential);
await updateUserName(_googleSignIn.currentUser.displayName, currentUser);
}
// GOOGLE
Future<String> signInWithGoogle() async {
final GoogleSignInAccount account = await _googleSignIn.signIn();
final GoogleSignInAuthentication _googleAuth = await account.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
idToken: _googleAuth.idToken,
accessToken: _googleAuth.accessToken,
);
return (await _firebaseAuth.signInWithCredential(credential)).user.uid;
}
// APPLE
Future signInWithApple() async {
final AuthorizationResult result = await AppleSignIn.performRequests([
AppleIdRequest(requestedScopes: [Scope.email, Scope.fullName])
]);
switch (result.status) {
case AuthorizationStatus.authorized:
final AppleIdCredential _auth = result.credential;
final OAuthProvider oAuthProvider =
new OAuthProvider("apple.com");
final AuthCredential credential = oAuthProvider.credential(
idToken: String.fromCharCodes(_auth.identityToken),
accessToken: String.fromCharCodes(_auth.authorizationCode),
);
await _firebaseAuth.signInWithCredential(credential);
// update the user information
if (_auth.fullName != null) {
await _firebaseAuth.currentUser.updateProfile(displayName: "${_auth.fullName.givenName} ${_auth.fullName.familyName}");
}
break;
case AuthorizationStatus.error:
print("Sign In Failed ${result.error.localizedDescription}");
break;
case AuthorizationStatus.cancelled:
print("User Cancled");
break;
}
}
Future createUserWithPhone(String phone, BuildContext context) async {
_firebaseAuth.verifyPhoneNumber(
phoneNumber: phone,
timeout: Duration(seconds: 0),
verificationCompleted: (AuthCredential authCredential) {
_firebaseAuth.signInWithCredential(authCredential).then((UserCredential result){
Navigator.of(context).pop(); // to pop the dialog box
Navigator.of(context).pushReplacementNamed('/home');
}).catchError((e) {
return "error";
});
},
verificationFailed: (FirebaseAuthException exception) {
return "error";
},
codeSent: (String verificationId, [int forceResendingToken]) {
final _codeController = TextEditingController();
showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Text("Enter Verification Code From Text Message"),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[TextField(controller: _codeController)],
),
actions: <Widget>[
FlatButton(
child: Text("submit"),
textColor: Colors.white,
color: Colors.green,
onPressed: () {
var _credential = PhoneAuthProvider.credential(verificationId: verificationId,
smsCode: _codeController.text.trim());
_firebaseAuth.signInWithCredential(_credential).then((UserCredential result){
Navigator.of(context).pop(); // to pop the dialog box
Navigator.of(context).pushReplacementNamed('/home');
}).catchError((e) {
return "error";
});
},
)
],
),
);
},
codeAutoRetrievalTimeout: (String verificationId) {
verificationId = verificationId;
});
}
}
class NameValidator {
static String validate(String value) {
if (value.isEmpty) {
return "Name can't be empty";
}
if (value.length < 2) {
return "Name must be at least 2 characters long";
}
if (value.length > 50) {
return "Name must be less than 50 characters long";
}
return null;
}
}
class EmailValidator {
static String validate(String value) {
if (value.isEmpty) {
return "Email can't be empty";
}
return null;
}
}
class PasswordValidator {
static String validate(String value) {
if (value.isEmpty) {
return "Password can't be empty";
}
return null;
}
}
================================================
FILE: lib/services/custom_colors.dart
================================================
import 'package:flutter/material.dart';
class CustomColors {
Brightness brightness;
Color text1, primary;
CustomColors(Brightness brightness) {
this.brightness = brightness;
if(brightness == Brightness.dark) {
this.text1 = Color(0xff252223);
this.primary = Color(0xff3c7778);
} else {
this.text1 = Colors.white;
this.primary = Color(0xff57AEAF);
}
}
}
================================================
FILE: lib/services/firebase_service.dart
================================================
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:travel_budget/widgets/provider_widget.dart';
class FirebaseService {
static Future<Trip> getNextTrip(context) async {
final uid = Provider.of(context).auth.getCurrentUID();
var snapshot = await FirebaseFirestore.instance
.collection('userData')
.doc(uid)
.collection('trips')
.orderBy('startDate')
.limit(1)
.get();
return Trip.fromSnapshot(snapshot.docs.first);
}
static void addToLedger(context, documentId, item) async {
await Provider.of(context).db
.collection('userData')
.doc(Provider.of(context).auth.getCurrentUID())
.collection('trips')
.doc(documentId)
.update(item);
}
}
================================================
FILE: lib/views/deposit_view.dart
================================================
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:travel_budget/services/firebase_service.dart';
import 'package:travel_budget/views/navigation_view.dart';
import 'package:travel_budget/widgets/provider_widget.dart';
import 'package:travel_budget/widgets/rounded_button.dart';
class DepositView extends StatefulWidget {
final Trip trip;
DepositView({
@required this.trip,
});
@override
_DepositViewState createState() => _DepositViewState();
}
class _DepositViewState extends State<DepositView> {
String _amount = "0";
String _error;
@override
Widget build(BuildContext context) {
return Container(
color: Colors.indigo,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: SafeArea(
child: Column(
children: [
Spacer(),
FittedBox(
fit: BoxFit.fitWidth,
child: Text(
"\$$_amount",
style: TextStyle(fontSize: 100, fontWeight: FontWeight.bold, color: Colors.white),
),
),
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Text("${_error ?? ''}", style: TextStyle(color: Colors.white)),
),
Container(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: GridView.count(
crossAxisCount: 3,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
childAspectRatio: 1.4,
children: setKeyboard(),
),
),
),
Spacer(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_actionBtn("spent"),
_actionBtn("saved"),
],
),
),
Spacer()
],
),
),
);
}
Widget _numberBtn(String number) {
return FlatButton(
child: Text(
"$number",
style: TextStyle(fontSize: 40, color: Colors.white),
),
onPressed: () {
setState(() {
if (_amount == "0") {
_amount = "$number";
} else if (_amount.length == 5) {
_amount = _amount;
HapticFeedback.heavyImpact();
} else {
_amount += "$number";
}
});
},
);
}
Widget _deleteBtn() {
return FlatButton(
child: Text(
"<",
style: TextStyle(fontSize: 40, color: Colors.white),
),
onPressed: () {
setState(() {
if (_amount.length <= 1) {
_amount = "0";
} else {
_amount = _amount.substring(0, _amount.length - 1);
}
});
},
);
}
Widget _actionBtn(String type) {
return Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
child: RoundedButton(
color: Colors.indigoAccent,
child:
Text("${type[0].toUpperCase()}${type.substring(1)}", style: TextStyle(color: Colors.white, fontSize: 20)),
onPressed: () async {
if (_amount == "0") {
setState(() {
_error = "Enter an amount";
});
} else if (type == "spent" && double.parse(_amount) > widget.trip.saved) {
setState(() {
_error = "Yove've only saved \$${widget.trip.saved.floor()}";
});
} else {
FirebaseService.addToLedger(context, widget.trip.documentId, widget.trip.ledgerItem(_amount, type));
Navigator.pushReplacement(
context,
PageRouteBuilder(
pageBuilder: (_, __, ___) => NavigationView(),
transitionDuration: Duration(seconds: 0),
),
);
}
},
),
),
);
}
setKeyboard() {
List<Widget> keyboard = [];
// numbers 1-9
List.generate(9, (index) {
keyboard.add(_numberBtn("${index + 1}"));
});
keyboard.add(Text(""));
keyboard.add(_numberBtn("0"));
keyboard.add(_deleteBtn());
return keyboard;
}
}
================================================
FILE: lib/views/detail_trip_view.dart
================================================
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:travel_budget/services/admob_service.dart';
import 'package:travel_budget/widgets/provider_widget.dart';
import 'edit_notes_view.dart';
import 'package:intl/intl.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:travel_budget/widgets/money_text_field.dart';
import 'package:travel_budget/widgets/calculator_widget.dart';
class DetailTripView extends StatefulWidget {
final Trip trip;
DetailTripView({Key key, @required this.trip}) : super(key: key);
@override
_DetailTripViewState createState() => _DetailTripViewState();
}
class _DetailTripViewState extends State<DetailTripView> {
TextEditingController _budgetController = TextEditingController();
var _budget;
void initState() {
super.initState();
AdMobService.hideHomeBannerAd();
_budgetController.text = widget.trip.budget.toStringAsFixed(0);
_budget = widget.trip.budget.floor();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text('Trip Details'),
backgroundColor: Colors.green,
expandedHeight: 350.0,
flexibleSpace: FlexibleSpaceBar(
background: widget.trip.getLocationImage(),
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.settings,
color: Colors.white,
size: 30,
),
padding: const EdgeInsets.only(right: 15),
onPressed: () {
_tripEditModalBottomSheet(context);
},
),
],
),
SliverList(
delegate: SliverChildListDelegate([
tripDetails(),
CalculatorWidget(trip: widget.trip),
totalBudgetCard(),
daysOutCard(),
notesCard(context),
Container(
height: 200,
)
]),
)
],
),
),
);
}
Widget daysOutCard() {
return Card(
color: Colors.amberAccent,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text("${widget.trip.getDaysUntilTrip()}", style: TextStyle(fontSize: 75)),
Text("days until your trip", style: TextStyle(fontSize: 25))
],
),
),
);
}
Widget tripDetails() {
return Card(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
widget.trip.title,
style: TextStyle(fontSize: 30, color: Colors.green[900]),
),
),
],
),
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0, bottom: 8.0),
child: Text(
"${DateFormat('MM/dd/yyyy').format(widget.trip.startDate).toString()} - ${DateFormat('MM/dd/yyyy').format(widget.trip.endDate).toString()}"),
),
],
),
],
),
);
}
Widget totalBudgetCard() {
return Card(
color: Colors.blue,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Daily Budget",
style: TextStyle(fontSize: 15, color: Colors.white)),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: AutoSizeText(
"\$$_budget",
style: TextStyle(fontSize: 100),
maxLines: 1,
),
),
],
),
),
Row(
children: <Widget>[
Expanded(
child: Container(
color: Colors.blue[900],
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0, horizontal: 20),
child: Text(
"\$${_budget * widget.trip.getTotalTripDays()} total",
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
)
],
)
],
),
);
}
Widget notesCard(context) {
return Hero(
tag: "TripNotes-${widget.trip.title}",
transitionOnUserGestures: true,
child: Card(
color: Colors.deepPurpleAccent,
child: InkWell(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 10.0, left: 10.0),
child: Row(
children: <Widget>[
Text("Trip Notes",
style: TextStyle(fontSize: 24, color: Colors.white)),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: setNoteText(),
),
)
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EditNotesView(trip: widget.trip)));
},
),
),
);
}
List<Widget> setNoteText() {
if (widget.trip.notes == null) {
return [
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Icon(Icons.add_circle_outline, color: Colors.grey[300]),
),
Text("Click To Add Notes", style: TextStyle(color: Colors.grey[300])),
];
} else {
return [
Text(widget.trip.notes, style: TextStyle(color: Colors.grey[300]))
];
}
}
void _tripEditModalBottomSheet(context) {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return Container(
height: MediaQuery.of(context).size.height * .60,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text("Edit Trip"),
Spacer(),
IconButton(
icon: Icon(
Icons.cancel,
color: Colors.orange,
size: 25,
),
onPressed: () {
Navigator.of(context).pop();
},
)
],
),
Row(
children: [
Text(
widget.trip.title,
style: TextStyle(fontSize: 30, color: Colors.green[900]),
),
],
),
Row(
children: <Widget>[
Expanded(
child: MoneyTextField(
controller: _budgetController,
helperText: "Budget",
),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Submit'),
color: Colors.deepPurple,
textColor: Colors.white,
onPressed: () async {
widget.trip.budget = double.parse(_budgetController.text);
setState(() {
_budget = widget.trip.budget.floor();
});
await updateTrip(context);
Navigator.of(context).pop();
},
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Delete'),
color: Colors.red,
textColor: Colors.white,
onPressed: () async {
await deleteTrip(context);
Navigator.of(context).pushNamedAndRemoveUntil('/home', (Route<dynamic> route) => false);
},
)
],
)
],
),
),
);
},
);
}
Future updateTrip(context) async {
var uid = await Provider.of(context).auth.getCurrentUID();
final doc = FirebaseFirestore.instance
.collection('userData')
.doc(uid)
.collection("trips")
.doc(widget.trip.documentId);
return await doc.set(widget.trip.toJson());
}
Future deleteTrip(context) async {
var uid = await Provider.of(context).auth.getCurrentUID();
final doc = FirebaseFirestore.instance
.collection('userData')
.doc(uid)
.collection("trips")
.doc(widget.trip.documentId);
return await doc.delete();
}
}
================================================
FILE: lib/views/edit_notes_view.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:travel_budget/widgets/provider_widget.dart';
import 'package:travel_budget/widgets/rounded_button.dart';
class EditNotesView extends StatefulWidget {
final Trip trip;
EditNotesView({Key key, @required this.trip}) : super(key: key);
@override
_EditNotesViewState createState() => _EditNotesViewState();
}
class _EditNotesViewState extends State<EditNotesView> {
TextEditingController _notesController = new TextEditingController();
final db = FirebaseFirestore.instance;
@override
void initState() {
super.initState();
_notesController.text = widget.trip.notes;
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Colors.amberAccent,
child: Hero(
tag: "TripNotes-${widget.trip.title}",
transitionOnUserGestures: true,
child: SafeArea(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
buildHeading(context),
buildNotesText(),
buildSubmitButton(context),
],
),
),
),
),
),
);
}
Widget buildHeading(context) {
return Material(
color: Colors.amberAccent,
child: Padding(
padding: const EdgeInsets.only(left: 20.0, top: 10.0),
child: Row(
children: <Widget>[
Expanded(
child: Text(
"Trip Notes",
style: TextStyle(fontSize: 24, color: Colors.black),
),
),
FlatButton(
child: Icon(Icons.close, color: Colors.black, size: 30),
onPressed: () {
Navigator.of(context).pop();
},
)
],
),
),
);
}
Widget buildNotesText() {
return Material(
color: Colors.amberAccent,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: TextField(
maxLines: null,
controller: _notesController,
decoration: InputDecoration(
border: InputBorder.none,
),
cursorColor: Colors.black,
autofocus: true,
style: TextStyle(color: Colors.black),
),
),
);
}
Widget buildSubmitButton(context) {
return Material(
color: Colors.amberAccent,
child: RoundedButton(
child: Text("Save", style: TextStyle(color: Colors.white)),
color: Colors.indigo,
onPressed: () async {
widget.trip.notes = _notesController.text;
final uid = Provider.of(context).auth.getCurrentUID();
await db.collection("userData")
.doc(uid)
.collection("trips")
.doc(widget.trip.documentId)
.update({'notes': _notesController.text});
Navigator.of(context).pop();
},
),
);
}
}
================================================
FILE: lib/views/first_view.dart
================================================
import 'package:flutter/material.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:travel_budget/widgets/custom_dialog.dart';
class FirstView extends StatelessWidget {
final primaryColor = const Color(0xFF75A2EA);
@override
Widget build(BuildContext context) {
final _width = MediaQuery.of(context).size.width;
final _height = MediaQuery.of(context).size.height;
return Scaffold(
body: Container(
width: _width,
height: _height,
color: primaryColor,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
SizedBox(height: _height * 0.10),
Text(
"Welcome",
style: TextStyle(fontSize: 44, color: Colors.white),
),
SizedBox(height: _height * 0.10),
AutoSizeText(
"Let’s start planning your next trip",
maxLines: 2,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 40,
color: Colors.white,
),
),
SizedBox(height: _height * 0.15),
RaisedButton(
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)),
child: Padding(
padding: const EdgeInsets.only(top: 10.0, bottom: 10.0, left: 30.0, right: 30.0),
child: Text(
"Get Started",
style: TextStyle(
color: primaryColor,
fontSize: 28,
fontWeight: FontWeight.w300,
),
),
),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) => CustomDialog(
title: "Would you like to create a free account?",
description:
"With an account, your data will be securely saved, allowing you to access it from multiple devices.",
primaryButtonText: "Create My Account",
primaryButtonRoute: "/signUp",
secondaryButtonText: "Maybe Later",
secondaryButtonRoute: "/anonymousSignIn",
),
);
},
),
SizedBox(height: _height * 0.05),
FlatButton(
child: Text(
"Sign In",
style: TextStyle(color: Colors.white, fontSize: 25),
),
onPressed: () {
Navigator.of(context).pushReplacementNamed('/signIn');
},
)
],
),
),
),
),
);
}
}
================================================
FILE: lib/views/home_view.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:travel_budget/views/home_widgets/home_header.dart';
import 'package:travel_budget/views/home_widgets/percent_saved.dart';
import 'package:travel_budget/views/home_widgets/saved_vs_needed.dart';
import 'package:travel_budget/views/home_widgets/travel_type.dart';
import 'package:travel_budget/views/home_widgets/trip_details_card.dart';
import 'home_widgets/current_daily_budget.dart';
import 'home_widgets/days_until_trip.dart';
import 'home_widgets/notes.dart';
class HomeView extends StatefulWidget {
final Trip trip;
HomeView({
@required this.trip,
});
@override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: [
HomeHeader(widget.trip),
TripDetailsCard(widget.trip),
Padding(
padding: const EdgeInsets.only(left: 15.0, right: 15.0),
child: IntrinsicHeight(
child: Row(
children: [
Expanded(
flex: 12,
child: DaysUntilTrip(widget.trip),
),
Spacer(),
Expanded(
flex: 12,
child: CurrentDailyBudget(widget.trip),
)
],
),
),
),
Padding(
padding: const EdgeInsets.all(15.0),
child: SavedVsNeeded(widget.trip),
),
Padding(
padding: const EdgeInsets.only(left: 15.0, right: 15.0),
child: IntrinsicHeight(
child: Row(
children: [
Expanded(
flex: 5,
child: TravelType(widget.trip),
),
Spacer(),
Expanded(
flex: 12,
child: PercentSaved(widget.trip),
)
],
),
),
),
Padding(
padding: const EdgeInsets.all(15.0),
child: Notes(trip: widget.trip),
),
Container(height: 40)
],
),
);
}
}
================================================
FILE: lib/views/home_widgets/current_daily_budget.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
class CurrentDailyBudget extends StatelessWidget {
CurrentDailyBudget(this.trip);
final Trip trip;
@override
Widget build(BuildContext context) {
return Card(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.0),
gradient: LinearGradient(
colors: [Colors.blueAccent, Colors.blue],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FittedBox(
fit: BoxFit.fitWidth,
child: Text("\$${trip.getCurrentDailyBudget()}", style: TextStyle(fontSize: 60, color: Colors.white)),
),
FittedBox(
fit: BoxFit.fitWidth,
child: Text("current daily budget", style: TextStyle(color: Colors.white)),
),
],
),
),
),
);
}
}
================================================
FILE: lib/views/home_widgets/days_until_trip.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
class DaysUntilTrip extends StatelessWidget {
DaysUntilTrip(this.trip);
final Trip trip;
@override
Widget build(BuildContext context) {
return Card(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.0),
gradient: LinearGradient(
colors: [Colors.lightBlue, Colors.blueAccent],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FittedBox(
fit: BoxFit.fitWidth,
child: Text("${trip.getDaysUntilTrip()}", style: TextStyle(fontSize: 60, color: Colors.white)),
),
FittedBox(
fit: BoxFit.fitWidth,
child: Text("days until your trip", style: TextStyle(color: Colors.white)),
),
],
),
),
),
);
}
}
================================================
FILE: lib/views/home_widgets/home_header.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
class HomeHeader extends StatelessWidget {
HomeHeader(this.trip);
final Trip trip;
@override
Widget build(BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 0.25,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.deepPurple, Colors.blueAccent],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
)
),
child: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: FittedBox(
fit: BoxFit.fitWidth,
child: Text("\$${(trip.saved ?? 0.0).floor()}", style: TextStyle(color: Colors.white, fontSize: 65)),
),
),
Text("Total Saved", style: TextStyle(color: Colors.white)),
],
),
),
);
}
}
================================================
FILE: lib/views/home_widgets/notes.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:travel_budget/views/edit_notes_view.dart';
class Notes extends StatelessWidget {
final Trip trip;
Notes({@required this.trip});
@override
Widget build(BuildContext context) {
return Hero(
tag: "TripNotes-${trip.title}",
transitionOnUserGestures: true,
child: Card(
color: Colors.amberAccent,
child: InkWell(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 10.0, top: 8.0),
child: Row(
children: <Widget>[
Text("Notes", style: TextStyle(fontSize: 24, color: Colors.black)),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: setNoteText(),
),
)
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => EditNotesView(trip: trip)),
);
},
),
),
);
}
List<Widget> setNoteText() {
if (trip.notes == null) {
return [
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Icon(Icons.add_circle_outline, color: Colors.grey),
),
Text("Click To Add Notes", style: TextStyle(color: Colors.black)),
];
} else {
return [
Flexible(
child: Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Text(
trip.notes,
style: TextStyle(color: Colors.black),
overflow: TextOverflow.fade,
maxLines: 5,
),
),
)
];
}
}
}
================================================
FILE: lib/views/home_widgets/percent_saved.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/classes/progress_painter.dart';
import 'package:travel_budget/models/Trip.dart';
class PercentSaved extends StatelessWidget {
PercentSaved(this.trip);
final Trip trip;
@override
Widget build(BuildContext context) {
final totalBudget = trip.budget.floor() * trip.getTotalTripDays();
final saved = (trip.saved ?? 0).floor();
final percentComplete = (saved / totalBudget) * 100;
return Card(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.0),
gradient: LinearGradient(
colors: [Colors.indigoAccent, Colors.indigo],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Padding(
padding: const EdgeInsets.all(25.0),
child: Column(
children: [
Container(
height: 200,
width: 200,
decoration: BoxDecoration(
shape: BoxShape.circle,
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Stack(
children: [
Center(
child: Text("${percentComplete.toStringAsFixed(0)}%",
style: TextStyle(color: Colors.white, fontSize: 30))),
CustomPaint(
child: Center(),
painter: ProgressPainter(
circleWidth: 40,
completedPercentage: percentComplete,
defaultCircleColor: Colors.white30,
percentageCompletedCircleColor: Colors.greenAccent,
),
),
],
),
),
),
Container(
child: Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Text("percent saved", style: TextStyle(color: Colors.white)),
),
),
],
),
),
),
);
}
}
================================================
FILE: lib/views/home_widgets/saved_vs_needed.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
class SavedVsNeeded extends StatelessWidget {
SavedVsNeeded(this.trip);
final Trip trip;
@override
Widget build(BuildContext context) {
final saved = (trip.saved ?? 0.0).floor();
final totalBudget = trip.budget.floor() * trip.getTotalTripDays();
final needed = (totalBudget - saved).floor();
return Card(
child: Container (
height: MediaQuery.of(context).size.height * 0.30,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.0),
gradient: LinearGradient(
colors: [Colors.blueAccent, Colors.indigo],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 15.0, bottom: 15.0),
child: Text("saved", style: TextStyle(color: Colors.white)),
),
Expanded(
child: Container(
alignment: Alignment.bottomCenter,
child: FractionallySizedBox(
heightFactor: (saved > totalBudget) ? 1 : (saved/totalBudget),
child: Container(
width: 50,
color: Colors.white,
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 15.0, bottom: 15.0),
child: Text("\$$saved", style: TextStyle(color: Colors.white)),
),
],
),
Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 15.0, bottom: 15.0),
child: Text("needed", style: TextStyle(color: Colors.white)),
),
Expanded(
child: Container(
alignment: Alignment.bottomCenter,
child: FractionallySizedBox(
heightFactor: (needed <= 0) ? 0 : (needed/totalBudget),
child: Container(
width: 50,
color: Colors.white,
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 15.0, bottom: 15.0),
child: Text("\$${(needed <= 0) ? 0 : needed}", style: TextStyle(color: Colors.white)),
),
],
)
],
),
),
);
}
}
================================================
FILE: lib/views/home_widgets/travel_type.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
class TravelType extends StatelessWidget {
TravelType(this.trip);
final Trip trip;
Widget getTypeIcon() {
if (trip.types().containsKey(trip.travelType)) {
return trip.types(color: Colors.white)[trip.travelType];
} else {
return Icon(Icons.directions, size: 40, color: Colors.white);
}
}
@override
Widget build(BuildContext context) {
return Card(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4.0),
gradient: LinearGradient(
colors: [Colors.lightBlue, Colors.blueAccent],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FittedBox(
fit: BoxFit.fitWidth,
child: Padding(
padding: const EdgeInsets.only(top: 6.0),
child: Text(
"transport",
style: TextStyle(color: Colors.white),
),
),
),
Expanded(
child: getTypeIcon(),
),
Text(trip.travelType, style: TextStyle(color: Colors.white)),
],
),
),
),
);
}
}
================================================
FILE: lib/views/home_widgets/trip_details_card.dart
================================================
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:travel_budget/models/Trip.dart';
class TripDetailsCard extends StatelessWidget {
TripDetailsCard(this.trip);
final Trip trip;
@override
Widget build(BuildContext context) {
return Container(
child: Stack(
overflow: Overflow.visible,
alignment: Alignment.bottomCenter,
children: [
Container(
child: Column(
children: [
SizedBox(
width: double.infinity,
height: 250,
child: trip.getLocationImage(),
),
SizedBox(
height: 50,
width: double.infinity,
)
],
),
),
Positioned(
top: 150,
left: 15,
right: 15,
child: Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Row(
children: [
Expanded(
child: Container(
height: 40,
child: AutoSizeText(
trip.title,
style: TextStyle(fontSize: 30.0),
maxLines: 2,
),
),
)
],
),
Row(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Text(
"${DateFormat('MMM dd, yyyy').format(trip.startDate).toString()} - ${DateFormat('MMM dd, yyyy').format(trip.endDate).toString()}"),
),
],
),
Row(
children: [
Text("\$${(trip.budget.floor() * trip.getTotalTripDays()).toString()}",
style: TextStyle(fontSize: 25.0, fontWeight: FontWeight.bold)),
Padding(
padding: const EdgeInsets.only(top: 8.0, left: 4.0),
child: Text("total budget"),
),
],
)
],
),
),
),
)
],
),
);
}
}
================================================
FILE: lib/views/navigation_view.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/services/firebase_service.dart';
import 'package:travel_budget/views/home_view.dart';
import 'deposit_view.dart';
import 'profile_view.dart';
import 'package:travel_budget/models/Trip.dart';
class NavigationView extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _NavigationViewState();
}
}
class _NavigationViewState extends State<NavigationView> {
Future _nextTrip;
Trip _trip;
int _currentIndex = 0;
@override
void didChangeDependencies() {
super.didChangeDependencies();
_nextTrip = FirebaseService.getNextTrip(context);
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _nextTrip,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if(snapshot.hasData) {
_trip = snapshot.data;
return _buildView();
} else {
// TODO update when user has no trips
return Container(
color: Colors.white,
child: Center(
child: CircularProgressIndicator(),
),
);
}
} else {
return Container(
color: Colors.white,
child: Center(
child: CircularProgressIndicator(),
),
);
}
},
);
}
_buildView() {
final List<Widget> _children = [
HomeView(trip: _trip),
DepositView(trip: _trip),
ProfileView(),
];
return Scaffold(
body: _children[_currentIndex],
floatingActionButton: FloatingActionButton(
onPressed: () {
onTabTapped(1);
},
tooltip: "Add Savings",
child: Icon(Icons.attach_money, color: Colors.indigo),
elevation: 4.0,
backgroundColor: Colors.white,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomNavigationBar(
onTap: onTabTapped,
currentIndex: _currentIndex,
items: [
BottomNavigationBarItem(
icon: new Icon(Icons.home),
title: new Text("Home"),
),
BottomNavigationBarItem(
icon: new Icon(Icons.attach_money),
title: new Text("Save"),
),
BottomNavigationBarItem(
icon: new Icon(Icons.account_circle),
title: new Text("Profile"),
),
]
),
);
}
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}
}
================================================
FILE: lib/views/new_trips/budget_view.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:travel_budget/widgets/divider_with_text_widget.dart';
import 'package:travel_budget/widgets/money_text_field.dart';
import 'summary_view.dart';
enum budgetType { simple, complex }
class NewTripBudgetView extends StatefulWidget {
final Trip trip;
NewTripBudgetView({Key key, @required this.trip}) : super(key: key);
@override
_NewTripBudgetViewState createState() => _NewTripBudgetViewState();
}
class _NewTripBudgetViewState extends State<NewTripBudgetView> {
var _budgetState = budgetType.simple;
var _switchButtonText = "Build Budget";
var _budgetTotal = 0;
TextEditingController _budgetController = new TextEditingController();
TextEditingController _transportationController = new TextEditingController();
TextEditingController _foodController = new TextEditingController();
TextEditingController _lodgingController = new TextEditingController();
TextEditingController _entertainmentController = new TextEditingController();
@override
void initState() {
super.initState();
_budgetController.addListener(_setBudgetTotal);
_transportationController.addListener(_setTotalBudget);
_foodController.addListener(_setTotalBudget);
_lodgingController.addListener(_setTotalBudget);
_entertainmentController.addListener(_setTotalBudget);
}
_setTotalBudget() {
var total = 0;
total = (_transportationController.text == "") ? 0 : int.parse(_transportationController.text);
total += (_foodController.text == "") ? 0 : int.parse(_foodController.text);
total += (_lodgingController.text== "") ? 0 : int.parse(_lodgingController.text);
total += (_entertainmentController.text == "") ? 0 : int.parse(_entertainmentController.text);
setState(() {
_budgetTotal = total;
});
}
_setBudgetTotal() {
setState(() {
_budgetTotal = (_budgetController.text == "") ? 0 : int.parse(_budgetController.text);
});
}
List<Widget> setBudgetFields(_budgetController) {
List<Widget> fields = [];
if (_budgetState == budgetType.simple) {
_switchButtonText = "Build Budget";
fields.add(Padding(
padding: const EdgeInsets.all(12.0),
child: Text("Enter a Trip Budget"),
));
fields.add(MoneyTextField(controller: _budgetController, helperText: "Daily estimated budget"));
} else {
// assumes complex budget
_switchButtonText = "Simple Budget";
fields.add(Padding(
padding: const EdgeInsets.all(12.0),
child: Text("Enter How much you want to spend in each area"),
));
fields.add(MoneyTextField(controller: _transportationController, helperText: "Daily Estimated Transportation Budget"));
fields.add(MoneyTextField(controller: _foodController, helperText: "Daily Estimated Food Budget"));
fields.add(MoneyTextField(controller: _lodgingController, helperText: "Daily Estimated Lodging Budget"));
fields.add(MoneyTextField(controller: _entertainmentController, helperText: "Daily Estimated Entertainment Budget"));
fields.add(Text("Total: \$$_budgetTotal"));
}
fields.add(FlatButton(
child: Text(
"Continue",
style: TextStyle(fontSize: 25, color: Colors.blue),
),
onPressed: () async {
widget.trip.budget = _budgetTotal.toDouble();
widget.trip.budgetTypes = {
'transportation': (_transportationController.text == "") ? 0.0 : double.parse(_transportationController.text),
'food': (_foodController.text == "") ? 0.0 : double.parse(_foodController.text),
'lodging': (_lodgingController.text== "") ? 0.0 : double.parse(_lodgingController.text),
'entertainment': (_entertainmentController.text == "") ? 0.0 : double.parse(_entertainmentController.text),
};
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewTripSummaryView(trip: widget.trip)),
);
},
));
fields.add(DividerWithText(dividerText: "or"));
fields.add(FlatButton(
child: Text(
_switchButtonText,
style: TextStyle(fontSize: 25, color: Colors.blue),
),
onPressed: () {
setState(() {
_budgetState = (_budgetState == budgetType.simple)
? budgetType.complex
: budgetType.simple;
});
},
));
return fields;
}
@override
Widget build(BuildContext context) {
_budgetController.text = (_budgetController.text == "") ? "" : _budgetTotal.toString();
_budgetController.selection = TextSelection.collapsed(offset: _budgetController.text.length);
return Scaffold(
appBar: AppBar(
title: Text('Create Trip - Budget'),
),
body: SingleChildScrollView(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: setBudgetFields(_budgetController),
),
),
),
);
}
}
================================================
FILE: lib/views/new_trips/date_view.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:date_range_picker/date_range_picker.dart' as DateRagePicker;
import 'package:intl/intl.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'dart:async';
import 'budget_view.dart';
class NewTripDateView extends StatefulWidget {
final Trip trip;
NewTripDateView({Key key, @required this.trip}) : super(key: key);
@override
_NewTripDateViewState createState() => _NewTripDateViewState();
}
class _NewTripDateViewState extends State<NewTripDateView> {
DateTime _startDate = DateTime.now();
DateTime _endDate = DateTime.now().add(Duration(days: 7));
Future displayDateRangePicker(BuildContext context) async {
final List<DateTime> picked = await DateRagePicker.showDatePicker(
context: context,
initialFirstDate: _startDate,
initialLastDate: _endDate,
firstDate: new DateTime(DateTime.now().year - 50),
lastDate: new DateTime(DateTime.now().year + 50));
if (picked != null && picked.length == 2) {
setState(() {
_startDate = picked[0];
_endDate = picked[1];
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text(''),
backgroundColor: Colors.green,
expandedHeight: 350.0,
flexibleSpace: FlexibleSpaceBar(
background: widget.trip.getLocationImage(),
),
),
SliverFixedExtentList(
itemExtent: 200.00,
delegate: SliverChildListDelegate([
buildSelectedDetails(context, widget.trip),
buildButtons(),
]),
)
],
),
),
);
}
Widget buildButtons() {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SizedBox(
width: MediaQuery.of(context).size.width * 0.60,
child: RaisedButton(
child: Text("Change Date Range"),
color: Colors.deepPurpleAccent,
textColor: Colors.white,
onPressed: () async {
await displayDateRangePicker(context);
},
),
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.60,
child: RaisedButton(
child: Text('Continue'),
color: Colors.amberAccent,
onPressed: () {
widget.trip.startDate = _startDate;
widget.trip.endDate = _endDate;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewTripBudgetView(
trip: widget.trip,
),
),
);
},
),
),
],
);
}
Widget buildingSelectedDates() {
return Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("Start Date"),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
"${DateFormat('MM-dd').format(_startDate).toString()}",
style: TextStyle(fontSize: 35, color: Colors.deepPurple),
),
),
Text(
"${DateFormat('yyyy').format(_startDate).toString()}",
style: TextStyle(color: Colors.deepPurple),
),
],
),
Container(
child: Icon(
Icons.arrow_forward,
color: Colors.deepOrange,
size: 45,
)),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text("End Date"),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
"${DateFormat('MM-dd').format(_endDate).toString()}",
style: TextStyle(fontSize: 35, color: Colors.deepPurple),
),
),
Text(
"${DateFormat('yyyy').format(_endDate).toString()}",
style: TextStyle(color: Colors.deepPurple),
),
],
),
],
),
),
);
}
Widget buildSelectedDetails(BuildContext context, Trip trip) {
return Hero(
tag: "SelectedTrip-${trip.title}",
transitionOnUserGestures: true,
child: Container(
child: Padding(
padding: const EdgeInsets.only(
left: 8.0,
right: 8.0,
),
child: SingleChildScrollView(
child: Card(
child: Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.only(
top: 16.0, left: 16.0, bottom: 16.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Flexible(
child: AutoSizeText(trip.title,
maxLines: 3,
style: TextStyle(fontSize: 25.0)),
),
],
),
buildingSelectedDates(),
],
),
),
),
],
),
),
),
),
),
);
}
}
================================================
FILE: lib/views/new_trips/location_view.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:travel_budget/models/Place.dart';
import 'package:travel_budget/widgets/divider_with_text_widget.dart';
import 'date_view.dart';
import 'package:travel_budget/credentials.dart';
import 'package:dio/dio.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'dart:async';
import 'package:uuid/uuid.dart';
class NewTripLocationView extends StatefulWidget {
final Trip trip;
NewTripLocationView({Key key, @required this.trip}) : super(key: key);
@override
_NewTripLocationViewState createState() => _NewTripLocationViewState();
}
class _NewTripLocationViewState extends State<NewTripLocationView> {
TextEditingController _searchController = new TextEditingController();
// Timer _throttle;
var uuid = new Uuid();
String _sessionToken;
String _heading;
List<Place> _placesList;
final List<Place> _suggestedList = [
// Place("New York", 320.00),
// Place("Austin", 250.00),
// Place("Boston", 290.00),
// Place("Florence", 300.00),
// Place("Washington D.C.", 190.00),
];
@override
void initState() {
super.initState();
_heading = "Suggestions";
_placesList = _suggestedList;
_searchController.addListener(_onSearchChanged);
}
@override
void dispose() {
_searchController.removeListener(_onSearchChanged);
_searchController.dispose();
super.dispose();
}
_onSearchChanged() {
if(_sessionToken == null) {
setState(() {
_sessionToken = uuid.v4();
});
}
getLocationResults(_searchController.text);
}
void getLocationResults(String input) async {
if (input.isEmpty) {
setState(() {
_heading = "Suggestions";
});
return;
}
String baseURL = 'https://maps.googleapis.com/maps/api/place/autocomplete/json';
String type = '(regions)';
String request = '$baseURL?input=$input&key=$PLACES_API_KEY&type=$type&sessiontoken=$_sessionToken';
Response response = await Dio().get(request);
final predictions = response.data['predictions'];
List<Place> _displayResults = [];
for (var i=0; i < predictions.length; i++) {
String name = predictions[i]['description'];
String placeId = predictions[i]['place_id'];
// TODO figure out the budget
double averageBudget = 200.0;
_displayResults.add(Place(name, averageBudget, placeId));
}
setState(() {
_heading = "Results";
_placesList = _displayResults;
});
}
Future<String> getLocationPhotoRef(placeId) async {
String placeImgRequest = 'https://maps.googleapis.com/maps/api/place/details/json?place_id=$placeId&fields=photo,geometry&key=$PLACES_API_KEY&sessiontoken=$_sessionToken';
Response placeDetails = await Dio().get(placeImgRequest);
return placeDetails.data["result"]["photos"][0]["photo_reference"];
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Create Trip - Location'),
),
body: Center(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(30.0),
child: TextField(
controller: _searchController,
decoration: InputDecoration(
prefixIcon: Icon(Icons.search),
),
),
),
Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: new DividerWithText(
dividerText: _heading,
),
),
Expanded(
child: ListView.builder(
itemCount: _placesList.length,
itemBuilder: (BuildContext context, int index) =>
buildPlaceCard(context, index),
),
),
],
),
),
);
}
Widget buildPlaceCard(BuildContext context, int index) {
return Hero(
tag: "SelectedTrip-${_placesList[index].name}",
transitionOnUserGestures: true,
child: Container(
child: Padding(
padding: const EdgeInsets.only(
left: 8.0,
right: 8.0,
),
child: Card(
child: InkWell(
child: Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Flexible(
child: AutoSizeText(_placesList[index].name,
maxLines: 3,
style: TextStyle(fontSize: 25.0)),
),
],
),
Row(
children: <Widget>[
Text(
"Average Budget \$${_placesList[index].averageBudget.toStringAsFixed(2)}"),
],
),
],
),
),
),
],
),
onTap: () async {
String photoReference = await getLocationPhotoRef(_placesList[index].placeId);
widget.trip.title = _placesList[index].name;
widget.trip.photoReference = photoReference;
setState(() {
_sessionToken = null;
});
// TODO maybe pass the trip average budget through here too...
// that would need to be added to the Trip object
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewTripDateView(trip: widget.trip)),
);
},
),
),
),
),
);
}
}
================================================
FILE: lib/views/new_trips/summary_view.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:travel_budget/widgets/provider_widget.dart';
import 'package:intl/intl.dart';
import 'package:travel_budget/services/admob_service.dart';
import 'package:firebase_admob/firebase_admob.dart';
class NewTripSummaryView extends StatelessWidget {
final db = FirebaseFirestore.instance;
final Trip trip;
final ams = AdMobService();
NewTripSummaryView({Key key, @required this.trip}) : super(key: key);
@override
Widget build(BuildContext context) {
InterstitialAd newTripAd = ams.getNewTripInterstitial();
newTripAd.load();
final tripTypes = trip.types();
var tripKeys = tripTypes.keys.toList();
return Scaffold(
appBar: AppBar(
title: Text('Trip Summary'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(12.0),
child: Text("Submit", style: TextStyle(fontSize: 20, color: Colors.green),),
),
Text("${trip.title}"),
Text("${DateFormat('dd/MM/yyyy').format(trip.startDate).toString()} - ${DateFormat('dd/MM/yyyy').format(trip.endDate).toString()}"),
Text("\$${trip.budget.toStringAsFixed(2)}"),
Expanded(
child: GridView.count(
crossAxisCount: 3,
scrollDirection: Axis.vertical,
primary: false,
children: List.generate(tripTypes.length, (index) {
return FlatButton(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
tripTypes[tripKeys[index]],
Text(tripKeys[index]),
],
),
onPressed: () async {
trip.travelType = tripKeys[index];
final uid = await Provider.of(context).auth.getCurrentUID();
await db.collection("userData").doc(uid).collection("trips").add(trip.toJson());
newTripAd.show(
anchorType: AnchorType.bottom,
anchorOffset: 0.0,
horizontalCenterOffset: 0.0,
);
Navigator.of(context).popUntil((route) => route.isFirst);
},
);
}),
),
),
],
)
)
);
}
}
================================================
FILE: lib/views/past_trips_view.dart
================================================
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:travel_budget/widgets/provider_widget.dart';
import 'package:travel_budget/widgets/trip_card.dart';
class PastTripsView extends StatefulWidget {
@override
_PastTripsViewState createState() => _PastTripsViewState();
}
class _PastTripsViewState extends State<PastTripsView> {
TextEditingController _searchController = TextEditingController();
Future resultsLoaded;
List _allResults = [];
List _resultsList = [];
@override
void initState() {
super.initState();
_searchController.addListener(_onSearchChanged);
}
@override
void dispose() {
_searchController.removeListener(_onSearchChanged);
_searchController.dispose();
super.dispose();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
resultsLoaded = getUsersPastTripsStreamSnapshots();
}
_onSearchChanged() {
searchResultsList();
}
searchResultsList() {
var showResults = [];
if(_searchController.text != "") {
for(var tripSnapshot in _allResults){
var title = Trip.fromSnapshot(tripSnapshot).title.toLowerCase();
if(title.contains(_searchController.text.toLowerCase())) {
showResults.add(tripSnapshot);
}
}
} else {
showResults = List.from(_allResults);
}
setState(() {
_resultsList = showResults;
});
}
getUsersPastTripsStreamSnapshots() async {
final uid = await Provider.of(context).auth.getCurrentUID();
var data = await FirebaseFirestore.instance
.collection('userData')
.doc(uid)
.collection('trips')
.where("endDate", isLessThanOrEqualTo: DateTime.now())
.orderBy('endDate')
.get();
setState(() {
_allResults = data.docs;
});
searchResultsList();
return "complete";
}
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Text("Past Trips", style: TextStyle(fontSize: 20)),
Padding(
padding: const EdgeInsets.only(left: 30.0, right: 30.0, bottom: 30.0),
child: TextField(
controller: _searchController,
decoration: InputDecoration(
prefixIcon: Icon(Icons.search)
),
),
),
Expanded(
child: ListView.builder(
itemCount: _resultsList.length,
itemBuilder: (BuildContext context, int index) =>
buildTripCard(context, _resultsList[index]),
)
),
],
),
);
}
}
================================================
FILE: lib/views/profile_view.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/widgets/provider_widget.dart';
import 'package:intl/intl.dart';
import 'package:travel_budget/models/User.dart';
class ProfileView extends StatefulWidget {
@override
_ProfileViewState createState() => _ProfileViewState();
}
class _ProfileViewState extends State<ProfileView> {
User user = User("");
bool _isAdmin = false;
TextEditingController _userCountryController = TextEditingController();
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width,
child: Column(
children: <Widget>[
FutureBuilder(
future: Provider.of(context).auth.getCurrentUser(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return displayUserInformation(context, snapshot);
} else {
return CircularProgressIndicator();
}
},
)
],
),
),
);
}
Widget displayUserInformation(context, snapshot) {
final authData = snapshot.data;
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Provider.of(context).auth.getProfileImage(),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Name: ${authData.displayName ?? 'Anonymous'}",
style: TextStyle(fontSize: 20),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Email: ${authData.email ?? 'Anonymous'}",
style: TextStyle(fontSize: 20),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Created: ${DateFormat('MM/dd/yyyy').format(authData.metadata.creationTime)}",
style: TextStyle(fontSize: 20),
),
),
FutureBuilder(
future: _getProfileData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
_userCountryController.text = user.homeCountry;
_isAdmin = user.admin ?? false;
}
return Container(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Home Country: ${_userCountryController.text}",
style: TextStyle(fontSize: 20),
),
),
adminFeature(),
],
),
);
}
),
showSignOut(context, authData.isAnonymous),
RaisedButton(
child: Text("Edit User"),
onPressed: () {
_userEditBottomSheet(context);
},
)
],
);
}
_getProfileData() async {
final uid = await Provider.of(context).auth.getCurrentUID();
await Provider.of(context)
.db
.collection('userData')
.document(uid)
.get().then((result) {
user.homeCountry = result.data['homeCountry'];
user.admin = result.data['admin'];
});
}
Widget showSignOut(context, bool isAnonymous) {
if (isAnonymous == true) {
return RaisedButton(
child: Text("Sign In To Save Your Data"),
onPressed: () {
Navigator.of(context).pushNamed('/convertUser');
},
);
} else {
return RaisedButton(
child: Text("Sign Out"),
onPressed: () {
try {
Provider.of(context).auth.signOut();
} catch (e) {
print(e);
}
},
);
}
}
Widget adminFeature() {
if(_isAdmin == true) {
return Text("You are an admin");
} else {
return Container();
}
}
void _userEditBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return Container(
height: MediaQuery.of(context).size.height * .60,
child: Padding(
padding: const EdgeInsets.only(left: 15.0, top: 15.0),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text("Update Profile"),
Spacer(),
IconButton(
icon: Icon(Icons.cancel),
color: Colors.orange,
iconSize: 25,
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 15.0),
child: TextField(
controller: _userCountryController,
decoration: InputDecoration(
helperText: "Home Country",
),
),
),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Save'),
color: Colors.green,
textColor: Colors.white,
onPressed: () async {
user.homeCountry = _userCountryController.text;
setState(() {
_userCountryController.text = user.homeCountry;
});
final uid =
await Provider.of(context).auth.getCurrentUID();
await Provider.of(context)
.db
.collection('userData')
.document(uid)
.setData(user.toJson());
Navigator.of(context).pop();
},
)
],
),
],
),
),
);
},
);
}
}
================================================
FILE: lib/views/sign_up_view.dart
================================================
import 'package:apple_sign_in/apple_sign_in.dart';
import 'package:flutter/material.dart';
import 'package:travel_budget/services/auth_service.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:travel_budget/widgets/provider_widget.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter_auth_buttons/flutter_auth_buttons.dart';
import 'package:international_phone_input/international_phone_input.dart';
// TODO move this to tone location
final primaryColor = const Color(0xFF75A2EA);
enum AuthFormType { signIn, signUp, reset, anonymous, convert, phone }
class SignUpView extends StatefulWidget {
final AuthFormType authFormType;
SignUpView({Key key, @required this.authFormType}) : super(key: key);
@override
_SignUpViewState createState() =>
_SignUpViewState(authFormType: this.authFormType);
}
class _SignUpViewState extends State<SignUpView> {
AuthFormType authFormType;
bool _showAppleSignIn = false;
@override
void initState() {
super.initState();
_useAppleSignIn();
}
_useAppleSignIn() async {
final isAvailable = await AppleSignIn.isAvailable();
setState(() {
_showAppleSignIn = isAvailable;
});
}
_SignUpViewState({this.authFormType});
final formKey = GlobalKey<FormState>();
String _email, _password, _name, _warning, _phone;
void switchFormState(String state) {
formKey.currentState.reset();
if (state == "signUp") {
setState(() {
authFormType = AuthFormType.signUp;
});
} else if (state == 'home') {
Navigator.of(context).pop();
} else {
setState(() {
authFormType = AuthFormType.signIn;
});
}
}
bool validate() {
final form = formKey.currentState;
if (authFormType == AuthFormType.anonymous) {
return true;
}
form.save();
if (form.validate()) {
form.save();
return true;
} else {
return false;
}
}
void submit() async {
if (validate()) {
try {
final auth = Provider.of(context).auth;
switch (authFormType) {
case AuthFormType.signIn:
await auth.signInWithEmailAndPassword(_email, _password);
Navigator.of(context).pushReplacementNamed('/home');
break;
case AuthFormType.signUp:
await auth.createUserWithEmailAndPassword(_email, _password, _name);
Navigator.of(context).pushReplacementNamed('/home');
break;
case AuthFormType.reset:
await auth.sendPasswordResetEmail(_email);
setState(() {
_warning = "A password reset link has been sent to $_email";
authFormType = AuthFormType.signIn;
});
break;
case AuthFormType.anonymous:
await auth.singInAnonymously();
Navigator.of(context).pushReplacementNamed('/home');
break;
case AuthFormType.convert:
await auth.convertUserWithEmail(_email, _password, _name);
Navigator.of(context).pop();
break;
case AuthFormType.phone:
var result = await auth.createUserWithPhone(_phone, context);
if (_phone == "" || result == "error") {
setState(() {
_warning = "Your phone number could not be validated";
});
}
break;
}
} catch (e) {
setState(() {
_warning = e.message;
});
}
}
}
@override
Widget build(BuildContext context) {
final _width = MediaQuery.of(context).size.width;
final _height = MediaQuery.of(context).size.height;
if (authFormType == AuthFormType.anonymous) {
submit();
return Scaffold(
backgroundColor: primaryColor,
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SpinKitDoubleBounce(
color: Colors.white,
),
Text(
"Loading",
style: TextStyle(color: Colors.white),
),
],
),
));
} else {
return Scaffold(
body: SingleChildScrollView(
child: Container(
color: primaryColor,
height: _height,
width: _width,
child: SafeArea(
child: Column(
children: <Widget>[
SizedBox(height: _height * 0.025),
showAlert(),
SizedBox(height: _height * 0.025),
buildHeaderText(),
SizedBox(height: _height * 0.05),
Padding(
padding: const EdgeInsets.all(20.0),
child: Form(
key: formKey,
child: Column(
children: buildInputs() + buildButtons(),
),
),
),
],
),
),
),
),
);
}
}
Widget showAlert() {
if (_warning != null) {
return Container(
color: Colors.amberAccent,
width: double.infinity,
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Icon(Icons.error_outline),
),
Expanded(
child: AutoSizeText(
_warning,
maxLines: 3,
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: IconButton(
icon: Icon(Icons.close),
onPressed: () {
setState(() {
_warning = null;
});
},
),
)
],
),
);
}
return SizedBox(
height: 0,
);
}
AutoSizeText buildHeaderText() {
String _headerText;
if (authFormType == AuthFormType.signIn) {
_headerText = "Sign In";
} else if (authFormType == AuthFormType.reset) {
_headerText = "Reset Password";
} else if (authFormType == AuthFormType.phone) {
_headerText = "Phone Sign In";
} else {
_headerText = "Create New Account";
}
return AutoSizeText(
_headerText,
maxLines: 1,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 35,
color: Colors.white,
),
);
}
void onPhoneNumberChange(
String number, String internationalizedPhoneNumber, String isoCode) {
setState(() {
_phone = internationalizedPhoneNumber;
});
}
List<Widget> buildInputs() {
List<Widget> textFields = [];
// if were in the sign up state add name
if ([AuthFormType.signUp, AuthFormType.convert].contains(authFormType)) {
textFields.add(
TextFormField(
validator: NameValidator.validate,
style: TextStyle(fontSize: 22.0),
decoration: buildSignUpInputDecoration("Name"),
onSaved: (value) => _name = value,
),
);
textFields.add(SizedBox(height: 20));
}
// add email & password
if ([
AuthFormType.signUp,
AuthFormType.convert,
AuthFormType.reset,
AuthFormType.signIn
].contains(authFormType)) {
textFields.add(
TextFormField(
validator: EmailValidator.validate,
style: TextStyle(fontSize: 22.0),
decoration: buildSignUpInputDecoration("Email"),
onSaved: (value) => _email = value,
),
);
textFields.add(SizedBox(height: 20));
}
if (authFormType != AuthFormType.reset &&
authFormType != AuthFormType.phone) {
textFields.add(
TextFormField(
validator: PasswordValidator.validate,
style: TextStyle(fontSize: 22.0),
decoration: buildSignUpInputDecoration("Password"),
obscureText: true,
onSaved: (value) => _password = value,
),
);
textFields.add(SizedBox(height: 20));
}
if (authFormType == AuthFormType.phone) {
textFields.add(
InternationalPhoneInput(
decoration: buildSignUpInputDecoration("Enter Phone Number"),
onPhoneNumberChange: onPhoneNumberChange,
initialPhoneNumber: _phone,
initialSelection: 'US',
showCountryCodes: true),
);
textFields.add(SizedBox(height: 20));
}
return textFields;
}
InputDecoration buildSignUpInputDecoration(String hint) {
return InputDecoration(
hintText: hint,
filled: true,
fillColor: Colors.white,
focusColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white, width: 0.0)),
contentPadding:
const EdgeInsets.only(left: 14.0, bottom: 10.0, top: 10.0),
);
}
List<Widget> buildButtons() {
String _switchButtonText, _newFormState, _submitButtonText;
bool _showForgotPassword = false;
bool _showSocial = true;
if (authFormType == AuthFormType.signIn) {
_switchButtonText = "Create New Account";
_newFormState = "signUp";
_submitButtonText = "Sign In";
_showForgotPassword = true;
} else if (authFormType == AuthFormType.reset) {
_switchButtonText = "Return to Sign In";
_newFormState = "signIn";
_submitButtonText = "Submit";
_showSocial = false;
} else if (authFormType == AuthFormType.convert) {
_switchButtonText = "Cancel";
_newFormState = "home";
_submitButtonText = "Sign Up";
} else if (authFormType == AuthFormType.phone) {
_switchButtonText = "Cancel";
_newFormState = "signIn";
_submitButtonText = "Continue";
_showSocial = false;
} else {
_switchButtonText = "Have an Account? Sign In";
_newFormState = "signIn";
_submitButtonText = "Sign Up";
}
return [
Container(
width: MediaQuery.of(context).size.width * 0.7,
child: RaisedButton(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)),
color: Colors.white,
textColor: primaryColor,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
_submitButtonText,
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.w300),
),
),
onPressed: submit,
),
),
showForgotPassword(_showForgotPassword),
FlatButton(
child: Text(
_switchButtonText,
style: TextStyle(color: Colors.white),
),
onPressed: () {
switchFormState(_newFormState);
},
),
buildSocialIcons(_showSocial),
];
}
Widget showForgotPassword(bool visible) {
return Visibility(
child: FlatButton(
child: Text(
"Forgot Password?",
style: TextStyle(color: Colors.white),
),
onPressed: () {
setState(() {
authFormType = AuthFormType.reset;
});
},
),
visible: visible,
);
}
Widget buildSocialIcons(bool visible) {
final _auth = Provider.of(context).auth;
return Visibility(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Divider(
color: Colors.white,
),
SizedBox(height: 10),
buildAppleSignIn(_auth),
SizedBox(height: 10),
GoogleSignInButton(
onPressed: () async {
try {
if (authFormType == AuthFormType.convert) {
await _auth.convertWithGoogle();
Navigator.of(context).pop();
} else {
await _auth.signInWithGoogle();
Navigator.of(context).pushReplacementNamed('/home');
}
} catch (e) {
setState(() {
_warning = e.message;
});
}
},
),
RaisedButton(
color: Colors.green,
textColor: Colors.white,
child: Row(
children: <Widget>[
Icon(Icons.phone),
Padding(
padding: const EdgeInsets.only(
left: 14.0, top: 10.0, bottom: 10.0),
child: Text("Sign in with Phone",
style: TextStyle(fontSize: 18)),
)
],
),
onPressed: () {
setState(() {
authFormType = AuthFormType.phone;
});
},
),
],
),
visible: visible,
);
}
Widget buildAppleSignIn(_auth) {
if (authFormType != AuthFormType.convert && _showAppleSignIn == true) {
return AppleSignInButton(
onPressed: () async {
await _auth.signInWithApple();
Navigator.of(context).pushReplacementNamed('/home');
},
style: ButtonStyle.black,
);
} else {
return Container();
}
}
}
================================================
FILE: lib/widgets/calculator_widget.dart
================================================
import 'package:flutter/material.dart';
import 'package:travel_budget/widgets/money_text_field.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:travel_budget/widgets/provider_widget.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class CalculatorWidget extends StatefulWidget {
final Trip trip;
CalculatorWidget({
@required this.trip,
});
@override
_CalculatorWidgetState createState() => _CalculatorWidgetState();
}
class _CalculatorWidgetState extends State<CalculatorWidget> {
TextEditingController _moneyController = TextEditingController();
int _saved;
int _needed;
@override
void initState() {
super.initState();
_saved = (widget.trip.saved ?? 0.0).floor();
_needed = (widget.trip.budget.floor() * widget.trip.getTotalTripDays()) - _saved;
}
@override
Widget build(BuildContext context) {
return Card(
child: Column(
children: <Widget>[
Container(
color: Colors.cyan,
child: Padding(
padding: const EdgeInsets.only(top: 12.0, bottom: 12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Column(
children: <Widget>[
Text("\$$_saved", style: TextStyle(fontSize: 60)),
Text("Saved", style: TextStyle(fontSize: 20)),
],
),
Container(
height: 80,
child: VerticalDivider(
color: Colors.white,
thickness: 5,
),
),
Column(
children: <Widget>[
Text("\$$_needed", style: TextStyle(fontSize: 60)),
Text("Needed", style: TextStyle(fontSize: 20)),
],
),
],
),
),
),
Container(
color: Colors.orangeAccent,
child: Padding(
padding: const EdgeInsets.only(left: 20.0, right: 40.0),
child: Row(
children: <Widget>[
Expanded(
child: MoneyTextField(
controller: _moneyController,
helperText: "Save Additional",
),
),
IconButton(
icon: Icon(Icons.add_circle),
color: Colors.green,
iconSize: 50,
onPressed: () async {
setState(() {
_saved = _saved + int.parse(_moneyController.text);
_needed = _needed - int.parse(_moneyController.text);
});
final uid = await Provider.of(context).auth.getCurrentUID();
await FirebaseFirestore.instance.collection('userData')
.doc(uid)
.collection('trips')
.doc(widget.trip.documentId)
.update({'saved': _saved.toDouble()});
},
),
IconButton(
icon: Icon(Icons.remove_circle),
color: Colors.red,
iconSize: 50,
onPressed: () async {
setState(() {
_saved = _saved - int.parse(_moneyController.text);
_needed = _needed + int.parse(_moneyController.text);
});
final uid = await Provider.of(context).auth.getCurrentUID();
await FirebaseFirestore.instance.collection('userData')
.doc(uid)
.collection('trips')
.doc(widget.trip.documentId)
.update({'saved': _saved.toDouble()});
},
)
],
),
),
),
Container(
color: Colors.orangeAccent,
child: Padding(
padding: const EdgeInsets.only(bottom: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
generateAddMoneyBtn(25),
generateAddMoneyBtn(50),
generateAddMoneyBtn(100),
],
),
),
)
],
),
);
}
RaisedButton generateAddMoneyBtn(int amount) {
return RaisedButton(
child: Text("\$$amount"),
color: Colors.white,
textColor: Colors.deepOrange,
onPressed: () async {
setState(() {
_saved = _saved + amount;
_needed = _needed - amount;
});
final uid = await Provider.of(context).auth.getCurrentUID();
await FirebaseFirestore.instance.collection('userData')
.doc(uid)
.collection('trips')
.doc(widget.trip.documentId)
.update({'saved': _saved.toDouble()});
},
);
}
}
================================================
FILE: lib/widgets/custom_dialog.dart
================================================
import 'package:flutter/material.dart';
import 'package:auto_size_text/auto_size_text.dart';
class CustomDialog extends StatelessWidget {
final primaryColor = const Color(0xFF75A2EA);
final grayColor = const Color(0xFF939393);
final String title,
description,
primaryButtonText,
primaryButtonRoute,
secondaryButtonText,
secondaryButtonRoute;
CustomDialog(
{@required this.title,
@required this.description,
@required this.primaryButtonText,
@required this.primaryButtonRoute,
this.secondaryButtonText,
this.secondaryButtonRoute});
static const double padding = 20.0;
@override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(padding),
),
child: Stack(
children: <Widget>[
Container(
padding: EdgeInsets.all(padding),
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(padding),
boxShadow: [
BoxShadow(
color: Colors.black,
blurRadius: 10.0,
offset: const Offset(0.0, 10.0),
),
]),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(height: 24.0),
AutoSizeText(
title,
maxLines: 2,
textAlign: TextAlign.center,
style: TextStyle(
color: primaryColor,
fontSize: 25.0,
),
),
SizedBox(height: 24.0),
AutoSizeText(
description,
maxLines: 4,
textAlign: TextAlign.center,
style: TextStyle(
color: grayColor,
fontSize: 18.0,
),
),
SizedBox(height: 24.0),
RaisedButton(
color: primaryColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0)),
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 10, 20, 10),
child: AutoSizeText(
primaryButtonText,
maxLines: 1,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w200,
color: Colors.white,
),
),
),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context)
.pushReplacementNamed(primaryButtonRoute);
},
),
SizedBox(height: 10.0),
showSecondaryButton(context),
],
),
)
],
),
);
}
showSecondaryButton(BuildContext context) {
if (secondaryButtonRoute != null && secondaryButtonText != null ){
return FlatButton(
child: AutoSizeText(
secondaryButtonText,
maxLines: 1,
style: TextStyle(
fontSize: 18,
color: primaryColor,
fontWeight: FontWeight.w400,
),
),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).pushReplacementNamed(secondaryButtonRoute);
},
);
} else {
return SizedBox(height: 10.0);
}
}
}
================================================
FILE: lib/widgets/divider_with_text_widget.dart
================================================
import 'package:flutter/material.dart';
class DividerWithText extends StatelessWidget {
final String dividerText;
const DividerWithText({Key key, @required this.dividerText}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Expanded(child: Padding(
padding: const EdgeInsets.only(right:8.0),
child: Divider(),
)),
Text(dividerText),
Expanded(child: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Divider(),
)),
],
);
}
}
================================================
FILE: lib/widgets/money_text_field.dart
================================================
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class MoneyTextField extends StatelessWidget {
final TextEditingController controller;
final String helperText;
const MoneyTextField({Key key, @required this.controller, this.helperText})
: super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(30.0),
child: TextField(
controller: controller,
maxLines: 1,
decoration: InputDecoration(
prefixIcon: Icon(Icons.attach_money),
helperText: helperText,
),
keyboardType: TextInputType.numberWithOptions(decimal: false),
inputFormatters: [
WhitelistingTextInputFormatter.digitsOnly,
],
autofocus: false,
),
);
}
}
================================================
FILE: lib/widgets/provider_widget.dart
================================================
import 'package:travel_budget/services/auth_service.dart';
import 'package:flutter/material.dart';
class Provider extends InheritedWidget {
final AuthService auth;
final db;
final colors;
Provider({Key key, Widget child, this.auth, this.db, this.colors}) : super(key: key, child: child);
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
return true;
}
static Provider of(BuildContext context) =>
(context.dependOnInheritedWidgetOfExactType<Provider>());
}
================================================
FILE: lib/widgets/rounded_button.dart
================================================
import 'package:flutter/material.dart';
class RoundedButton extends RaisedButton {
final VoidCallback onPressed;
final Widget child;
final Color color;
const RoundedButton({@required this.onPressed, this.child, this.color}) : super(onPressed: onPressed, child: child);
@override
Widget build(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
buttonTheme: Theme.of(context).buttonTheme.copyWith(
shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30.0)),
buttonColor: color,
)
),
child: Builder(builder: super.build),
);
}
}
================================================
FILE: lib/widgets/trip_card.dart
================================================
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:travel_budget/models/Trip.dart';
import 'package:travel_budget/services/admob_service.dart';
import 'package:travel_budget/views/detail_trip_view.dart';
Widget buildTripCard(BuildContext context, DocumentSnapshot document, [bool loadBannerAd]) {
final trip = Trip.fromSnapshot(document);
final tripType = trip.types();
return new Container(
child: Card(
child: InkWell(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 4.0),
child: Row(children: <Widget>[
Text(
trip.title,
style: GoogleFonts.seymourOne(fontSize: 20.0),
),
Spacer(),
]),
),
Padding(
padding: const EdgeInsets.only(top: 4.0, bottom: 80.0),
child: Row(children: <Widget>[
Text(
"${DateFormat('MM/dd/yyyy').format(trip.startDate).toString()} - ${DateFormat('MM/dd/yyyy').format(trip.endDate).toString()}"),
Spacer(),
]),
),
Padding(
padding: const EdgeInsets.only(top: 8.0, bottom: 8.0),
child: Row(
children: <Widget>[
Text(
"\$${(trip.budget == null) ? "n/a" : trip.budget.toStringAsFixed(2)}",
style: new TextStyle(fontSize: 35.0),
),
Spacer(),
(tripType.containsKey(trip.travelType)) ? tripType[trip.travelType] : tripType["other"],
],
),
)
],
),
),
onTap: () {
if (loadBannerAd == true) {
Navigator.push(context, MaterialPageRoute(builder: (context) => DetailTripView(trip: trip))).then((value) {
AdMobService.showHomeBannerAd();
});
} else {
Navigator.push(context, MaterialPageRoute(builder: (context) => DetailTripView(trip: trip)));
}
},
),
),
);
}
================================================
FILE: pubspec.yaml
================================================
name: travel_budget
description: A new Flutter application.
# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
firebase_core: ^0.5.3
cloud_firestore: ^0.14.0
firebase_auth: ^0.18.0
google_sign_in: ^4.0.4
apple_sign_in: ^0.1.0
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
intl: 0.16.1
date_range_picker: ^1.0.5
auto_size_text: ^2.0.2
flutter_spinkit: ^3.1.0
flutter_auth_buttons: ^0.5.0
dio: ^3.0.10
uuid: 2.0.1
device_info: ^0.4.1+4
google_fonts: ^0.3.2
firebase_admob: ^0.10.0-dev.1
flare_flutter: ^2.0.3
international_phone_input: ^1.0.4
flutter_launcher_icons: "^0.7.3"
firebase_crashlytics: "^0.2.4"
# flutter pub run flutter_launcher_icons:main
flutter_icons:
image_path: "assets/icons/main_logo.png"
adaptive_icon_foreground: "assets/icons/foreground_logo.png"
adaptive_icon_background: "#57AEAF"
android: true
ios: true
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
# To add assets to your application, add an assets section, like this:
assets:
- assets/
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
================================================
FILE: res/values/strings_en.arb
================================================
================================================
FILE: test/widget_test.dart
================================================
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:travel_budget/main.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(MyApp());
// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);
expect(find.text('1'), findsNothing);
// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
}
gitextract_mhc07qrs/
├── .github/
│ └── FUNDING.yml
├── .gitignore
├── .metadata
├── LICENSE
├── README.md
├── android/
│ ├── app/
│ │ ├── build.gradle
│ │ └── src/
│ │ ├── debug/
│ │ │ └── AndroidManifest.xml
│ │ ├── main/
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin/
│ │ │ │ └── com/
│ │ │ │ └── a1manstartup/
│ │ │ │ └── travel_budget/
│ │ │ │ └── MainActivity.kt
│ │ │ └── res/
│ │ │ ├── drawable/
│ │ │ │ └── launch_background.xml
│ │ │ ├── mipmap-anydpi-v26/
│ │ │ │ └── ic_launcher.xml
│ │ │ └── values/
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ │ └── profile/
│ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle/
│ │ └── wrapper/
│ │ └── gradle-wrapper.properties
│ ├── gradle.properties
│ ├── settings.gradle
│ └── settings_aar.gradle
├── assets/
│ └── sun_clouds.flr
├── ios/
│ ├── Flutter/
│ │ ├── .last_build_id
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ ├── Flutter.podspec
│ │ ├── Release.xcconfig
│ │ └── flutter_export_environment.sh
│ ├── Podfile
│ ├── Runner/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── LaunchImage.imageset/
│ │ │ ├── Contents.json
│ │ │ └── README.md
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ ├── Runner-Bridging-Header.h
│ │ └── Runner.entitlements
│ ├── Runner.xcodeproj/
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace/
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcshareddata/
│ │ └── xcschemes/
│ │ └── Runner.xcscheme
│ └── Runner.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ └── IDEWorkspaceChecks.plist
├── lib/
│ ├── classes/
│ │ └── progress_painter.dart
│ ├── generated/
│ │ └── i18n.dart
│ ├── main.dart
│ ├── models/
│ │ ├── Place.dart
│ │ ├── Trip.dart
│ │ └── User.dart
│ ├── services/
│ │ ├── admob_service.dart
│ │ ├── auth_service.dart
│ │ ├── custom_colors.dart
│ │ └── firebase_service.dart
│ ├── views/
│ │ ├── deposit_view.dart
│ │ ├── detail_trip_view.dart
│ │ ├── edit_notes_view.dart
│ │ ├── first_view.dart
│ │ ├── home_view.dart
│ │ ├── home_widgets/
│ │ │ ├── current_daily_budget.dart
│ │ │ ├── days_until_trip.dart
│ │ │ ├── home_header.dart
│ │ │ ├── notes.dart
│ │ │ ├── percent_saved.dart
│ │ │ ├── saved_vs_needed.dart
│ │ │ ├── travel_type.dart
│ │ │ └── trip_details_card.dart
│ │ ├── navigation_view.dart
│ │ ├── new_trips/
│ │ │ ├── budget_view.dart
│ │ │ ├── date_view.dart
│ │ │ ├── location_view.dart
│ │ │ └── summary_view.dart
│ │ ├── past_trips_view.dart
│ │ ├── profile_view.dart
│ │ └── sign_up_view.dart
│ └── widgets/
│ ├── calculator_widget.dart
│ ├── custom_dialog.dart
│ ├── divider_with_text_widget.dart
│ ├── money_text_field.dart
│ ├── provider_widget.dart
│ ├── rounded_button.dart
│ └── trip_card.dart
├── pubspec.yaml
├── res/
│ └── values/
│ └── strings_en.arb
└── test/
└── widget_test.dart
SYMBOL INDEX (203 symbols across 39 files)
FILE: lib/classes/progress_painter.dart
class ProgressPainter (line 4) | class ProgressPainter extends CustomPainter {
method paint (line 25) | void paint(Canvas canvas, Size size)
method shouldRepaint (line 39) | bool shouldRepaint(CustomPainter painter)
FILE: lib/generated/i18n.dart
class S (line 11) | class S implements WidgetsLocalizations {
method of (line 19) | S of(BuildContext context)
class $en (line 26) | class $en extends S {
class GeneratedLocalizationsDelegate (line 30) | class GeneratedLocalizationsDelegate extends LocalizationsDelegate<S> {
method listResolution (line 39) | LocaleListResolutionCallback listResolution({Locale fallback, bool wit...
method resolution (line 49) | LocaleResolutionCallback resolution({Locale fallback, bool withCountry...
method load (line 56) | Future<S> load(Locale locale)
method isSupported (line 72) | bool isSupported(Locale locale)
method shouldReload (line 75) | bool shouldReload(GeneratedLocalizationsDelegate old)
method _resolve (line 80) | Locale _resolve(Locale locale, Locale fallback, Iterable<Locale> suppo...
method _isSupported (line 99) | bool _isSupported(Locale locale, bool withCountry)
function getLang (line 122) | String getLang(Locale l)
FILE: lib/main.dart
function main (line 15) | void main()
class MyApp (line 23) | class MyApp extends StatefulWidget {
method createState (line 25) | _MyAppState createState()
class _MyAppState (line 28) | class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
method initState (line 32) | void initState()
method dispose (line 38) | void dispose()
method didChangePlatformBrightness (line 44) | void didChangePlatformBrightness()
method build (line 51) | Widget build(BuildContext context)
class HomeController (line 80) | class HomeController extends StatelessWidget {
method build (line 82) | Widget build(BuildContext context)
FILE: lib/models/Place.dart
class Place (line 1) | class Place {
FILE: lib/models/Trip.dart
class Trip (line 6) | class Trip {
method toJson (line 30) | Map<String, dynamic> toJson()
method types (line 56) | Map<String, Icon> types({color = Colors.black})
method getLocationImage (line 66) | Image getLocationImage()
method getTotalTripDays (line 73) | int getTotalTripDays()
method getDaysUntilTrip (line 81) | int getDaysUntilTrip()
method getCurrentDailyBudget (line 89) | int getCurrentDailyBudget()
method ledgerItem (line 97) | Map<String, dynamic> ledgerItem(String amount, String type)
FILE: lib/models/User.dart
class User (line 1) | class User {
method toJson (line 7) | Map<String, dynamic> toJson()
FILE: lib/services/admob_service.dart
class AdMobService (line 5) | class AdMobService {
method getAdMobAppId (line 7) | String getAdMobAppId()
method _getBannerAdId (line 16) | String _getBannerAdId()
method getInterstitialAdId (line 27) | String getInterstitialAdId()
method getNewTripInterstitial (line 39) | InterstitialAd getNewTripInterstitial()
method _getHomePageBannerAd (line 50) | BannerAd _getHomePageBannerAd()
method showHomeBannerAd (line 57) | void showHomeBannerAd()
method hideHomeBannerAd (line 64) | void hideHomeBannerAd()
FILE: lib/services/auth_service.dart
class AuthService (line 7) | class AuthService {
method getCurrentUID (line 16) | String getCurrentUID()
method getCurrentUser (line 21) | Future getCurrentUser()
method createUserWithEmailAndPassword (line 34) | Future<String> createUserWithEmailAndPassword(
method updateUserName (line 46) | Future updateUserName(String name, User currentUser)
method signInWithEmailAndPassword (line 52) | Future<String> signInWithEmailAndPassword(
method sendPasswordResetEmail (line 66) | Future sendPasswordResetEmail(String email)
method singInAnonymously (line 71) | Future singInAnonymously()
method convertUserWithEmail (line 75) | Future convertUserWithEmail(
method convertWithGoogle (line 85) | Future convertWithGoogle()
method signInWithGoogle (line 98) | Future<String> signInWithGoogle()
method signInWithApple (line 109) | Future signInWithApple()
method createUserWithPhone (line 144) | Future createUserWithPhone(String phone, BuildContext context)
class NameValidator (line 196) | class NameValidator {
method validate (line 197) | String validate(String value)
class EmailValidator (line 211) | class EmailValidator {
method validate (line 212) | String validate(String value)
class PasswordValidator (line 220) | class PasswordValidator {
method validate (line 221) | String validate(String value)
FILE: lib/services/custom_colors.dart
class CustomColors (line 3) | class CustomColors {
FILE: lib/services/firebase_service.dart
class FirebaseService (line 5) | class FirebaseService {
method getNextTrip (line 7) | Future<Trip> getNextTrip(context)
method addToLedger (line 19) | void addToLedger(context, documentId, item)
FILE: lib/views/deposit_view.dart
class DepositView (line 9) | class DepositView extends StatefulWidget {
method createState (line 17) | _DepositViewState createState()
class _DepositViewState (line 20) | class _DepositViewState extends State<DepositView> {
method build (line 25) | Widget build(BuildContext context)
method _numberBtn (line 75) | Widget _numberBtn(String number)
method _deleteBtn (line 96) | Widget _deleteBtn()
method _actionBtn (line 114) | Widget _actionBtn(String type)
FILE: lib/views/detail_trip_view.dart
class DetailTripView (line 12) | class DetailTripView extends StatefulWidget {
method createState (line 18) | _DetailTripViewState createState()
class _DetailTripViewState (line 21) | class _DetailTripViewState extends State<DetailTripView> {
method initState (line 25) | void initState()
method build (line 33) | Widget build(BuildContext context)
method daysOutCard (line 77) | Widget daysOutCard()
method tripDetails (line 93) | Widget tripDetails()
method totalBudgetCard (line 122) | Widget totalBudgetCard()
method notesCard (line 174) | Widget notesCard(context)
method setNoteText (line 211) | List<Widget> setNoteText()
method _tripEditModalBottomSheet (line 228) | void _tripEditModalBottomSheet(context)
method updateTrip (line 312) | Future updateTrip(context)
method deleteTrip (line 323) | Future deleteTrip(context)
FILE: lib/views/edit_notes_view.dart
class EditNotesView (line 7) | class EditNotesView extends StatefulWidget {
method createState (line 13) | _EditNotesViewState createState()
class _EditNotesViewState (line 16) | class _EditNotesViewState extends State<EditNotesView> {
method initState (line 22) | void initState()
method build (line 28) | Widget build(BuildContext context)
method buildHeading (line 53) | Widget buildHeading(context)
method buildNotesText (line 78) | Widget buildNotesText()
method buildSubmitButton (line 97) | Widget buildSubmitButton(context)
FILE: lib/views/first_view.dart
class FirstView (line 5) | class FirstView extends StatelessWidget {
method build (line 9) | Widget build(BuildContext context)
FILE: lib/views/home_view.dart
class HomeView (line 13) | class HomeView extends StatefulWidget {
method createState (line 21) | _HomeViewState createState()
class _HomeViewState (line 24) | class _HomeViewState extends State<HomeView> {
method build (line 26) | Widget build(BuildContext context)
FILE: lib/views/home_widgets/current_daily_budget.dart
class CurrentDailyBudget (line 4) | class CurrentDailyBudget extends StatelessWidget {
method build (line 9) | Widget build(BuildContext context)
FILE: lib/views/home_widgets/days_until_trip.dart
class DaysUntilTrip (line 4) | class DaysUntilTrip extends StatelessWidget {
method build (line 9) | Widget build(BuildContext context)
FILE: lib/views/home_widgets/home_header.dart
class HomeHeader (line 4) | class HomeHeader extends StatelessWidget {
method build (line 9) | Widget build(BuildContext context)
FILE: lib/views/home_widgets/notes.dart
class Notes (line 5) | class Notes extends StatelessWidget {
method build (line 11) | Widget build(BuildContext context)
method setNoteText (line 47) | List<Widget> setNoteText()
FILE: lib/views/home_widgets/percent_saved.dart
class PercentSaved (line 5) | class PercentSaved extends StatelessWidget {
method build (line 10) | Widget build(BuildContext context)
FILE: lib/views/home_widgets/saved_vs_needed.dart
class SavedVsNeeded (line 4) | class SavedVsNeeded extends StatelessWidget {
method build (line 9) | Widget build(BuildContext context)
FILE: lib/views/home_widgets/travel_type.dart
class TravelType (line 4) | class TravelType extends StatelessWidget {
method getTypeIcon (line 8) | Widget getTypeIcon()
method build (line 17) | Widget build(BuildContext context)
FILE: lib/views/home_widgets/trip_details_card.dart
class TripDetailsCard (line 6) | class TripDetailsCard extends StatelessWidget {
method build (line 11) | Widget build(BuildContext context)
FILE: lib/views/navigation_view.dart
class NavigationView (line 8) | class NavigationView extends StatefulWidget {
method createState (line 10) | State<StatefulWidget> createState()
class _NavigationViewState (line 15) | class _NavigationViewState extends State<NavigationView> {
method didChangeDependencies (line 21) | void didChangeDependencies()
method build (line 27) | Widget build(BuildContext context)
method onTabTapped (line 96) | void onTabTapped(int index)
FILE: lib/views/new_trips/budget_view.dart
type budgetType (line 7) | enum budgetType { simple, complex }
class NewTripBudgetView (line 9) | class NewTripBudgetView extends StatefulWidget {
method createState (line 15) | _NewTripBudgetViewState createState()
class _NewTripBudgetViewState (line 18) | class _NewTripBudgetViewState extends State<NewTripBudgetView> {
method initState (line 30) | void initState()
method setBudgetFields (line 58) | List<Widget> setBudgetFields(_budgetController)
method build (line 122) | Widget build(BuildContext context)
FILE: lib/views/new_trips/date_view.dart
class NewTripDateView (line 9) | class NewTripDateView extends StatefulWidget {
method createState (line 15) | _NewTripDateViewState createState()
class _NewTripDateViewState (line 18) | class _NewTripDateViewState extends State<NewTripDateView> {
method displayDateRangePicker (line 22) | Future displayDateRangePicker(BuildContext context)
method build (line 38) | Widget build(BuildContext context)
method buildButtons (line 64) | Widget buildButtons()
method buildingSelectedDates (line 102) | Widget buildingSelectedDates()
method buildSelectedDetails (line 157) | Widget buildSelectedDetails(BuildContext context, Trip trip)
FILE: lib/views/new_trips/location_view.dart
class NewTripLocationView (line 13) | class NewTripLocationView extends StatefulWidget {
method createState (line 19) | _NewTripLocationViewState createState()
class _NewTripLocationViewState (line 22) | class _NewTripLocationViewState extends State<NewTripLocationView> {
method initState (line 39) | void initState()
method dispose (line 47) | void dispose()
method getLocationResults (line 62) | void getLocationResults(String input)
method getLocationPhotoRef (line 94) | Future<String> getLocationPhotoRef(placeId)
method build (line 101) | Widget build(BuildContext context)
method buildPlaceCard (line 137) | Widget buildPlaceCard(BuildContext context, int index)
FILE: lib/views/new_trips/summary_view.dart
class NewTripSummaryView (line 10) | class NewTripSummaryView extends StatelessWidget {
method build (line 18) | Widget build(BuildContext context)
FILE: lib/views/past_trips_view.dart
class PastTripsView (line 8) | class PastTripsView extends StatefulWidget {
method createState (line 10) | _PastTripsViewState createState()
class _PastTripsViewState (line 13) | class _PastTripsViewState extends State<PastTripsView> {
method initState (line 21) | void initState()
method dispose (line 27) | void dispose()
method didChangeDependencies (line 34) | void didChangeDependencies()
method build (line 80) | Widget build(BuildContext context)
FILE: lib/views/profile_view.dart
class ProfileView (line 6) | class ProfileView extends StatefulWidget {
method createState (line 8) | _ProfileViewState createState()
class _ProfileViewState (line 11) | class _ProfileViewState extends State<ProfileView> {
method build (line 17) | Widget build(BuildContext context)
method displayUserInformation (line 39) | Widget displayUserInformation(context, snapshot)
method showSignOut (line 115) | Widget showSignOut(context, bool isAnonymous)
method adminFeature (line 137) | Widget adminFeature()
method _userEditBottomSheet (line 145) | void _userEditBottomSheet(BuildContext context)
FILE: lib/views/sign_up_view.dart
type AuthFormType (line 13) | enum AuthFormType { signIn, signUp, reset, anonymous, convert, phone }
class SignUpView (line 15) | class SignUpView extends StatefulWidget {
method createState (line 21) | _SignUpViewState createState()
class _SignUpViewState (line 25) | class _SignUpViewState extends State<SignUpView> {
method initState (line 30) | void initState()
method switchFormState (line 48) | void switchFormState(String state)
method validate (line 63) | bool validate()
method submit (line 77) | void submit()
method build (line 123) | Widget build(BuildContext context)
method showAlert (line 178) | Widget showAlert()
method buildHeaderText (line 216) | AutoSizeText buildHeaderText()
method onPhoneNumberChange (line 238) | void onPhoneNumberChange(
method buildInputs (line 245) | List<Widget> buildInputs()
method buildSignUpInputDecoration (line 308) | InputDecoration buildSignUpInputDecoration(String hint)
method buildButtons (line 321) | List<Widget> buildButtons()
method showForgotPassword (line 383) | Widget showForgotPassword(bool visible)
method buildSocialIcons (line 400) | Widget buildSocialIcons(bool visible)
method buildAppleSignIn (line 455) | Widget buildAppleSignIn(_auth)
FILE: lib/widgets/calculator_widget.dart
class CalculatorWidget (line 7) | class CalculatorWidget extends StatefulWidget {
method createState (line 15) | _CalculatorWidgetState createState()
class _CalculatorWidgetState (line 18) | class _CalculatorWidgetState extends State<CalculatorWidget> {
method initState (line 24) | void initState()
method build (line 31) | Widget build(BuildContext context)
method generateAddMoneyBtn (line 135) | RaisedButton generateAddMoneyBtn(int amount)
FILE: lib/widgets/custom_dialog.dart
class CustomDialog (line 4) | class CustomDialog extends StatelessWidget {
method build (line 26) | Widget build(BuildContext context)
FILE: lib/widgets/divider_with_text_widget.dart
class DividerWithText (line 3) | class DividerWithText extends StatelessWidget {
method build (line 8) | Widget build(BuildContext context)
FILE: lib/widgets/money_text_field.dart
class MoneyTextField (line 4) | class MoneyTextField extends StatelessWidget {
method build (line 12) | Widget build(BuildContext context)
FILE: lib/widgets/provider_widget.dart
class Provider (line 4) | class Provider extends InheritedWidget {
method updateShouldNotify (line 12) | bool updateShouldNotify(InheritedWidget oldWidget)
method of (line 16) | Provider of(BuildContext context)
FILE: lib/widgets/rounded_button.dart
class RoundedButton (line 3) | class RoundedButton extends RaisedButton {
method build (line 11) | Widget build(BuildContext context)
FILE: lib/widgets/trip_card.dart
function buildTripCard (line 9) | Widget buildTripCard(BuildContext context, DocumentSnapshot document, [b...
FILE: test/widget_test.dart
function main (line 13) | void main()
Condensed preview — 83 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (199K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 754,
"preview": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [u"
},
{
"path": ".gitignore",
"chars": 1415,
"preview": "# Miscellaneous\n*.class\n*.log\n*.pyc\n*.swp\n.DS_Store\n.atom/\n.buildlog/\n.history\n.svn/\n\n# IntelliJ related\n*.iml\n*.ipr\n*.i"
},
{
"path": ".metadata",
"chars": 305,
"preview": "# This file tracks properties of this Flutter project.\n# Used by Flutter tool to assess capabilities and perform upgrade"
},
{
"path": "LICENSE",
"chars": 1070,
"preview": "MIT License\n\nCopyright (c) 2019 Dave Faliskie\n\nPermission is hereby granted, free of charge, to any person obtaining a c"
},
{
"path": "README.md",
"chars": 1261,
"preview": "# Travel Treasury\n[Download The Live App](https://traveltreasury.app)\n\n\ndef localPropertiesFile = rootProject.file('local.properties')\nif (localPropertie"
},
{
"path": "android/app/src/debug/AndroidManifest.xml",
"chars": 338,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package=\"com.a1manstartup.travel_budget\">\n <"
},
{
"path": "android/app/src/main/AndroidManifest.xml",
"chars": 1972,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package=\"com.a1manstartup.travel_budget\">\n\n "
},
{
"path": "android/app/src/main/kotlin/com/a1manstartup/travel_budget/MainActivity.kt",
"chars": 346,
"preview": "package com.a1manstartup.travel_budget\n\nimport android.os.Bundle\n\nimport io.flutter.app.FlutterActivity\nimport io.flutte"
},
{
"path": "android/app/src/main/res/drawable/launch_background.xml",
"chars": 382,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Modify this file to customize your launch splash screen -->\n<layer-list xmln"
},
{
"path": "android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
"chars": 264,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <bac"
},
{
"path": "android/app/src/main/res/values/colors.xml",
"chars": 120,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"ic_launcher_background\">#57AEAF</color>\n</resources>"
},
{
"path": "android/app/src/main/res/values/styles.xml",
"chars": 361,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <style name=\"LaunchTheme\" parent=\"@android:style/Theme.Black.NoTi"
},
{
"path": "android/app/src/profile/AndroidManifest.xml",
"chars": 338,
"preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n package=\"com.a1manstartup.travel_budget\">\n <"
},
{
"path": "android/build.gradle",
"chars": 713,
"preview": "buildscript {\n ext.kotlin_version = '1.3.21'\n repositories {\n google()\n jcenter()\n }\n\n depende"
},
{
"path": "android/gradle/wrapper/gradle-wrapper.properties",
"chars": 233,
"preview": "#Fri Jun 23 08:50:38 CEST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER"
},
{
"path": "android/gradle.properties",
"chars": 104,
"preview": "org.gradle.jvmargs=-Xmx1536M\nandroid.useAndroidX=true\nandroid.enableJetifier=true\nandroid.enableR8=true\n"
},
{
"path": "android/settings.gradle",
"chars": 484,
"preview": "include ':app'\n\ndef flutterProjectRoot = rootProject.projectDir.parentFile.toPath()\n\ndef plugins = new Properties()\ndef "
},
{
"path": "android/settings_aar.gradle",
"chars": 15,
"preview": "include ':app'\n"
},
{
"path": "ios/Flutter/.last_build_id",
"chars": 32,
"preview": "ff43a8078c18a80d1d983aec4895d6ad"
},
{
"path": "ios/Flutter/AppFrameworkInfo.plist",
"chars": 773,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Flutter/Debug.xcconfig",
"chars": 106,
"preview": "#include \"Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig\"\n#include \"Generated.xcconfig\"\n"
},
{
"path": "ios/Flutter/Flutter.podspec",
"chars": 758,
"preview": "#\n# NOTE: This podspec is NOT to be published. It is only used as a local source!\n#\n\nPod::Spec.new do |s|\n s.name "
},
{
"path": "ios/Flutter/Release.xcconfig",
"chars": 108,
"preview": "#include \"Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig\"\n#include \"Generated.xcconfig\"\n"
},
{
"path": "ios/Flutter/flutter_export_environment.sh",
"chars": 768,
"preview": "#!/bin/sh\n# This is a generated file; do not edit or check into version control.\nexport \"FLUTTER_ROOT=/Users/davefaliski"
},
{
"path": "ios/Podfile",
"chars": 1354,
"preview": "# Uncomment this line to define a global platform for your project\n# platform :ios, '9.0'\n\n# CocoaPods analytics sends n"
},
{
"path": "ios/Runner/AppDelegate.swift",
"chars": 403,
"preview": "import UIKit\nimport Flutter\n\n@UIApplicationMain\n@objc class AppDelegate: FlutterAppDelegate {\n override func applicatio"
},
{
"path": "ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 2519,
"preview": "{\n \"images\" : [\n {\n \"size\" : \"20x20\",\n \"idiom\" : \"iphone\",\n \"filename\" : \"Icon-App-20x20@2x.png\",\n "
},
{
"path": "ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json",
"chars": 397,
"preview": "{\n \"images\" : [\n {\n \"filename\" : \"launch_screen.png\",\n \"idiom\" : \"universal\",\n \"scale\" : \"1x\"\n },\n"
},
{
"path": "ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md",
"chars": 336,
"preview": "# Launch Screen Assets\n\nYou can customize the launch screen with your own desired assets by replacing the image files in"
},
{
"path": "ios/Runner/Base.lproj/LaunchScreen.storyboard",
"chars": 2714,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3"
},
{
"path": "ios/Runner/Base.lproj/Main.storyboard",
"chars": 1605,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "ios/Runner/Info.plist",
"chars": 2223,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner/Runner-Bridging-Header.h",
"chars": 37,
"preview": "#import \"GeneratedPluginRegistrant.h\""
},
{
"path": "ios/Runner/Runner.entitlements",
"chars": 278,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner.xcodeproj/project.pbxproj",
"chars": 27800,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 152,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:Runner.xcodepr"
},
{
"path": "ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme",
"chars": 3331,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"0910\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "ios/Runner.xcworkspace/contents.xcworkspacedata",
"chars": 224,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"group:Runner.xcodepr"
},
{
"path": "ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "lib/classes/progress_painter.dart",
"chars": 1204,
"preview": "import 'package:flutter/material.dart';\nimport 'dart:math';\n\nclass ProgressPainter extends CustomPainter {\n Color defau"
},
{
"path": "lib/generated/i18n.dart",
"chars": 3548,
"preview": "import 'dart:async';\n\nimport 'package:flutter/foundation.dart';\nimport 'package:flutter/material.dart';\n\n// ignore_for_f"
},
{
"path": "lib/main.dart",
"chars": 3355,
"preview": "import 'package:cloud_firestore/cloud_firestore.dart';\nimport 'package:firebase_core/firebase_core.dart';\nimport 'packag"
},
{
"path": "lib/models/Place.dart",
"chars": 154,
"preview": "class Place {\n String name;\n double averageBudget;\n String placeId;\n\n Place(\n this.name,\n this.averageBudg"
},
{
"path": "lib/models/Trip.dart",
"chars": 3047,
"preview": "import 'package:flutter/material.dart';\nimport 'package:cloud_firestore/cloud_firestore.dart';\nimport 'package:travel_bu"
},
{
"path": "lib/models/User.dart",
"chars": 172,
"preview": "class User {\n String homeCountry;\n bool admin;\n\n User(this.homeCountry);\n\n Map<String, dynamic> toJson() => {\n 'h"
},
{
"path": "lib/services/admob_service.dart",
"chars": 1734,
"preview": "import 'dart:io';\nimport 'package:firebase_admob/firebase_admob.dart';\nimport 'package:flutter/material.dart';\n\nclass Ad"
},
{
"path": "lib/services/auth_service.dart",
"chars": 7278,
"preview": "import 'package:apple_sign_in/apple_sign_in.dart';\nimport 'package:firebase_auth/firebase_auth.dart';\nimport 'package:fl"
},
{
"path": "lib/services/custom_colors.dart",
"chars": 404,
"preview": "import 'package:flutter/material.dart';\n\nclass CustomColors {\n Brightness brightness;\n Color text1, primary;\n\n Custom"
},
{
"path": "lib/services/firebase_service.dart",
"chars": 817,
"preview": "import 'package:cloud_firestore/cloud_firestore.dart';\nimport 'package:travel_budget/models/Trip.dart';\nimport 'package:"
},
{
"path": "lib/views/deposit_view.dart",
"chars": 4566,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\nimport 'package:travel_budget/models/Tri"
},
{
"path": "lib/views/detail_trip_view.dart",
"chars": 10126,
"preview": "import 'package:cloud_firestore/cloud_firestore.dart';\nimport 'package:flutter/material.dart';\nimport 'package:travel_bu"
},
{
"path": "lib/views/edit_notes_view.dart",
"chars": 3237,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/models/Trip.dart';\nimport 'package:cloud_firestore"
},
{
"path": "lib/views/first_view.dart",
"chars": 3120,
"preview": "import 'package:flutter/material.dart';\nimport 'package:auto_size_text/auto_size_text.dart';\nimport 'package:travel_budg"
},
{
"path": "lib/views/home_view.dart",
"chars": 2387,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/models/Trip.dart';\nimport 'package:travel_budget/v"
},
{
"path": "lib/views/home_widgets/current_daily_budget.dart",
"chars": 1180,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/models/Trip.dart';\n\nclass CurrentDailyBudget exten"
},
{
"path": "lib/views/home_widgets/days_until_trip.dart",
"chars": 1167,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/models/Trip.dart';\n\nclass DaysUntilTrip extends St"
},
{
"path": "lib/views/home_widgets/home_header.dart",
"chars": 1120,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/models/Trip.dart';\n\nclass HomeHeader extends State"
},
{
"path": "lib/views/home_widgets/notes.dart",
"chars": 1930,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/models/Trip.dart';\nimport 'package:travel_budget/v"
},
{
"path": "lib/views/home_widgets/percent_saved.dart",
"chars": 2252,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/classes/progress_painter.dart';\nimport 'package:tr"
},
{
"path": "lib/views/home_widgets/saved_vs_needed.dart",
"chars": 2877,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/models/Trip.dart';\n\nclass SavedVsNeeded extends St"
},
{
"path": "lib/views/home_widgets/travel_type.dart",
"chars": 1521,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/models/Trip.dart';\n\nclass TravelType extends State"
},
{
"path": "lib/views/home_widgets/trip_details_card.dart",
"chars": 2680,
"preview": "import 'package:auto_size_text/auto_size_text.dart';\nimport 'package:flutter/material.dart';\nimport 'package:intl/intl.d"
},
{
"path": "lib/views/navigation_view.dart",
"chars": 2680,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/services/firebase_service.dart';\nimport 'package:t"
},
{
"path": "lib/views/new_trips/budget_view.dart",
"chars": 5052,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/models/Trip.dart';\nimport 'package:travel_budget/w"
},
{
"path": "lib/views/new_trips/date_view.dart",
"chars": 6246,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/models/Trip.dart';\nimport 'package:date_range_pick"
},
{
"path": "lib/views/new_trips/location_view.dart",
"chars": 6164,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/models/Trip.dart';\nimport 'package:travel_budget/m"
},
{
"path": "lib/views/new_trips/summary_view.dart",
"chars": 2878,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/models/Trip.dart';\nimport 'package:cloud_firestore"
},
{
"path": "lib/views/past_trips_view.dart",
"chars": 2739,
"preview": "import 'package:cloud_firestore/cloud_firestore.dart';\nimport 'package:flutter/material.dart';\nimport 'package:travel_bu"
},
{
"path": "lib/views/profile_view.dart",
"chars": 6580,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/widgets/provider_widget.dart';\nimport 'package:int"
},
{
"path": "lib/views/sign_up_view.dart",
"chars": 13432,
"preview": "import 'package:apple_sign_in/apple_sign_in.dart';\nimport 'package:flutter/material.dart';\nimport 'package:travel_budget"
},
{
"path": "lib/widgets/calculator_widget.dart",
"chars": 5282,
"preview": "import 'package:flutter/material.dart';\nimport 'package:travel_budget/widgets/money_text_field.dart';\nimport 'package:tr"
},
{
"path": "lib/widgets/custom_dialog.dart",
"chars": 3791,
"preview": "import 'package:flutter/material.dart';\nimport 'package:auto_size_text/auto_size_text.dart';\n\nclass CustomDialog extends"
},
{
"path": "lib/widgets/divider_with_text_widget.dart",
"chars": 594,
"preview": "import 'package:flutter/material.dart';\n\nclass DividerWithText extends StatelessWidget {\n final String dividerText;\n c"
},
{
"path": "lib/widgets/money_text_field.dart",
"chars": 837,
"preview": "import 'package:flutter/material.dart';\nimport 'package:flutter/services.dart';\n\nclass MoneyTextField extends StatelessW"
},
{
"path": "lib/widgets/provider_widget.dart",
"chars": 499,
"preview": "import 'package:travel_budget/services/auth_service.dart';\nimport 'package:flutter/material.dart';\n\nclass Provider exten"
},
{
"path": "lib/widgets/rounded_button.dart",
"chars": 640,
"preview": "import 'package:flutter/material.dart';\n\nclass RoundedButton extends RaisedButton {\n final VoidCallback onPressed;\n fi"
},
{
"path": "lib/widgets/trip_card.dart",
"chars": 2448,
"preview": "import 'package:cloud_firestore/cloud_firestore.dart';\nimport 'package:flutter/material.dart';\nimport 'package:google_fo"
},
{
"path": "pubspec.yaml",
"chars": 3413,
"preview": "name: travel_budget\ndescription: A new Flutter application.\n\n# The following defines the version and build number for yo"
},
{
"path": "res/values/strings_en.arb",
"chars": 0,
"preview": ""
},
{
"path": "test/widget_test.dart",
"chars": 1052,
"preview": "// This is a basic Flutter widget test.\n//\n// To perform an interaction with a widget in your test, use the WidgetTester"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the davefaliskie/travel_treasury GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 83 files (179.4 KB), approximately 45.5k tokens, and a symbol index with 203 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.