diff --git a/veggieseasons/.gitignore b/veggieseasons/.gitignore new file mode 100644 index 0000000..0542173 --- /dev/null +++ b/veggieseasons/.gitignore @@ -0,0 +1,45 @@ +# This app is designed to show how to use Flutter's cupertino package to build UI for iOS. It's not intended to run on Android, desktop, or web. +android + +# 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/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/veggieseasons/.metadata b/veggieseasons/.metadata new file mode 100644 index 0000000..9c1959e --- /dev/null +++ b/veggieseasons/.metadata @@ -0,0 +1,33 @@ +# 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: "5874a72aa4c779a02553007c47dacbefba2374dc" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc + base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc + - platform: ios + create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc + base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc + - platform: macos + create_revision: 5874a72aa4c779a02553007c47dacbefba2374dc + base_revision: 5874a72aa4c779a02553007c47dacbefba2374dc + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/veggieseasons/README.md b/veggieseasons/README.md new file mode 100644 index 0000000..bf21b07 --- /dev/null +++ b/veggieseasons/README.md @@ -0,0 +1,33 @@ +# Veggie Seasons + +An iOS sample app that shows which fruits and vegetables are currently in season. It +showcases Flutter's Cupertino package. + +**NOTE:** While Flutter supports many platforms, this application is designed +specifically for iOS. It's not intended to be run on Android, web, or desktop. + +## Goals + +* Show how to build an interface that iOS users will feel right at home + with. +* Show how Flutter's Cupertino widgets work together. + +## The important bits + +### `/screens/*` + +These are the screens presented in the app, roughly analogous to +UIViewControllers. `HomeScreen` is the root, and the others are shown +as the user navigates. + +## Questions/issues + +If you have a general question about any of the techniques you see in +the sample, the best places to go are: + +* [The FlutterDev Google Group](https://groups.google.com/forum/#!forum/flutter-dev) +* [The Flutter Gitter channel](https://gitter.im/flutter/flutter) +* [StackOverflow](https://stackoverflow.com/questions/tagged/flutter) + +If you run into an issue with the sample itself, please file an issue +in the [main Flutter repo](https://github.com/flutter/flutter/issues). diff --git a/veggieseasons/analysis_options.yaml b/veggieseasons/analysis_options.yaml new file mode 100644 index 0000000..e99e9ce --- /dev/null +++ b/veggieseasons/analysis_options.yaml @@ -0,0 +1,5 @@ +include: package:analysis_defaults/flutter.yaml + +linter: + rules: + - prefer_relative_imports \ No newline at end of file diff --git a/veggieseasons/assets/fonts/NotoSans-Bold.ttf b/veggieseasons/assets/fonts/NotoSans-Bold.ttf new file mode 100755 index 0000000..6e00cdc Binary files /dev/null and b/veggieseasons/assets/fonts/NotoSans-Bold.ttf differ diff --git a/veggieseasons/assets/fonts/NotoSans-BoldItalic.ttf b/veggieseasons/assets/fonts/NotoSans-BoldItalic.ttf new file mode 100755 index 0000000..51b7b29 Binary files /dev/null and b/veggieseasons/assets/fonts/NotoSans-BoldItalic.ttf differ diff --git a/veggieseasons/assets/fonts/NotoSans-Italic.ttf b/veggieseasons/assets/fonts/NotoSans-Italic.ttf new file mode 100755 index 0000000..dc93fea Binary files /dev/null and b/veggieseasons/assets/fonts/NotoSans-Italic.ttf differ diff --git a/veggieseasons/assets/fonts/NotoSans-Regular.ttf b/veggieseasons/assets/fonts/NotoSans-Regular.ttf new file mode 100755 index 0000000..9dd1019 Binary files /dev/null and b/veggieseasons/assets/fonts/NotoSans-Regular.ttf differ diff --git a/veggieseasons/assets/icon/launcher_icon.png b/veggieseasons/assets/icon/launcher_icon.png new file mode 100644 index 0000000..73c1b01 Binary files /dev/null and b/veggieseasons/assets/icon/launcher_icon.png differ diff --git a/veggieseasons/assets/images/apple.jpg b/veggieseasons/assets/images/apple.jpg new file mode 100644 index 0000000..7305880 Binary files /dev/null and b/veggieseasons/assets/images/apple.jpg differ diff --git a/veggieseasons/assets/images/artichoke.jpg b/veggieseasons/assets/images/artichoke.jpg new file mode 100644 index 0000000..43337dd Binary files /dev/null and b/veggieseasons/assets/images/artichoke.jpg differ diff --git a/veggieseasons/assets/images/asparagus.jpg b/veggieseasons/assets/images/asparagus.jpg new file mode 100644 index 0000000..76d340e Binary files /dev/null and b/veggieseasons/assets/images/asparagus.jpg differ diff --git a/veggieseasons/assets/images/avocado.jpg b/veggieseasons/assets/images/avocado.jpg new file mode 100644 index 0000000..16ec1e7 Binary files /dev/null and b/veggieseasons/assets/images/avocado.jpg differ diff --git a/veggieseasons/assets/images/blackberry.jpg b/veggieseasons/assets/images/blackberry.jpg new file mode 100644 index 0000000..4d8193a Binary files /dev/null and b/veggieseasons/assets/images/blackberry.jpg differ diff --git a/veggieseasons/assets/images/cantaloupe.jpg b/veggieseasons/assets/images/cantaloupe.jpg new file mode 100644 index 0000000..f048570 Binary files /dev/null and b/veggieseasons/assets/images/cantaloupe.jpg differ diff --git a/veggieseasons/assets/images/cauliflower.jpg b/veggieseasons/assets/images/cauliflower.jpg new file mode 100644 index 0000000..ce2aa91 Binary files /dev/null and b/veggieseasons/assets/images/cauliflower.jpg differ diff --git a/veggieseasons/assets/images/endive.jpg b/veggieseasons/assets/images/endive.jpg new file mode 100644 index 0000000..80c5b7e Binary files /dev/null and b/veggieseasons/assets/images/endive.jpg differ diff --git a/veggieseasons/assets/images/fig.jpg b/veggieseasons/assets/images/fig.jpg new file mode 100644 index 0000000..baaeafe Binary files /dev/null and b/veggieseasons/assets/images/fig.jpg differ diff --git a/veggieseasons/assets/images/grape.jpg b/veggieseasons/assets/images/grape.jpg new file mode 100644 index 0000000..94cd645 Binary files /dev/null and b/veggieseasons/assets/images/grape.jpg differ diff --git a/veggieseasons/assets/images/green_bell_pepper.jpg b/veggieseasons/assets/images/green_bell_pepper.jpg new file mode 100644 index 0000000..f9fac8c Binary files /dev/null and b/veggieseasons/assets/images/green_bell_pepper.jpg differ diff --git a/veggieseasons/assets/images/habanero.jpg b/veggieseasons/assets/images/habanero.jpg new file mode 100644 index 0000000..3d85abd Binary files /dev/null and b/veggieseasons/assets/images/habanero.jpg differ diff --git a/veggieseasons/assets/images/kale.jpg b/veggieseasons/assets/images/kale.jpg new file mode 100644 index 0000000..7a09929 Binary files /dev/null and b/veggieseasons/assets/images/kale.jpg differ diff --git a/veggieseasons/assets/images/kiwi.jpg b/veggieseasons/assets/images/kiwi.jpg new file mode 100644 index 0000000..21be2a6 Binary files /dev/null and b/veggieseasons/assets/images/kiwi.jpg differ diff --git a/veggieseasons/assets/images/lemon.jpg b/veggieseasons/assets/images/lemon.jpg new file mode 100644 index 0000000..62bd785 Binary files /dev/null and b/veggieseasons/assets/images/lemon.jpg differ diff --git a/veggieseasons/assets/images/lime.jpg b/veggieseasons/assets/images/lime.jpg new file mode 100644 index 0000000..a9878a5 Binary files /dev/null and b/veggieseasons/assets/images/lime.jpg differ diff --git a/veggieseasons/assets/images/mango.jpg b/veggieseasons/assets/images/mango.jpg new file mode 100644 index 0000000..27a82e5 Binary files /dev/null and b/veggieseasons/assets/images/mango.jpg differ diff --git a/veggieseasons/assets/images/mushroom.jpg b/veggieseasons/assets/images/mushroom.jpg new file mode 100644 index 0000000..a12fc69 Binary files /dev/null and b/veggieseasons/assets/images/mushroom.jpg differ diff --git a/veggieseasons/assets/images/nectarine.jpg b/veggieseasons/assets/images/nectarine.jpg new file mode 100644 index 0000000..24b55b7 Binary files /dev/null and b/veggieseasons/assets/images/nectarine.jpg differ diff --git a/veggieseasons/assets/images/orange_bell_pepper.jpg b/veggieseasons/assets/images/orange_bell_pepper.jpg new file mode 100644 index 0000000..2f78910 Binary files /dev/null and b/veggieseasons/assets/images/orange_bell_pepper.jpg differ diff --git a/veggieseasons/assets/images/persimmon.jpg b/veggieseasons/assets/images/persimmon.jpg new file mode 100644 index 0000000..c0e5d07 Binary files /dev/null and b/veggieseasons/assets/images/persimmon.jpg differ diff --git a/veggieseasons/assets/images/plum.jpg b/veggieseasons/assets/images/plum.jpg new file mode 100644 index 0000000..743c7a4 Binary files /dev/null and b/veggieseasons/assets/images/plum.jpg differ diff --git a/veggieseasons/assets/images/potato.jpg b/veggieseasons/assets/images/potato.jpg new file mode 100644 index 0000000..0f09e21 Binary files /dev/null and b/veggieseasons/assets/images/potato.jpg differ diff --git a/veggieseasons/assets/images/radicchio.jpg b/veggieseasons/assets/images/radicchio.jpg new file mode 100644 index 0000000..acd8f66 Binary files /dev/null and b/veggieseasons/assets/images/radicchio.jpg differ diff --git a/veggieseasons/assets/images/radish.jpg b/veggieseasons/assets/images/radish.jpg new file mode 100644 index 0000000..0dcbfb7 Binary files /dev/null and b/veggieseasons/assets/images/radish.jpg differ diff --git a/veggieseasons/assets/images/squash.jpg b/veggieseasons/assets/images/squash.jpg new file mode 100644 index 0000000..d20b745 Binary files /dev/null and b/veggieseasons/assets/images/squash.jpg differ diff --git a/veggieseasons/assets/images/strawberry.jpg b/veggieseasons/assets/images/strawberry.jpg new file mode 100644 index 0000000..feecd8a Binary files /dev/null and b/veggieseasons/assets/images/strawberry.jpg differ diff --git a/veggieseasons/assets/images/tangelo.jpg b/veggieseasons/assets/images/tangelo.jpg new file mode 100644 index 0000000..83c0a03 Binary files /dev/null and b/veggieseasons/assets/images/tangelo.jpg differ diff --git a/veggieseasons/assets/images/tomato.jpg b/veggieseasons/assets/images/tomato.jpg new file mode 100644 index 0000000..ab36947 Binary files /dev/null and b/veggieseasons/assets/images/tomato.jpg differ diff --git a/veggieseasons/assets/images/watermelon.jpg b/veggieseasons/assets/images/watermelon.jpg new file mode 100644 index 0000000..43880ba Binary files /dev/null and b/veggieseasons/assets/images/watermelon.jpg differ diff --git a/veggieseasons/ios/.gitignore b/veggieseasons/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/veggieseasons/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/veggieseasons/ios/Flutter/AppFrameworkInfo.plist b/veggieseasons/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..7c56964 --- /dev/null +++ b/veggieseasons/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/veggieseasons/ios/Flutter/Debug.xcconfig b/veggieseasons/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..ec97fc6 --- /dev/null +++ b/veggieseasons/ios/Flutter/Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "Generated.xcconfig" diff --git a/veggieseasons/ios/Flutter/Release.xcconfig b/veggieseasons/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..c4855bf --- /dev/null +++ b/veggieseasons/ios/Flutter/Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "Generated.xcconfig" diff --git a/veggieseasons/ios/Podfile b/veggieseasons/ios/Podfile new file mode 100644 index 0000000..d97f17e --- /dev/null +++ b/veggieseasons/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/veggieseasons/ios/Runner.xcodeproj/project.pbxproj b/veggieseasons/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..ab82aea --- /dev/null +++ b/veggieseasons/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,731 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 63DF5AF6EA7E5752FD193C17 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38D833D84C3CBFFBC2A61387 /* Pods_Runner.framework */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + BDDC9E5BD53006E983AC444C /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C7D1011F5450B20EBA2923B /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 1D00FE80EC6A4B68C8E227F8 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 2E0D48114CA3C6D9CCFFEF16 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 38D833D84C3CBFFBC2A61387 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 5C5AC2EFB5606C655AB6C34A /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 5C7D1011F5450B20EBA2923B /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 67C3CA414545302E36760BB5 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 971FE7CB47EC26D3DD304A6B /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 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 = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + FA6AACB3CDFE5B8D169FDAD3 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 63DF5AF6EA7E5752FD193C17 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + C3870E06F7C4E0C4CA0F4C1C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BDDC9E5BD53006E983AC444C /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1AC2876AB73DE877F0C0B83B /* Pods */ = { + isa = PBXGroup; + children = ( + 971FE7CB47EC26D3DD304A6B /* Pods-Runner.debug.xcconfig */, + 67C3CA414545302E36760BB5 /* Pods-Runner.release.xcconfig */, + 1D00FE80EC6A4B68C8E227F8 /* Pods-Runner.profile.xcconfig */, + 2E0D48114CA3C6D9CCFFEF16 /* Pods-RunnerTests.debug.xcconfig */, + FA6AACB3CDFE5B8D169FDAD3 /* Pods-RunnerTests.release.xcconfig */, + 5C5AC2EFB5606C655AB6C34A /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 4968362A1680EFDF9222A5B5 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 38D833D84C3CBFFBC2A61387 /* Pods_Runner.framework */, + 5C7D1011F5450B20EBA2923B /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + 1AC2876AB73DE877F0C0B83B /* Pods */, + 4968362A1680EFDF9222A5B5 /* Frameworks */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + EEF989F59E37C6946EC40F1B /* [CP] Check Pods Manifest.lock */, + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + C3870E06F7C4E0C4CA0F4C1C /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 25194613EC4035A63337D2AA /* [CP] Check Pods Manifest.lock */, + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 1F3480CB2DDBB3AE2233D2E2 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 1F3480CB2DDBB3AE2233D2E2 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 25194613EC4035A63337D2AA /* [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; + }; + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + EEF989F59E37C6946EC40F1B /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = TC87DMJLQP; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.veggieseasons; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2E0D48114CA3C6D9CCFFEF16 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.veggieseasons.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = FA6AACB3CDFE5B8D169FDAD3 /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.veggieseasons.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 5C5AC2EFB5606C655AB6C34A /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.veggieseasons.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = TC87DMJLQP; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.veggieseasons; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = TC87DMJLQP; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.veggieseasons; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/veggieseasons/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/veggieseasons/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/veggieseasons/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/veggieseasons/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/veggieseasons/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/veggieseasons/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/veggieseasons/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/veggieseasons/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/veggieseasons/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/veggieseasons/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/veggieseasons/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..8e3ca5d --- /dev/null +++ b/veggieseasons/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/veggieseasons/ios/Runner.xcworkspace/contents.xcworkspacedata b/veggieseasons/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/veggieseasons/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/veggieseasons/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/veggieseasons/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/veggieseasons/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/veggieseasons/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/veggieseasons/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/veggieseasons/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/veggieseasons/ios/Runner/AppDelegate.swift b/veggieseasons/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..6266644 --- /dev/null +++ b/veggieseasons/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..55d5fc9 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..e3b431b Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..1861206 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..e846575 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..b12478c Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..bc7d6b4 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..a21c2b5 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..1861206 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..e494c44 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..81c4020 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..81c4020 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..27b09c6 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..15cc145 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..0374611 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..beef9b9 Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/veggieseasons/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/veggieseasons/ios/Runner/Base.lproj/LaunchScreen.storyboard b/veggieseasons/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/veggieseasons/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/veggieseasons/ios/Runner/Base.lproj/Main.storyboard b/veggieseasons/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/veggieseasons/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/veggieseasons/ios/Runner/Info.plist b/veggieseasons/ios/Runner/Info.plist new file mode 100644 index 0000000..c985223 --- /dev/null +++ b/veggieseasons/ios/Runner/Info.plist @@ -0,0 +1,48 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Veggie Seasons + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + veggieseasons + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/veggieseasons/ios/Runner/Runner-Bridging-Header.h b/veggieseasons/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/veggieseasons/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/veggieseasons/ios/RunnerTests/RunnerTests.swift b/veggieseasons/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/veggieseasons/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/veggieseasons/lib/data/app_state.dart b/veggieseasons/lib/data/app_state.dart new file mode 100644 index 0000000..4c4edd2 --- /dev/null +++ b/veggieseasons/lib/data/app_state.dart @@ -0,0 +1,86 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'local_veggie_provider.dart'; +import 'veggie.dart'; + +class AppState extends ChangeNotifier { + final List _veggies; + + AppState() : _veggies = LocalVeggieProvider.veggies; + + List get allVeggies => List.from(_veggies); + + List get availableVeggies { + var currentSeason = _getSeasonForDate(DateTime.now()); + return _veggies + .where((v) => v.seasons.contains(currentSeason)) + .toList(); + } + + List get favoriteVeggies => + _veggies.where((v) => v.isFavorite).toList(); + + List get unavailableVeggies { + var currentSeason = _getSeasonForDate(DateTime.now()); + return _veggies + .where((v) => !v.seasons.contains(currentSeason)) + .toList(); + } + + Veggie getVeggie(int? id) => _veggies.singleWhere((v) => v.id == id); + + List searchVeggies(String? terms) => _veggies + .where((v) => v.name.toLowerCase().contains(terms!.toLowerCase())) + .toList(); + + void setFavorite(int? id, bool isFavorite) { + var veggie = getVeggie(id); + veggie.isFavorite = isFavorite; + notifyListeners(); + } + + /// Used in tests to set the season independent of the current date. + static Season? debugCurrentSeason; + + static Season? _getSeasonForDate(DateTime date) { + if (debugCurrentSeason != null) { + return debugCurrentSeason; + } + + // Technically the start and end dates of seasons can vary by a day or so, + // but this is close enough for produce. + switch (date.month) { + case 1: + return Season.winter; + case 2: + return Season.winter; + case 3: + return date.day < 21 ? Season.winter : Season.spring; + case 4: + return Season.spring; + case 5: + return Season.spring; + case 6: + return date.day < 21 ? Season.spring : Season.summer; + case 7: + return Season.summer; + case 8: + return Season.summer; + case 9: + return date.day < 22 ? Season.autumn : Season.winter; + case 10: + return Season.autumn; + case 11: + return Season.autumn; + case 12: + return date.day < 22 ? Season.autumn : Season.winter; + default: + throw ArgumentError( + 'Can\'t return a season for month #${date.month}.', + ); + } + } +} diff --git a/veggieseasons/lib/data/local_veggie_provider.dart b/veggieseasons/lib/data/local_veggie_provider.dart new file mode 100644 index 0000000..9b387bc --- /dev/null +++ b/veggieseasons/lib/data/local_veggie_provider.dart @@ -0,0 +1,1071 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'veggie.dart'; + +class LocalVeggieProvider { + static List veggies = [ + Veggie( + id: 1, + name: 'Apples', + imageAssetPath: 'assets/images/apple.jpg', + category: VeggieCategory.fruit, + shortDescription: + 'Green or red, they\'re generally round and tasty.', + accentColor: const Color(0x40de8c66), + seasons: [ + Season.winter, + Season.spring, + Season.summer, + Season.autumn, + ], + vitaminAPercentage: 2, + vitaminCPercentage: 8, + servingSize: 'One large apple', + caloriesPerServing: 130, + trivia: const [ + Trivia( + 'A peck of apples (that\'s a real unit of mesaurement!) weighs approximately how many pounds?', + ['10 pounds', '20 pounds', '30 pounds'], + 0, + ), + Trivia('Which of these is an actual variety of apples?', [ + 'Dancing Turkey', + 'Winter Banana', + 'Red Sloth', + ], 1), + Trivia( + 'In Greek mythology, Paris gives a golden apple marked "To the Fairest" to a goddess. Which one?', + ['Hera', 'Athena', 'Aphrodite'], + 2, + ), + Trivia('Apples in the supermarket can be up to how old?', [ + '1 week', + '1 month', + '1 year', + ], 2), + Trivia( + 'How long does it take a typical apple tree to produce its first fruit?', + ['One to two years', 'Four or five years', 'Eight to ten years'], + 1, + ), + Trivia( + 'Archaeological evidence of humans eating apples dates back how far?', + ['500 C.E.', '2000 B.C.E.', '6500 B.C.E.'], + 2, + ), + Trivia('What are the seed pockets inside an apple called?', [ + 'Tarsals', + 'Carpels', + 'Sacs', + ], 1), + ], + ), + Veggie( + id: 2, + name: 'Artichokes', + imageAssetPath: 'assets/images/artichoke.jpg', + category: VeggieCategory.flower, + shortDescription: 'The armadillo of vegetables.', + accentColor: const Color(0x408ea26d), + seasons: [Season.spring, Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 25, + servingSize: '1 medium artichoke', + caloriesPerServing: 60, + trivia: const [ + Trivia('Artichokes are which part of the plant?', [ + 'Flower bud', + 'Root', + 'Seed', + ], 0), + Trivia( + '"Jerusalem artichoke" is another term for which vegetable?', + [ + 'Potato', + 'Cabbage', + 'Sunchoke', + ], + 2, + ), + Trivia( + 'Which city claims to be The Artichoke Capital of the World?', + [ + 'Castroville, California', + 'Galveston, Texas', + 'London, England', + ], + 0, + ), + Trivia('Artichokes are technically which type of plant?', [ + 'Thistle', + 'Azalea', + 'Tulip', + ], 0), + ], + ), + Veggie( + id: 3, + name: 'Asparagus', + imageAssetPath: 'assets/images/asparagus.jpg', + category: VeggieCategory.fern, + shortDescription: + 'It\'s been used a food and medicine for millenia.', + accentColor: const Color(0x408cb437), + seasons: [Season.spring], + vitaminAPercentage: 10, + vitaminCPercentage: 15, + servingSize: '5 spears', + caloriesPerServing: 20, + trivia: const [ + Trivia( + 'The nodules at the tip of an asparagus spear are actually which part of the plant?', + ['Seeds', 'Leaves', 'Potective scales'], + 1, + ), + Trivia('How is white asparagus made?', [ + 'It\'s watered with milk', + 'It\'s a different species', + 'It\'s grown in the shade', + ], 2), + Trivia( + 'Asapragus spears have been observed growing how many inches in a single day?', + ['1', '3', '6'], + 2, + ), + Trivia('To which flower is asparagus related?', [ + 'Lily', + 'Rose', + 'Whole wheat', + ], 0), + ], + ), + Veggie( + id: 4, + name: 'Avocado', + imageAssetPath: 'assets/images/avocado.jpg', + category: VeggieCategory.stealthFruit, + shortDescription: + 'One of the oiliest, richest fruits money can buy.', + accentColor: const Color(0x40b0ba59), + seasons: [Season.winter, Season.spring, Season.summer], + vitaminAPercentage: 0, + vitaminCPercentage: 4, + servingSize: '1/5 medium avocado', + caloriesPerServing: 50, + trivia: const [ + Trivia('What\'s the most popular variety of avocado?', [ + 'Stevenson', + 'Hass', + 'Juicy Lucy', + ], 1), + Trivia( + 'The word avocado derives from "ahuacatl," found in which civilization?', + ['Aztec', 'Incan', 'Sumerian'], + 0, + ), + Trivia('What percentage of an avocado is nutritional fat?', [ + '10', + '25', + '50', + ], 1), + Trivia( + 'The first evidence of avocado consumption by humans dates back to what year?', + ['2,000 B.C.', '6,000 B.C.', '10,000 B.C.'], + 2, + ), + ], + ), + Veggie( + id: 5, + name: 'Blackberries', + imageAssetPath: 'assets/images/blackberry.jpg', + category: VeggieCategory.berry, + shortDescription: + 'Find them on backroads and fences in the Northwest.', + accentColor: const Color(0x409d5adb), + seasons: [Season.summer], + vitaminAPercentage: 6, + vitaminCPercentage: 4, + servingSize: '1 cup', + caloriesPerServing: 62, + trivia: const [ + Trivia('What color are unripe blackberries?', [ + 'Red', + 'White', + 'Brown', + ], 0), + Trivia( + 'The blackberry is the official fruit of which American state?', + ['Washington', 'Colorado', 'Alabama'], + 2, + ), + Trivia('How many varieties of blackberries are known to exist?', [ + '500', + '1000', + '2000', + ], 2), + ], + ), + Veggie( + id: 6, + name: 'Cantaloupe', + imageAssetPath: 'assets/images/cantaloupe.jpg', + category: VeggieCategory.melon, + shortDescription: 'A fruit so tasty there\'s a utensil just for it.', + accentColor: const Color(0x40f6bd56), + seasons: [Season.summer], + vitaminAPercentage: 120, + vitaminCPercentage: 80, + servingSize: '1/4 medium cantaloupe', + caloriesPerServing: 50, + trivia: const [ + Trivia('Which of these is another name for cantaloupe?', [ + 'Muskmelon', + 'Crenshaw melon', + 'Rindfruit', + ], 0), + Trivia('The word "cantaloupe" is a reference to what?', [ + 'The Latin word for a ring of seeds', + 'The gardens of a castle in Italy', + 'An aphid species that feeds on cantaloupe leaves', + ], 1), + Trivia('Cantaloupes grow on what kind of plant?', [ + 'Tree', + 'Shrub', + 'Vine', + ], 2), + Trivia( + 'The most expensive melons in Japan can sell for up to how much?', + ['\$100', '\$1,000', '\$10,000'], + 2, + ), + ], + ), + Veggie( + id: 7, + name: 'Cauliflower', + imageAssetPath: 'assets/images/cauliflower.jpg', + category: VeggieCategory.cruciferous, + shortDescription: 'Looks like white broccoli and explodes when cut.', + accentColor: const Color(0x40c891a8), + seasons: [Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 100, + servingSize: '1/6 medium head', + caloriesPerServing: 25, + trivia: const [ + Trivia( + 'The quote "Cauliflower is nothing but cabbage with a college education" is attributed to whom?', + ['Cesar Romero', 'Mark Twain', 'Lucille Ball'], + 1, + ), + Trivia( + 'The edible head of a cauliflower plant is sometimes called what?', + ['The curd', 'The cow', 'The cudgel'], + 0, + ), + Trivia( + 'Cauliflower is related closest to which of these other plants?', + ['Mustard greens', 'Apples', 'Potatoes'], + 0, + ), + Trivia( + 'Cauliflower\'s green spiral-shaped cousin is known as what?', + [ + 'Romesco', + 'Brittany cabbage', + 'Muscle sprouts', + ], + 0, + ), + Trivia('Green cauliflower is sometimes called what?', [ + 'Broccoflower', + 'Avocadoflower', + 'Gross', + ], 0), + ], + ), + Veggie( + id: 8, + name: 'Endive', + imageAssetPath: 'assets/images/endive.jpg', + category: VeggieCategory.leafy, + shortDescription: 'It\'s basically the veal of lettuce.', + accentColor: const Color(0x40c5be53), + seasons: [Season.winter, Season.spring, Season.autumn], + vitaminAPercentage: 10, + vitaminCPercentage: 2, + servingSize: '1/2 cup, chopped', + caloriesPerServing: 4, + trivia: const [ + Trivia('What\'s another name for Belgian endive?', [ + 'Radicchio', + 'St. Paul\'s lettuce', + 'Witloof chicory', + ], 2), + Trivia('How does endive propagate itself?', [ + 'By seed', + 'By rhizome', + 'By packing up and moving to Des Moines', + ], 0), + Trivia( + 'Some farmers cover their endive with shade to reduce what?', + [ + 'Size', + 'Toughness', + 'Bitterness', + ], + 2, + ), + ], + ), + Veggie( + id: 9, + name: 'Figs', + imageAssetPath: 'assets/images/fig.jpg', + category: VeggieCategory.fruit, + shortDescription: 'Delicious when sliced and wrapped in prosciutto.', + accentColor: const Color(0x40aa6d7c), + seasons: [Season.summer, Season.autumn], + vitaminAPercentage: 2, + vitaminCPercentage: 2, + servingSize: '1 large fig', + caloriesPerServing: 50, + trivia: const [ + Trivia('Which of these isn\'t a variety of figs?', [ + 'Brown Turkey', + 'Green Ischia', + 'Red Racer', + ], 2), + Trivia('A fig\'s natural sugar content is around what?', [ + '25%', + '50%', + '75%', + ], 1), + Trivia('How much sun should be used to ripen figs?', [ + 'Shade', + 'Partial shade', + 'Full sun', + ], 2), + ], + ), + Veggie( + id: 10, + name: 'Grapes', + imageAssetPath: 'assets/images/grape.jpg', + category: VeggieCategory.berry, + shortDescription: 'Couldn\'t have wine without them.', + accentColor: const Color(0x40ac708a), + seasons: [Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 2, + servingSize: '3/4 cup', + caloriesPerServing: 90, + trivia: const [ + Trivia('How long ago were grapes introduced to the Americas?', [ + '100 years', + '200 years', + '300 years', + ], 2), + Trivia('Which of these is not an actual color of grapes?', [ + 'Pink', + 'Yellow', + 'Brown', + ], 2), + Trivia( + 'About how many millions of tons of grapes are produced each year?', + ['40', '80', '120'], + 1, + ), + Trivia('There are about how many known varieties of grapes?', [ + '2,000', + '4,000', + '8,000', + ], 2), + ], + ), + Veggie( + id: 11, + name: 'Green Pepper', + imageAssetPath: 'assets/images/green_bell_pepper.jpg', + category: VeggieCategory.stealthFruit, + shortDescription: 'Pleasantly bitter, like a sad movie.', + accentColor: const Color(0x408eb332), + seasons: [Season.summer], + vitaminAPercentage: 4, + vitaminCPercentage: 190, + servingSize: '1 medium pepper', + caloriesPerServing: 25, + trivia: const [ + Trivia('What\'s the Australian term for a bell pepper?', [ + 'Capsicum', + 'Ringer', + 'John Dobbins', + ], 0), + Trivia('How are green peppers produced?', [ + 'They\'re picked before ripening', + 'They\'re grown in the shade', + 'They\'re a distinct species', + ], 0), + Trivia( + 'How quickly can a green pepper grow from seed to harvest?', + [ + '10 weeks', + '20 weeks', + '30 weeks', + ], + 0, + ), + ], + ), + Veggie( + id: 12, + name: 'Habanero', + imageAssetPath: 'assets/images/habanero.jpg', + category: VeggieCategory.stealthFruit, + shortDescription: 'Delicious... in extremely small quantities.', + accentColor: const Color(0x40ff7a01), + seasons: [Season.summer, Season.autumn], + vitaminAPercentage: 9, + vitaminCPercentage: 100, + servingSize: '1 pepper', + caloriesPerServing: 20, + trivia: const [ + Trivia('How high can habaneros rate on the Scoville scale?', [ + '200,000 units', + '600,000 units', + '1,000,000 units', + ], 1), + Trivia( + 'Which of these is a pepper known to be hotter than the habanero?', + ['Serrano pepper', 'Hatch chile', 'Pepper X'], + 2, + ), + Trivia('Which of these isn\'t a variety of habaneros?', [ + 'White giant', + 'Condor\'s beak', + 'Saucy tyrant', + ], 2), + ], + ), + Veggie( + id: 13, + name: 'Kale', + imageAssetPath: 'assets/images/kale.jpg', + category: VeggieCategory.cruciferous, + shortDescription: + 'The meanest vegetable. Does not want to be eaten.', + accentColor: const Color(0x40a86bd8), + seasons: [Season.winter, Season.autumn], + vitaminAPercentage: 133, + vitaminCPercentage: 134, + servingSize: '1 cup, chopped', + caloriesPerServing: 33, + trivia: const [ + Trivia('Kale is sweeter when harvested after what?', [ + 'Sundown', + 'The first frost', + 'Reading it a sad story', + ], 1), + Trivia( + 'Which of these isn\'t a color in which Kale can be found?', + [ + 'Purple', + 'White', + 'Orange', + ], + 2, + ), + Trivia( + 'One serving of kale provides what percentage of a typical person\'s requirement for vitamin K?', + ['100%', '300%', '900%'], + 2, + ), + ], + ), + Veggie( + id: 14, + name: 'Kiwi', + imageAssetPath: 'assets/images/kiwi.jpg', + category: VeggieCategory.berry, + shortDescription: 'Also known as Chinese gooseberry.', + accentColor: const Color(0x40b47b37), + seasons: [Season.summer], + vitaminAPercentage: 2, + vitaminCPercentage: 240, + servingSize: '2 medium kiwis', + caloriesPerServing: 90, + trivia: const [ + Trivia('Europeans sometimes refer to kiwi as what?', [ + 'Chinese gooseberry', + 'Gem berries', + 'Bulbfruit', + ], 0), + Trivia('On what type of plant do kiwi grow?', [ + 'Tree', + 'Shrub', + 'Vine', + ], 2), + Trivia( + 'Compared to oranges, kiwi typically contain how much vitamin C?', + ['Half as much', 'About the same', 'Twice as much'], + 2, + ), + ], + ), + Veggie( + id: 15, + name: 'Lemons', + imageAssetPath: 'assets/images/lemon.jpg', + category: VeggieCategory.citrus, + shortDescription: 'Similar to limes, only yellow.', + accentColor: const Color(0x40e2a500), + seasons: [Season.winter], + vitaminAPercentage: 0, + vitaminCPercentage: 40, + servingSize: '1 medium lemon', + caloriesPerServing: 15, + trivia: const [ + Trivia( + 'A lemon tree can produce up to how many pounds of fruit each year?', + ['100', '300', '600'], + 2, + ), + Trivia('Which of these isn\'t a type of lemon?', [ + 'Acid', + 'Sarcastic', + 'Sweet', + ], 1), + Trivia('What percent of a typical lemon is composed of juice?', [ + '20%', + '40%', + '60%', + ], 0), + Trivia( + 'Which lemon variety is prized for its sweeter-than-averga flavor?', + ['Hookeye', 'Meyer', 'Minnesota Stomp'], + 1, + ), + ], + ), + Veggie( + id: 16, + name: 'Limes', + imageAssetPath: 'assets/images/lime.jpg', + category: VeggieCategory.citrus, + shortDescription: + 'Couldn\'t have ceviche and margaritas without them.', + accentColor: const Color(0x4089b733), + seasons: [Season.winter], + vitaminAPercentage: 0, + vitaminCPercentage: 35, + servingSize: '1 medium lime', + caloriesPerServing: 20, + trivia: const [ + Trivia('Which American state is famous for its Key Lime Pie?', [ + 'Pennsylvania', + 'Arizona', + 'Florida', + ], 2), + Trivia( + 'Dried limes are a particularly popular soup ingredient in which part of the world?', + ['Middle East', 'Africa', 'Australia'], + 0, + ), + Trivia( + 'Sailors once carried limes on their ships to help against which condition?', + ['Influenza', 'Scurvy', 'Boredom'], + 1, + ), + ], + ), + Veggie( + id: 17, + name: 'Mangos', + imageAssetPath: 'assets/images/mango.jpg', + category: VeggieCategory.tropical, + shortDescription: + 'A fun orange fruit popular with smoothie enthusiasts.', + accentColor: const Color(0x40fcc93c), + seasons: [Season.summer, Season.autumn], + vitaminAPercentage: 72, + vitaminCPercentage: 203, + servingSize: '1 fruit', + caloriesPerServing: 201, + trivia: const [ + Trivia( + 'In Mexico, mangos are frequently dusted with what spices before being eaten as a snack?', + [ + 'Black pepper and sugar', + 'Chile pepper and lime juice', + 'Cumin and salt', + ], + 1, + ), + Trivia('To which nut is the mango closely related?', [ + 'Cashew', + 'Peanut', + 'Walnut', + ], 0), + Trivia('In which country did mangos originate?', [ + 'India', + 'Madagascar', + 'Belize', + ], 0), + ], + ), + Veggie( + id: 18, + name: 'Mushrooms', + imageAssetPath: 'assets/images/mushroom.jpg', + category: VeggieCategory.fungus, + shortDescription: 'They\'re not truffles, but they\'re still tasty.', + accentColor: const Color(0x40ba754b), + seasons: [Season.spring, Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 2, + servingSize: '5 medium \'shrooms', + caloriesPerServing: 20, + trivia: const [ + Trivia('Someone who loves eating mushrooms is called what?', [ + 'A mycophagist', + 'A philologist', + 'A phlebotomist', + ], 0), + Trivia( + 'Morel mushrooms are particulary prized by cooks of which style of cuisine?', + ['French', 'Italian', 'Japanese'], + 0, + ), + Trivia( + 'The largest living organism ever identified is what type of mushroom?', + ['Shiitake mushroom', 'Honey mushroom', 'Glory mushroom'], + 1, + ), + Trivia( + 'One mushroom cousin is the truffle. Which color truffle is the most prized?', + ['White', 'Black', 'Brown'], + 0, + ), + ], + ), + Veggie( + id: 19, + name: 'Nectarines', + imageAssetPath: 'assets/images/nectarine.jpg', + category: VeggieCategory.stoneFruit, + shortDescription: 'Tiny, bald peaches.', + accentColor: const Color(0x40e45b3b), + seasons: [Season.summer], + vitaminAPercentage: 8, + vitaminCPercentage: 15, + servingSize: '1 medium nectarine', + caloriesPerServing: 60, + trivia: const [ + Trivia( + 'Nectarines are technically a variety of which other fruit?', + [ + 'Peach', + 'Plum', + 'Cherry', + ], + 0, + ), + Trivia('Nectarines are sometimes called what?', [ + 'Neckless geese', + 'Giant grapes', + 'Shaved peaches', + ], 2), + Trivia( + 'Nectarines are thought to have originated in which country?', + [ + 'China', + 'Italy', + 'Ethiopia', + ], + 0, + ), + ], + ), + Veggie( + id: 20, + name: 'Persimmons', + imageAssetPath: 'assets/images/persimmon.jpg', + category: VeggieCategory.fruit, + shortDescription: + 'It\'s like a plum and an apple had a baby together.', + accentColor: const Color(0x40979852), + seasons: [Season.winter, Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 27, + servingSize: '1 fruit', + caloriesPerServing: 32, + trivia: const [ + Trivia('What\'s the most commonly grown variety of persimmon?', [ + 'Sugar', + 'Yellowbird', + 'Kaki', + ], 2), + Trivia('The word "persimmon" is derived from which language?', [ + 'Latin', + 'Indo-European', + 'Powhatan', + ], 2), + Trivia('Which of these is an alternate variety of persimmon?', [ + 'Black Sapote', + 'Green Troubador', + 'Red Captain', + ], 0), + ], + ), + Veggie( + id: 21, + name: 'Plums', + imageAssetPath: 'assets/images/plum.jpg', + category: VeggieCategory.stoneFruit, + shortDescription: 'Popular in fruit salads and children\'s tales.', + accentColor: const Color(0x40e48b47), + seasons: [Season.summer], + vitaminAPercentage: 8, + vitaminCPercentage: 10, + servingSize: '2 medium plums', + caloriesPerServing: 70, + trivia: const [ + Trivia('Plums should be handled with care because...?', [ + 'They\'re particularly sticky', + 'They bruise easily', + 'It\'s easy to hurt their feelings', + ], 1), + Trivia('A dried plum is known as what?', [ + 'A prune', + 'An apricot', + 'A raisin', + ], 0), + Trivia('A sugar plum typically contains how much plum juice?', [ + '0%', + '25%', + '50%', + ], 0), + ], + ), + Veggie( + id: 22, + name: 'Potatoes', + imageAssetPath: 'assets/images/potato.jpg', + category: VeggieCategory.tuber, + shortDescription: 'King of starches and giver of french fries.', + accentColor: const Color(0x40c65c63), + seasons: [Season.winter, Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 45, + servingSize: '1 medium spud', + caloriesPerServing: 110, + trivia: const [ + Trivia( + 'Which country consumes the most fried potatoes per capita?', + [ + 'United States', + 'Belgium', + 'Ireland', + ], + 1, + ), + Trivia( + 'Who is credited with introducing French Fries to the United States?', + ['Thomas Jefferson', 'Betsy Ross', 'Alexander Hamilton'], + 0, + ), + Trivia( + 'The world record for loongest curly fry stands at how many inches?', + ['38', '58', '78'], + 0, + ), + ], + ), + Veggie( + id: 23, + name: 'Radicchio', + imageAssetPath: 'assets/images/radicchio.jpg', + category: VeggieCategory.leafy, + shortDescription: + 'It\'s that bitter taste in the salad you\'re eating.', + accentColor: const Color(0x40d75875), + seasons: [Season.spring, Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 10, + servingSize: '2 cups shredded', + caloriesPerServing: 20, + trivia: const [ + Trivia( + 'Radicchio is a particuarly good source of which mineral?', + [ + 'Manganese', + 'Mercury', + 'Molybdenum', + ], + 0, + ), + Trivia('Radicchio should be stored at what temperature?', [ + 'Room temperature', + 'Refrigerator temperature', + 'Freezer temperature', + ], 1), + Trivia( + 'What happens to the taste of radicchio once the plant flowers?', + [ + 'It becomes bitter', + 'It becomes sweeter', + 'Nothing. It just looks nicer!', + ], + 0, + ), + ], + ), + Veggie( + id: 24, + name: 'Radishes', + imageAssetPath: 'assets/images/radish.jpg', + category: VeggieCategory.root, + shortDescription: + 'Try roasting them in addition to slicing them up raw.', + accentColor: const Color(0x40819e4e), + seasons: [Season.spring, Season.autumn], + vitaminAPercentage: 0, + vitaminCPercentage: 30, + servingSize: '7 radishes', + caloriesPerServing: 10, + trivia: const [ + Trivia( + 'Which ancient civilization is known to have used radish oil?', + [ + 'Egyptian', + 'Sumerian', + 'Incan', + ], + 0, + ), + Trivia( + 'What\'s the name of the radish commonly used in Japanese cuisine?', + ['Daisuki', 'Daijin', 'Daikon'], + 2, + ), + Trivia( + 'The annual "Night of the Radishes" festival takes place just before Christmas Eve in which country?', + ['Mexico', 'France', 'South Korea'], + 0, + ), + ], + ), + Veggie( + id: 25, + name: 'Squash', + imageAssetPath: 'assets/images/squash.jpg', + category: VeggieCategory.gourd, + shortDescription: + 'Just slather them in butter and pop \'em in the oven.', + accentColor: const Color(0x40dbb721), + seasons: [Season.winter, Season.autumn], + vitaminAPercentage: 297, + vitaminCPercentage: 48, + servingSize: '1 cup diced butternut', + caloriesPerServing: 63, + trivia: const [ + Trivia('Which of these is not a type of squash?', [ + 'Zucchini', + 'Spaghetti', + 'Martini', + ], 2), + Trivia('Gourds like squash are also handy as what?', [ + 'Containers', + 'Furniture', + 'Musical instruments', + ], 0), + Trivia( + 'Which country is the world\'s largest importer of squashes?', + [ + 'China', + 'United States', + 'Russia', + ], + 1, + ), + ], + ), + Veggie( + id: 26, + name: 'Strawberries', + imageAssetPath: 'assets/images/strawberry.jpg', + category: VeggieCategory.berry, + shortDescription: + 'A delicious fruit that keeps its seeds on the outside.', + accentColor: const Color(0x40f06a44), + seasons: [Season.spring, Season.summer], + vitaminAPercentage: 0, + vitaminCPercentage: 160, + servingSize: '8 medium strawberries', + caloriesPerServing: 50, + trivia: const [ + Trivia('How many seeds are in the average strawberry?', [ + '50', + '100', + '200', + ], 2), + Trivia( + 'Strawberries are closely related to which type of flower?', + [ + 'The rose', + 'The daisy', + 'The tulip', + ], + 0, + ), + Trivia('Strawberries are unique among fruit for what reason?', [ + 'Their seeds are on the outside', + 'Their flowers are striped', + 'Their plants have a taproot', + ], 0), + ], + ), + Veggie( + id: 27, + name: 'Tangelo', + imageAssetPath: 'assets/images/tangelo.jpg', + category: VeggieCategory.citrus, + shortDescription: + 'No one\'s sure what they are or where they came from.', + accentColor: const Color(0x40f88c06), + seasons: [Season.winter, Season.autumn], + vitaminAPercentage: 6, + vitaminCPercentage: 181, + servingSize: '1 medium tangelo', + caloriesPerServing: 60, + trivia: const [ + Trivia( + 'The tangelo is thought to be a cross between oranges and which other fruit?', + ['Peach', 'Plum', 'Pummelo'], + 2, + ), + Trivia('Which of these is a variety of tangelo?', [ + 'Orlando', + 'Bluebonnet', + 'Creakey Pete', + ], 0), + Trivia('A typical tangelo is about what size?', [ + 'Golf ball', + 'Baseball', + 'Bowling ball', + ], 1), + ], + ), + Veggie( + id: 28, + name: 'Tomatoes', + imageAssetPath: 'assets/images/tomato.jpg', + category: VeggieCategory.stealthFruit, + shortDescription: 'A new world food with old world tradition.', + accentColor: const Color(0x40ea3628), + seasons: [Season.summer], + vitaminAPercentage: 20, + vitaminCPercentage: 40, + servingSize: '1 medium tomato', + caloriesPerServing: 25, + trivia: const [ + Trivia( + 'French speakers sometimes refer to tomatoes with which name?', + [ + 'Piet de terre', + 'Mille-feuille', + 'Pomme d\'amour', + ], + 2, + ), + Trivia( + 'The largest tomato known to have been grown weighed in at how many pounds?', + ['8', '10', '12'], + 0, + ), + Trivia( + 'Which country is the world\'s largest producer of tomatoes?', + [ + 'China', + 'Italy', + 'Ecuador', + ], + 0, + ), + ], + ), + Veggie( + id: 29, + name: 'Watermelon', + imageAssetPath: 'assets/images/watermelon.jpg', + category: VeggieCategory.melon, + shortDescription: 'Everyone\'s favorite closing act at the picnic.', + accentColor: const Color(0x40fa8c75), + seasons: [Season.summer], + vitaminAPercentage: 30, + vitaminCPercentage: 25, + servingSize: '2 cups diced', + caloriesPerServing: 80, + trivia: const [ + Trivia('How much of a watermelon is water?', [ + '50%', + '75%', + '90%', + ], 2), + Trivia( + 'Which nation is famous for growing watermelons in unsual shapes like cubes and hearts?', + ['Armenia', 'Japan', 'Saudi Arabia'], + 1, + ), + Trivia( + 'Which U.S. state declared the watermelon to be its state vegetable (that\'s right, vegetable)?', + ['Kansas', 'Iowa', 'Oklahoma'], + 2, + ), + Trivia( + 'Early explorers to the Americas used watermelons as which piece of equipment?', + ['Stools', 'Pillows', 'Canteens'], + 2, + ), + ], + ), + Veggie( + id: 30, + name: 'Orange Bell Pepper', + imageAssetPath: 'assets/images/orange_bell_pepper.jpg', + category: VeggieCategory.stealthFruit, + shortDescription: 'Like green pepper, but nicer.', + accentColor: const Color(0x40fd8e00), + seasons: [Season.summer], + vitaminAPercentage: 4, + vitaminCPercentage: 190, + servingSize: '1 medium pepper', + caloriesPerServing: 25, + trivia: const [ + Trivia( + 'Which compound (not found in bell peppers) is responsible for many peppers\' spicy taste?', + ['Alum', 'Capsacin', 'Calcium'], + 1, + ), + Trivia( + 'In comparison to green peppers, how expensive are their orange cousins?', + ['Cheaper', 'About the same', 'More expensive'], + 2, + ), + Trivia( + 'Who is generally credited with giving bell peppers their peppery name?', + [ + 'Christopher Columbus', + 'Benjamin Franklin', + 'Eleanor Roosevelt', + ], + 0, + ), + ], + ), + ]; +} diff --git a/veggieseasons/lib/data/preferences.dart b/veggieseasons/lib/data/preferences.dart new file mode 100644 index 0000000..07f16ca --- /dev/null +++ b/veggieseasons/lib/data/preferences.dart @@ -0,0 +1,90 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'veggie.dart'; + +/// A model class that mirrors the options in [SettingsScreen] and stores data +/// in shared preferences. +class Preferences extends ChangeNotifier { + // Keys to use with shared preferences. + static const _caloriesKey = 'calories'; + static const _preferredCategoriesKey = 'preferredCategories'; + + // Indicates whether a call to [_loadFromSharedPrefs] is in progress; + Future? _loading; + + int _desiredCalories = 2000; + + final Set _preferredCategories = {}; + + Future get desiredCalories async { + await _loading; + return _desiredCalories; + } + + Future> get preferredCategories async { + await _loading; + return Set.from(_preferredCategories); + } + + Future addPreferredCategory(VeggieCategory category) async { + _preferredCategories.add(category); + await _saveToSharedPrefs(); + notifyListeners(); + } + + Future removePreferredCategory(VeggieCategory category) async { + _preferredCategories.remove(category); + await _saveToSharedPrefs(); + notifyListeners(); + } + + Future setDesiredCalories(int calories) async { + _desiredCalories = calories; + await _saveToSharedPrefs(); + notifyListeners(); + } + + Future restoreDefaults() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.clear(); + load(); + } + + void load() { + _loading = _loadFromSharedPrefs(); + } + + Future _saveToSharedPrefs() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setInt(_caloriesKey, _desiredCalories); + + // Store preferred categories as a comma-separated string containing their + // indices. + await prefs.setString( + _preferredCategoriesKey, + _preferredCategories.map((c) => c.index.toString()).join(','), + ); + } + + Future _loadFromSharedPrefs() async { + final prefs = await SharedPreferences.getInstance(); + _desiredCalories = prefs.getInt(_caloriesKey) ?? 2000; + _preferredCategories.clear(); + final names = prefs.getString(_preferredCategoriesKey); + + if (names != null && names.isNotEmpty) { + for (final name in names.split(',')) { + final index = int.tryParse(name) ?? -1; + _preferredCategories.add(VeggieCategory.values[index]); + } + } + + notifyListeners(); + } +} diff --git a/veggieseasons/lib/data/veggie.dart b/veggieseasons/lib/data/veggie.dart new file mode 100644 index 0000000..feeb83b --- /dev/null +++ b/veggieseasons/lib/data/veggie.dart @@ -0,0 +1,125 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; + +enum VeggieCategory { + allium, + berry, + citrus, + cruciferous, + fern, + flower, + fruit, + fungus, + gourd, + leafy, + legume, + melon, + root, + stealthFruit, + stoneFruit, + tropical, + tuber, + vegetable, +} + +enum Season { winter, spring, summer, autumn } + +class Trivia { + final String question; + final List answers; + final int correctAnswerIndex; + + const Trivia(this.question, this.answers, this.correctAnswerIndex); +} + +const Map veggieCategoryNames = { + VeggieCategory.allium: 'Allium', + VeggieCategory.berry: 'Berry', + VeggieCategory.citrus: 'Citrus', + VeggieCategory.cruciferous: 'Cruciferous', + VeggieCategory.fern: 'Technically a fern', + VeggieCategory.flower: 'Flower', + VeggieCategory.fruit: 'Fruit', + VeggieCategory.fungus: 'Fungus', + VeggieCategory.gourd: 'Gourd', + VeggieCategory.leafy: 'Leafy', + VeggieCategory.legume: 'Legume', + VeggieCategory.melon: 'Melon', + VeggieCategory.root: 'Root vegetable', + VeggieCategory.stealthFruit: 'Stealth fruit', + VeggieCategory.stoneFruit: 'Stone fruit', + VeggieCategory.tropical: 'Tropical', + VeggieCategory.tuber: 'Tuber', + VeggieCategory.vegetable: 'Vegetable', +}; + +const Map seasonNames = { + Season.winter: 'Winter', + Season.spring: 'Spring', + Season.summer: 'Summer', + Season.autumn: 'Autumn', +}; + +class Veggie { + Veggie({ + required this.id, + required this.name, + required this.imageAssetPath, + required this.category, + required this.shortDescription, + required this.accentColor, + required this.seasons, + required this.vitaminAPercentage, + required this.vitaminCPercentage, + required this.servingSize, + required this.caloriesPerServing, + required this.trivia, + this.isFavorite = false, + }); + + final int id; + + final String name; + + /// Each veggie has an associated image asset that's used as a background + /// image and icon. + final String imageAssetPath; + + final VeggieCategory category; + + /// A short, snappy line. + final String shortDescription; + + /// A color value to use when constructing UI elements to match the image + /// found at [imageAssetPath]. + final Color accentColor; + + /// Seasons during which a veggie is harvested. + final List seasons; + + /// Percentage of the FDA's recommended daily value of vitamin A for someone + /// with a 2,000 calorie diet. + final int vitaminAPercentage; + + /// Percentage of the FDA's recommended daily value of vitamin C for someone + /// with a 2,000 calorie diet. + final int vitaminCPercentage; + + /// A text description of a single serving (e.g. '1 apple' or '1/2 cup'). + final String servingSize; + + /// Calories per serving (as described in [servingSize]). + final int caloriesPerServing; + + /// Whether or not the veggie has been saved to the user's garden (i.e. marked + /// as a favorite). + bool isFavorite; + + /// A set of trivia questions and answers related to the veggie. + final List trivia; + + String? get categoryName => veggieCategoryNames[category]; +} diff --git a/veggieseasons/lib/main.dart b/veggieseasons/lib/main.dart new file mode 100644 index 0000000..13f321f --- /dev/null +++ b/veggieseasons/lib/main.dart @@ -0,0 +1,243 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:io' show Platform; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter/services.dart' + show DeviceOrientation, SystemChrome; +import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; +import 'package:window_size/window_size.dart'; + +import 'data/app_state.dart'; +import 'data/preferences.dart'; +import 'screens/details.dart'; +import 'screens/favorites.dart'; +import 'screens/home.dart'; +import 'screens/list.dart'; +import 'screens/search.dart'; +import 'screens/settings.dart'; +import 'styles.dart'; +import 'widgets/veggie_seasons_page.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown, + ]); + setupWindow(); + + runApp( + const RootRestorationScope(restorationId: 'root', child: VeggieApp()), + ); +} + +const double windowWidth = 480; +const double windowHeight = 854; + +void setupWindow() { + if (!kIsWeb && + (Platform.isWindows || Platform.isLinux || Platform.isMacOS)) { + setWindowTitle('Veggie Seasons'); + setWindowMinSize(const Size(windowWidth, windowHeight)); + setWindowMaxSize(const Size(windowWidth, windowHeight)); + getCurrentScreen().then((screen) { + setWindowFrame( + Rect.fromCenter( + center: screen!.frame.center, + width: windowWidth, + height: windowHeight, + ), + ); + }); + } +} + +final _rootNavigatorKey = GlobalKey(); +final _shellNavigatorKey = GlobalKey(); + +class VeggieApp extends StatefulWidget { + const VeggieApp({super.key}); + + @override + State createState() => _VeggieAppState(); +} + +class _VeggieAppState extends State with RestorationMixin { + final _RestorableAppState _appState = _RestorableAppState(); + + @override + String get restorationId => 'wrapper'; + + @override + void restoreState(RestorationBucket? oldBucket, bool initialRestore) { + registerForRestoration(_appState, 'state'); + } + + @override + void dispose() { + _appState.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return MultiProvider( + providers: [ + ChangeNotifierProvider.value(value: _appState.value), + ChangeNotifierProvider(create: (_) => Preferences()..load()), + ], + child: CupertinoApp.router( + theme: Styles.veggieThemeData, + debugShowCheckedModeBanner: false, + restorationScopeId: 'app', + routerConfig: GoRouter( + navigatorKey: _rootNavigatorKey, + restorationScopeId: 'router', + initialLocation: '/list', + redirect: (context, state) { + if (state.path == '/') { + return '/list'; + } + return null; + }, + debugLogDiagnostics: true, + routes: [ + ShellRoute( + navigatorKey: _shellNavigatorKey, + pageBuilder: (context, state, child) { + return CupertinoPage( + restorationId: 'router.shell', + child: HomeScreen( + restorationId: 'home', + child: child, + onTap: (index) { + if (index == 0) { + context.go('/list'); + } else if (index == 1) { + context.go('/favorites'); + } else if (index == 2) { + context.go('/search'); + } else { + context.go('/settings'); + } + }, + ), + ); + }, + routes: [ + GoRoute( + path: '/list', + pageBuilder: (context, state) { + return VeggieSeasonsPage( + key: state.pageKey, + restorationId: 'route.list', + child: const ListScreen(restorationId: 'list'), + ); + }, + routes: [_buildDetailsRoute()], + ), + GoRoute( + path: '/favorites', + pageBuilder: (context, state) { + return VeggieSeasonsPage( + key: state.pageKey, + restorationId: 'route.favorites', + child: const FavoritesScreen( + restorationId: 'favorites', + ), + ); + }, + routes: [_buildDetailsRoute()], + ), + GoRoute( + path: '/search', + pageBuilder: (context, state) { + return VeggieSeasonsPage( + key: state.pageKey, + restorationId: 'route.search', + child: const SearchScreen(restorationId: 'search'), + ); + }, + routes: [_buildDetailsRoute()], + ), + GoRoute( + path: '/settings', + pageBuilder: (context, state) { + return VeggieSeasonsPage( + key: state.pageKey, + restorationId: 'route.settings', + child: const SettingsScreen( + restorationId: 'settings', + ), + ); + }, + routes: [ + GoRoute( + parentNavigatorKey: _rootNavigatorKey, + path: 'categories', + pageBuilder: (context, state) { + return VeggieCategorySettingsScreen.pageBuilder( + context, + ); + }, + ), + GoRoute( + parentNavigatorKey: _rootNavigatorKey, + path: 'calories', + pageBuilder: (context, state) { + return CalorieSettingsScreen.pageBuilder(context); + }, + ), + ], + ), + ], + ), + ], + ), + ), + ); + } + + // GoRouter does not support relative routes, + // see https://github.com/flutter/flutter/issues/108177 + GoRoute _buildDetailsRoute() { + return GoRoute( + parentNavigatorKey: _rootNavigatorKey, + path: 'details/:id', + pageBuilder: (context, state) { + final veggieId = int.parse(state.pathParameters['id']!); + return CupertinoPage( + restorationId: 'route.details', + child: DetailsScreen(id: veggieId, restorationId: 'details'), + ); + }, + ); + } +} + +class _RestorableAppState extends RestorableListenable { + @override + AppState createDefaultValue() { + return AppState(); + } + + @override + AppState fromPrimitives(Object? data) { + final appState = AppState(); + final favorites = (data as List).cast(); + for (var id in favorites) { + appState.setFavorite(id, true); + } + return appState; + } + + @override + Object toPrimitives() { + return value.favoriteVeggies.map((veggie) => veggie.id).toList(); + } +} diff --git a/veggieseasons/lib/screens/details.dart b/veggieseasons/lib/screens/details.dart new file mode 100644 index 0000000..90c3aa0 --- /dev/null +++ b/veggieseasons/lib/screens/details.dart @@ -0,0 +1,294 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; +import '../data/app_state.dart'; +import '../data/preferences.dart'; +import '../data/veggie.dart'; +import '../styles.dart'; +import '../widgets/detail_buttons.dart'; + +class ServingInfoChart extends StatelessWidget { + const ServingInfoChart(this.veggie, this.prefs, {super.key}); + + final Veggie veggie; + + final Preferences prefs; + + // Creates a [Text] widget to display a veggie's "percentage of your daily + // value of this vitamin" data adjusted for the user's preferred calorie + // target. + Widget _buildVitaminText( + int standardPercentage, + Future targetCalories, + ) { + return FutureBuilder( + future: targetCalories, + builder: (context, snapshot) { + final target = snapshot.data ?? 2000; + final percent = standardPercentage * 2000 ~/ target; + + return Text( + '$percent% DV', + style: CupertinoTheme.of(context).textTheme.textStyle, + textAlign: TextAlign.end, + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + final themeData = CupertinoTheme.of(context); + return Column( + children: [ + const SizedBox(height: 32), + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Text( + 'Serving size', + style: Styles.detailsServingLabelText(themeData), + ), + const Spacer(), + Text( + veggie.servingSize, + textAlign: TextAlign.end, + style: CupertinoTheme.of(context).textTheme.textStyle, + ), + ], + ), + const SizedBox(height: 24), + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Text( + 'Calories', + style: Styles.detailsServingLabelText(themeData), + ), + const Spacer(), + Text( + '${veggie.caloriesPerServing} kCal', + style: CupertinoTheme.of(context).textTheme.textStyle, + textAlign: TextAlign.end, + ), + ], + ), + const SizedBox(height: 24), + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Text( + 'Vitamin A', + style: Styles.detailsServingLabelText(themeData), + ), + const Spacer(), + _buildVitaminText( + veggie.vitaminAPercentage, + prefs.desiredCalories, + ), + ], + ), + const SizedBox(height: 24), + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Text( + 'Vitamin C', + style: Styles.detailsServingLabelText(themeData), + ), + const Spacer(), + _buildVitaminText( + veggie.vitaminCPercentage, + prefs.desiredCalories, + ), + ], + ), + Padding( + padding: const EdgeInsets.only(top: 32), + child: FutureBuilder( + future: prefs.desiredCalories, + builder: (context, snapshot) { + return Text( + 'Percent daily values based on a diet of ' + '${snapshot.data ?? '2,000'} calories.', + style: Styles.detailsServingNoteText(themeData), + ); + }, + ), + ), + ], + ); + } +} + +class InfoView extends StatelessWidget { + final int? id; + + const InfoView(this.id, {super.key}); + + @override + Widget build(BuildContext context) { + final appState = Provider.of(context); + final prefs = Provider.of(context); + final veggie = appState.getVeggie(id); + final themeData = CupertinoTheme.of(context); + + return Padding( + padding: const EdgeInsets.all(24), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text(veggie.name, style: Styles.detailsTitleText(themeData)), + const SizedBox(height: 8), + Text( + veggie.shortDescription, + style: CupertinoTheme.of(context).textTheme.textStyle, + ), + const SizedBox(height: 16), + Text( + 'Seasons', + style: Styles.detailsServingLabelText(themeData), + ), + const SizedBox(height: 12), + Row( + mainAxisSize: MainAxisSize.max, + children: [ + for (var season in Season.values) ...[ + const Spacer(), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Styles.seasonIconData[season], + color: veggie.seasons.contains(season) + ? Styles.seasonColors[season] + : const Color.fromRGBO(128, 128, 128, 1), + size: 24, + ), + const SizedBox(height: 4), + Text( + season.name.characters.first.toUpperCase() + + season.name.characters.skip(1).string, + style: Styles.minorText( + CupertinoTheme.of(context), + ).copyWith(fontSize: 11), + ), + ], + ), + const Spacer(), + ], + ], + ), + ServingInfoChart(veggie, prefs), + ], + ), + ); + } +} + +class DetailsScreen extends StatelessWidget { + final int? id; + final String? restorationId; + + const DetailsScreen({this.id, this.restorationId, super.key}); + + Widget _buildHeader(BuildContext context, AppState model) { + final veggie = model.getVeggie(id); + + return SizedBox( + height: 240, + child: Stack( + children: [ + Positioned( + right: 0, + left: 0, + child: Image.asset( + veggie.imageAssetPath, + fit: BoxFit.cover, + semanticLabel: 'A background image of ${veggie.name}', + ), + ), + Positioned( + top: 16, + left: 16, + child: SafeArea( + child: CloseButton(() { + context.pop(); + }), + ), + ), + Positioned( + top: 16, + right: 16, + child: SafeArea( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + ShareButton(() { + showCupertinoModalPopup( + context: context, + builder: (context) { + return CupertinoActionSheet( + title: Text('Share ${veggie.name}'), + message: Text(veggie.shortDescription), + actions: [ + CupertinoActionSheetAction( + onPressed: () { + Navigator.pop(context); + }, + child: const Text('OK'), + ), + ], + ); + }, + ); + }), + const SizedBox(width: 8), + Builder( + builder: (context) { + final appState = Provider.of(context); + final veggie = appState.getVeggie(id); + + return FavoriteButton( + () => appState.setFavorite(id, !veggie.isFavorite), + veggie.isFavorite, + ); + }, + ), + ], + ), + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + final appState = Provider.of(context); + + return CupertinoPageScaffold( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: ListView( + restorationId: 'list', + children: [ + _buildHeader(context, appState), + const SizedBox(height: 20), + InfoView(id), + ], + ), + ), + ], + ), + ); + } +} diff --git a/veggieseasons/lib/screens/favorites.dart b/veggieseasons/lib/screens/favorites.dart new file mode 100644 index 0000000..3bdf2b0 --- /dev/null +++ b/veggieseasons/lib/screens/favorites.dart @@ -0,0 +1,59 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:provider/provider.dart'; +import '../data/app_state.dart'; +import '../data/veggie.dart'; +import '../widgets/veggie_headline.dart'; + +class FavoritesScreen extends StatelessWidget { + const FavoritesScreen({this.restorationId, super.key}); + + final String? restorationId; + + @override + Widget build(BuildContext context) { + return CupertinoTabView( + restorationScopeId: restorationId, + builder: (context) { + final model = Provider.of(context); + + return CupertinoPageScaffold( + navigationBar: const CupertinoNavigationBar( + middle: Text('My Garden'), + ), + child: Center( + child: model.favoriteVeggies.isEmpty + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Text( + 'You haven\'t added any favorite veggies to your garden yet.', + style: CupertinoTheme.of( + context, + ).textTheme.textStyle, + ), + ) + : ListView( + restorationId: 'list', + children: [ + const SizedBox(height: 24), + for (Veggie veggie in model.favoriteVeggies) + Padding( + padding: const EdgeInsets.fromLTRB( + 16, + 0, + 16, + 24, + ), + child: VeggieHeadline(veggie), + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/veggieseasons/lib/screens/home.dart b/veggieseasons/lib/screens/home.dart new file mode 100644 index 0000000..fd46ba9 --- /dev/null +++ b/veggieseasons/lib/screens/home.dart @@ -0,0 +1,81 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:go_router/go_router.dart'; + +const _bottomNavigationBarItemIconPadding = EdgeInsets.only(top: 4.0); + +class HomeScreen extends StatelessWidget { + const HomeScreen({ + super.key, + this.restorationId, + required this.child, + required this.onTap, + }); + + final String? restorationId; + final Widget child; + final void Function(int) onTap; + + @override + Widget build(BuildContext context) { + final String location = GoRouter.of( + context, + ).routerDelegate.currentConfiguration.uri.toString(); + final index = _getSelectedIndex(location); + return RestorationScope( + restorationId: restorationId, + child: CupertinoPageScaffold( + child: Column( + children: [ + Expanded(child: child), + CupertinoTabBar( + currentIndex: index, + items: const [ + BottomNavigationBarItem( + icon: Padding( + padding: _bottomNavigationBarItemIconPadding, + child: Icon(CupertinoIcons.home), + ), + label: 'Home', + ), + BottomNavigationBarItem( + icon: Padding( + padding: _bottomNavigationBarItemIconPadding, + child: Icon(CupertinoIcons.book), + ), + label: 'My Garden', + ), + BottomNavigationBarItem( + icon: Padding( + padding: _bottomNavigationBarItemIconPadding, + child: Icon(CupertinoIcons.search), + ), + label: 'Search', + ), + BottomNavigationBarItem( + icon: Padding( + padding: _bottomNavigationBarItemIconPadding, + child: Icon(CupertinoIcons.settings), + ), + label: 'Settings', + ), + ], + onTap: onTap, + ), + ], + ), + ), + ); + } + + int _getSelectedIndex(String location) { + if (location.startsWith('/list')) return 0; + if (location.startsWith('/favorites')) return 1; + if (location.startsWith('/search')) return 2; + if (location.startsWith('/settings')) return 3; + return 0; + } +} diff --git a/veggieseasons/lib/screens/list.dart b/veggieseasons/lib/screens/list.dart new file mode 100644 index 0000000..c348322 --- /dev/null +++ b/veggieseasons/lib/screens/list.dart @@ -0,0 +1,95 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; +import '../data/app_state.dart'; +import '../data/preferences.dart'; +import '../data/veggie.dart'; +import '../styles.dart'; +import '../widgets/veggie_card.dart'; + +class ListScreen extends StatelessWidget { + const ListScreen({this.restorationId, super.key}); + + final String? restorationId; + + Widget _generateVeggieCard( + Veggie veggie, + Preferences prefs, { + bool inSeason = true, + }) { + return Padding( + padding: const EdgeInsets.only(left: 16, right: 16, bottom: 24), + child: FutureBuilder>( + future: prefs.preferredCategories, + builder: (context, snapshot) { + final data = snapshot.data ?? {}; + return VeggieCard( + veggie, + inSeason, + data.contains(veggie.category), + ); + }, + ), + ); + } + + @override + Widget build(BuildContext context) { + return CupertinoTabView( + restorationScopeId: restorationId, + builder: (context) { + final appState = Provider.of(context); + final prefs = Provider.of(context); + final themeData = CupertinoTheme.of(context); + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarBrightness: MediaQuery.platformBrightnessOf(context), + ), + child: SafeArea( + bottom: false, + child: ListView.builder( + restorationId: 'list', + itemCount: appState.allVeggies.length + 2, + itemBuilder: (context, index) { + if (index == 0) { + return Padding( + padding: const EdgeInsets.fromLTRB(16, 24, 16, 16), + child: Text( + 'In season today', + style: Styles.headlineText(themeData), + ), + ); + } else if (index <= appState.availableVeggies.length) { + return _generateVeggieCard( + appState.availableVeggies[index - 1], + prefs, + ); + } else if (index <= appState.availableVeggies.length + 1) { + return Padding( + padding: const EdgeInsets.fromLTRB(16, 24, 16, 16), + child: Text( + 'Not in season', + style: Styles.headlineText(themeData), + ), + ); + } else { + var relativeIndex = + index - (appState.availableVeggies.length + 2); + return _generateVeggieCard( + appState.unavailableVeggies[relativeIndex], + prefs, + inSeason: false, + ); + } + }, + ), + ), + ); + }, + ); + } +} diff --git a/veggieseasons/lib/screens/search.dart b/veggieseasons/lib/screens/search.dart new file mode 100644 index 0000000..824c6df --- /dev/null +++ b/veggieseasons/lib/screens/search.dart @@ -0,0 +1,132 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; +import '../data/app_state.dart'; +import '../data/veggie.dart'; +import '../widgets/veggie_headline.dart'; + +class SearchScreen extends StatefulWidget { + const SearchScreen({this.restorationId, super.key}); + + final String? restorationId; + + @override + State createState() => _SearchScreenState(); +} + +class _SearchScreenState extends State + with RestorationMixin { + final controller = RestorableTextEditingController(); + final focusNode = FocusNode(); + String? terms; + + @override + String? get restorationId => widget.restorationId; + + @override + void restoreState(RestorationBucket? oldBucket, bool initialRestore) { + registerForRestoration(controller, 'text'); + controller.addListener(_onTextChanged); + terms = controller.value.text; + } + + @override + void dispose() { + focusNode.dispose(); + controller.dispose(); + super.dispose(); + } + + void _onTextChanged() { + setState(() => terms = controller.value.text); + } + + Widget _createSearchBox({bool focus = true}) { + return Padding( + padding: const EdgeInsets.all(8), + child: CupertinoSearchTextField( + controller: controller.value, + focusNode: focus ? focusNode : null, + ), + ); + } + + Widget _buildSearchResults(List veggies) { + if (veggies.isEmpty) { + return Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Text( + 'No veggies matching your search terms were found.', + style: CupertinoTheme.of(context).textTheme.textStyle, + ), + ), + ); + } + + return ListView.builder( + restorationId: 'list', + itemCount: veggies.length + 1, + itemBuilder: (context, i) { + if (i == 0) { + return Visibility( + // This invisible and otherwise unnecessary search box is used to + // pad the list entries downward, so none will be underneath the + // real search box when the list is at its top scroll position. + visible: false, + maintainSize: true, + maintainAnimation: true, + maintainState: true, + // This invisible and otherwise unnecessary search box is used to + // pad the list entries downward, so none will be underneath the + // real search box when the list is at its top scroll position. + child: _createSearchBox(focus: false), + ); + } else { + return Padding( + padding: const EdgeInsets.only( + left: 16, + right: 16, + bottom: 24, + ), + child: VeggieHeadline(veggies[i - 1]), + ); + } + }, + ); + } + + @override + Widget build(BuildContext context) { + final model = Provider.of(context); + + return UnmanagedRestorationScope( + bucket: bucket, + child: CupertinoTabView( + restorationScopeId: 'tabview', + builder: (context) { + return AnnotatedRegion( + value: SystemUiOverlayStyle( + statusBarBrightness: MediaQuery.platformBrightnessOf( + context, + ), + ), + child: SafeArea( + bottom: false, + child: Stack( + children: [ + _buildSearchResults(model.searchVeggies(terms)), + _createSearchBox(), + ], + ), + ), + ); + }, + ), + ); + } +} diff --git a/veggieseasons/lib/screens/settings.dart b/veggieseasons/lib/screens/settings.dart new file mode 100644 index 0000000..eb537dc --- /dev/null +++ b/veggieseasons/lib/screens/settings.dart @@ -0,0 +1,311 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; +import '../data/preferences.dart'; +import '../data/veggie.dart'; +import '../styles.dart'; + +class VeggieCategorySettingsScreen extends StatelessWidget { + const VeggieCategorySettingsScreen({super.key, this.restorationId}); + + final String? restorationId; + + static Page pageBuilder(BuildContext context) { + return const CupertinoPage( + restorationId: 'router.categories', + child: VeggieCategorySettingsScreen(restorationId: 'category'), + title: 'Preferred Categories', + ); + } + + @override + Widget build(BuildContext context) { + final model = Provider.of(context); + final currentPrefs = model.preferredCategories; + var brightness = CupertinoTheme.brightnessOf(context); + return RestorationScope( + restorationId: restorationId, + child: CupertinoPageScaffold( + navigationBar: const CupertinoNavigationBar( + middle: Text('Preferred Categories'), + previousPageTitle: 'Settings', + ), + backgroundColor: Styles.scaffoldBackground(brightness), + child: FutureBuilder>( + future: currentPrefs, + builder: (context, snapshot) { + final tiles = []; + + for (final category in VeggieCategory.values) { + CupertinoSwitch toggle; + + // It's possible that category data hasn't loaded from shared prefs + // yet, so display it if possible and fall back to disabled switches + // otherwise. + if (snapshot.hasData) { + toggle = CupertinoSwitch( + value: snapshot.data!.contains(category), + onChanged: (value) { + if (value) { + model.addPreferredCategory(category); + } else { + model.removePreferredCategory(category); + } + }, + ); + } else { + toggle = const CupertinoSwitch( + value: false, + onChanged: null, + ); + } + + tiles.add( + CupertinoListTile.notched( + title: Text(veggieCategoryNames[category]!), + trailing: toggle, + ), + ); + } + + return ListView( + restorationId: 'list', + children: [ + CupertinoListSection.insetGrouped( + hasLeading: false, + children: tiles, + ), + ], + ); + }, + ), + ), + ); + } +} + +class CalorieSettingsScreen extends StatelessWidget { + const CalorieSettingsScreen({super.key, this.restorationId}); + + final String? restorationId; + + static const max = 1000; + static const min = 2600; + static const step = 200; + + static Page pageBuilder(BuildContext context) { + return const CupertinoPage( + restorationId: 'router.calorie', + child: CalorieSettingsScreen(restorationId: 'calorie'), + title: 'Calorie Target', + ); + } + + @override + Widget build(BuildContext context) { + final model = Provider.of(context); + var brightness = CupertinoTheme.brightnessOf(context); + return RestorationScope( + restorationId: restorationId, + child: CupertinoPageScaffold( + navigationBar: const CupertinoNavigationBar( + previousPageTitle: 'Settings', + ), + backgroundColor: Styles.scaffoldBackground(brightness), + child: ListView( + restorationId: 'list', + children: [ + FutureBuilder( + future: model.desiredCalories, + builder: (context, snapshot) { + final tiles = []; + + for (var cals = max; cals < min; cals += step) { + tiles.add( + CupertinoListTile.notched( + title: Text('$cals calories'), + trailing: SettingsIcon( + icon: CupertinoIcons.check_mark, + foregroundColor: + snapshot.hasData && snapshot.data == cals + ? CupertinoColors.activeBlue + : Styles.transparentColor, + backgroundColor: Styles.transparentColor, + ), + onTap: snapshot.hasData + ? () => model.setDesiredCalories(cals) + : null, + ), + ); + } + + return CupertinoListSection.insetGrouped( + header: Text( + 'Available calorie levels'.toUpperCase(), + style: Styles.settingsGroupHeaderText( + CupertinoTheme.of(context), + ), + ), + footer: Text( + 'These are used for serving calculations', + style: Styles.settingsGroupFooterText( + CupertinoTheme.of(context), + ), + ), + children: tiles, + ); + }, + ), + ], + ), + ), + ); + } +} + +class SettingsScreen extends StatefulWidget { + const SettingsScreen({this.restorationId, super.key}); + + final String? restorationId; + + @override + State createState() => _SettingsScreenState(); +} + +class _SettingsScreenState extends State { + CupertinoListTile _buildCaloriesTile( + BuildContext context, + Preferences prefs, + ) { + return CupertinoListTile.notched( + leading: const SettingsIcon( + backgroundColor: CupertinoColors.systemBlue, + icon: Styles.calorieIcon, + ), + title: const Text('Calorie Target'), + additionalInfo: FutureBuilder( + future: prefs.desiredCalories, + builder: (context, snapshot) { + return Text( + snapshot.data?.toString() ?? '', + style: CupertinoTheme.of(context).textTheme.textStyle, + ); + }, + ), + trailing: const CupertinoListTileChevron(), + onTap: () => context.go('/settings/calories'), + ); + } + + CupertinoListTile _buildCategoriesTile( + BuildContext context, + Preferences prefs, + ) { + return CupertinoListTile.notched( + leading: const SettingsIcon( + backgroundColor: CupertinoColors.systemOrange, + icon: Styles.preferenceIcon, + ), + title: const Text('Preferred Categories'), + trailing: const CupertinoListTileChevron(), + onTap: () => context.go('/settings/categories'), + ); + } + + CupertinoListTile _buildRestoreDefaultsTile( + BuildContext context, + Preferences prefs, + ) { + return CupertinoListTile.notched( + leading: const SettingsIcon( + backgroundColor: CupertinoColors.systemRed, + icon: Styles.resetIcon, + ), + title: const Text('Restore Defaults'), + onTap: () { + showCupertinoDialog( + context: context, + builder: (context) => CupertinoAlertDialog( + title: const Text('Are you sure?'), + content: const Text( + 'Are you sure you want to reset the current settings?', + ), + actions: [ + CupertinoDialogAction( + isDestructiveAction: true, + child: const Text('Yes'), + onPressed: () async { + await prefs.restoreDefaults(); + if (!context.mounted) return; + context.pop(); + }, + ), + CupertinoDialogAction( + isDefaultAction: true, + child: const Text('No'), + onPressed: () => context.pop(), + ), + ], + ), + ); + }, + ); + } + + @override + Widget build(BuildContext context) { + final prefs = Provider.of(context); + + return CupertinoPageScaffold( + backgroundColor: Styles.scaffoldBackground( + CupertinoTheme.brightnessOf(context), + ), + child: CustomScrollView( + slivers: [ + const CupertinoSliverNavigationBar(largeTitle: Text('Settings')), + SliverList( + delegate: SliverChildListDelegate([ + CupertinoListSection.insetGrouped( + children: [ + _buildCaloriesTile(context, prefs), + _buildCategoriesTile(context, prefs), + ], + ), + CupertinoListSection.insetGrouped( + children: [_buildRestoreDefaultsTile(context, prefs)], + ), + ]), + ), + ], + ), + ); + } +} + +class SettingsIcon extends StatelessWidget { + const SettingsIcon({ + required this.icon, + this.foregroundColor = CupertinoColors.white, + this.backgroundColor = CupertinoColors.black, + super.key, + }); + + final Color backgroundColor; + final Color foregroundColor; + final IconData icon; + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: backgroundColor, + ), + child: Center(child: Icon(icon, color: foregroundColor, size: 20)), + ); + } +} diff --git a/veggieseasons/lib/styles.dart b/veggieseasons/lib/styles.dart new file mode 100644 index 0000000..ce45247 --- /dev/null +++ b/veggieseasons/lib/styles.dart @@ -0,0 +1,221 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'data/veggie.dart'; + +abstract class Styles { + static CupertinoThemeData veggieThemeData = const CupertinoThemeData( + textTheme: CupertinoTextThemeData( + textStyle: TextStyle( + color: CupertinoColors.label, + fontSize: 16, + fontWeight: FontWeight.normal, + fontStyle: FontStyle.normal, + fontFamily: 'CupertinoSystemText', + letterSpacing: -0.41, + decoration: TextDecoration.none, + ), + ), + ); + + static TextStyle headlineText(CupertinoThemeData themeData) => themeData + .textTheme + .textStyle + .copyWith(fontSize: 32, fontWeight: FontWeight.bold); + + static TextStyle minorText(CupertinoThemeData themeData) => themeData + .textTheme + .textStyle + .copyWith(color: const Color.fromRGBO(128, 128, 128, 1)); + + static TextStyle headlineName(CupertinoThemeData themeData) => themeData + .textTheme + .textStyle + .copyWith(fontSize: 24, fontWeight: FontWeight.bold); + + static TextStyle cardTitleText(CupertinoThemeData themeData) => + themeData.textTheme.textStyle.copyWith( + color: const Color.fromRGBO(0, 0, 0, 0.9), + fontSize: 32, + fontWeight: FontWeight.bold, + ); + + static TextStyle cardCategoryText(CupertinoThemeData themeData) => + themeData.textTheme.textStyle.copyWith( + color: const Color.fromRGBO(255, 255, 255, 0.9), + ); + + static TextStyle cardDescriptionText(CupertinoThemeData themeData) => + themeData.textTheme.textStyle.copyWith( + color: const Color.fromRGBO(0, 0, 0, 0.9), + ); + + static TextStyle detailsTitleText(CupertinoThemeData themeData) => + themeData.textTheme.textStyle.copyWith( + fontSize: 30, + fontWeight: FontWeight.bold, + ); + + static TextStyle detailsPreferredCategoryText( + CupertinoThemeData themeData, + ) => themeData.textTheme.textStyle.copyWith(fontWeight: FontWeight.bold); + + static TextStyle detailsBoldDescriptionText( + CupertinoThemeData themeData, + ) => themeData.textTheme.textStyle.copyWith( + color: const Color.fromRGBO(0, 0, 0, 0.9), + fontWeight: FontWeight.bold, + ); + + static TextStyle detailsServingHeaderText( + CupertinoThemeData themeData, + ) => themeData.textTheme.textStyle.copyWith( + color: const Color.fromRGBO(176, 176, 176, 1), + fontWeight: FontWeight.bold, + ); + + static TextStyle detailsServingLabelText(CupertinoThemeData themeData) => + themeData.textTheme.textStyle.copyWith(fontWeight: FontWeight.bold); + + static TextStyle detailsServingNoteText(CupertinoThemeData themeData) => + themeData.textTheme.textStyle.copyWith(fontStyle: FontStyle.italic); + + static TextStyle triviaFinishedTitleText(CupertinoThemeData themeData) => + themeData.textTheme.textStyle.copyWith(fontSize: 32); + + static TextStyle triviaFinishedBigText(CupertinoThemeData themeData) => + themeData.textTheme.textStyle.copyWith(fontSize: 48); + + static TextStyle settingsGroupHeaderText(CupertinoThemeData themeData) => + themeData.textTheme.textStyle.copyWith( + color: CupertinoColors.inactiveGray, + fontSize: 13.5, + letterSpacing: -0.5, + ); + + static TextStyle settingsGroupFooterText(CupertinoThemeData themeData) => + themeData.textTheme.textStyle.copyWith( + color: const Color(0xff777777), + fontSize: 13, + letterSpacing: -0.08, + ); + + static const appBackground = Color(0xffd0d0d0); + + static Color? scaffoldBackground(Brightness brightness) => + brightness == Brightness.light + ? CupertinoColors.extraLightBackgroundGray + : null; + + static const frostedBackground = Color(0xccf8f8f8); + + static const closeButtonUnpressed = Color(0xff101010); + + static const closeButtonPressed = Color(0xff808080); + + static TextStyle settingsItemSubtitleText( + CupertinoThemeData themeData, + ) => themeData.textTheme.textStyle.copyWith( + fontSize: 12, + letterSpacing: -0.2, + ); + + static const Color searchCursorColor = Color.fromRGBO(0, 122, 255, 1); + + static const Color searchIconColor = Color.fromRGBO(128, 128, 128, 1); + + static const seasonColors = { + Season.winter: Color(0xff336dcc), + Season.spring: Color(0xff2fa02b), + Season.summer: Color(0xff287213), + Season.autumn: Color(0xff724913), + }; + + // While handy, some of the Font Awesome icons sometimes bleed over their + // allotted bounds. This padding is used to adjust for that. + static const seasonIconPadding = { + Season.winter: EdgeInsets.only(right: 0), + Season.spring: EdgeInsets.only(right: 4), + Season.summer: EdgeInsets.only(right: 6), + Season.autumn: EdgeInsets.only(right: 0), + }; + + static const seasonIconData = { + Season.winter: FontAwesomeIcons.snowflake, + Season.spring: FontAwesomeIcons.leaf, + Season.summer: FontAwesomeIcons.umbrellaBeach, + Season.autumn: FontAwesomeIcons.canadianMapleLeaf, + }; + + static const seasonBorder = Border( + top: BorderSide(color: Color(0xff606060)), + left: BorderSide(color: Color(0xff606060)), + bottom: BorderSide(color: Color(0xff606060)), + right: BorderSide(color: Color(0xff606060)), + ); + + static const uncheckedIcon = IconData( + 0xf372, + fontFamily: CupertinoIcons.iconFont, + fontPackage: CupertinoIcons.iconFontPackage, + ); + + static const checkedIcon = IconData( + 0xf373, + fontFamily: CupertinoIcons.iconFont, + fontPackage: CupertinoIcons.iconFontPackage, + ); + + static const transparentColor = Color(0x00000000); + + static const shadowColor = Color(0xa0000000); + + static const shadowGradient = LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [transparentColor, shadowColor], + ); + + static const Color settingsMediumGray = Color(0xffc7c7c7); + + static const Color settingsItemPressed = Color(0xffd9d9d9); + + static Color settingsItemColor(Brightness brightness) => + brightness == Brightness.light + ? CupertinoColors.tertiarySystemBackground + : CupertinoColors.darkBackgroundGray; + + static Color settingsLineation(Brightness brightness) => + brightness == Brightness.light + ? const Color(0xffbcbbc1) + : const Color(0xff4c4b4b); + + static const Color settingsBackground = Color(0xffefeff4); + + static const preferenceIcon = IconData( + 0xf443, + fontFamily: CupertinoIcons.iconFont, + fontPackage: CupertinoIcons.iconFontPackage, + ); + + static const resetIcon = IconData( + 0xf4c4, + fontFamily: CupertinoIcons.iconFont, + fontPackage: CupertinoIcons.iconFontPackage, + ); + + static const calorieIcon = IconData( + 0xf3bb, + fontFamily: CupertinoIcons.iconFont, + fontPackage: CupertinoIcons.iconFontPackage, + ); + + static const servingInfoBorderColor = Color(0xffb0b0b0); + + static const ColorFilter desaturatedColorFilter = + // 222222 is a random color that has low color saturation. + ColorFilter.mode(Color(0xff222222), BlendMode.saturation); +} diff --git a/veggieseasons/lib/widgets/detail_buttons.dart b/veggieseasons/lib/widgets/detail_buttons.dart new file mode 100644 index 0000000..1ad4d1e --- /dev/null +++ b/veggieseasons/lib/widgets/detail_buttons.dart @@ -0,0 +1,148 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui' as ui; + +import 'package:flutter/cupertino.dart'; +import '../styles.dart'; + +/// Partially overlays and then blurs its child's background. +class FrostedBox extends StatelessWidget { + const FrostedBox({this.child, super.key}); + + final Widget? child; + + @override + Widget build(BuildContext context) { + return BackdropFilter( + filter: ui.ImageFilter.blur(sigmaX: 10, sigmaY: 10), + child: DecoratedBox( + decoration: const BoxDecoration(color: Styles.frostedBackground), + child: child, + ), + ); + } +} + +/// An Icon that implicitly animates changes to its color. +class ColorChangingIcon extends ImplicitlyAnimatedWidget { + const ColorChangingIcon( + this.icon, { + this.color = CupertinoColors.black, + this.size, + required super.duration, + super.key, + }); + + final Color color; + + final IconData icon; + + final double? size; + + @override + AnimatedWidgetBaseState createState() => + _ColorChangingIconState(); +} + +class _ColorChangingIconState + extends AnimatedWidgetBaseState { + ColorTween? _colorTween; + + @override + Widget build(BuildContext context) { + return Icon( + widget.icon, + semanticLabel: 'Close button', + size: widget.size, + color: _colorTween?.evaluate(animation), + ); + } + + @override + void forEachTween(TweenVisitor visitor) { + _colorTween = + visitor( + _colorTween, + widget.color, + (dynamic value) => ColorTween(begin: value as Color?), + ) + as ColorTween?; + } +} + +/// A close button that invokes a callback when pressed. +class CloseButton extends _DetailPageButton { + const CloseButton(VoidCallback onPressed, {super.key}) + : super(onPressed, CupertinoIcons.chevron_back); +} + +/// A share button that invokes a callback when pressed. +class ShareButton extends _DetailPageButton { + const ShareButton(VoidCallback onPressed, {super.key}) + : super(onPressed, CupertinoIcons.share); +} + +/// A favorite button that invokes a callback when pressed. +class FavoriteButton extends _DetailPageButton { + const FavoriteButton( + VoidCallback onPressed, + bool isFavorite, { + super.key, + }) : super( + onPressed, + isFavorite ? CupertinoIcons.heart_fill : CupertinoIcons.heart, + ); +} + +class _DetailPageButton extends StatefulWidget { + const _DetailPageButton(this.onPressed, this.icon, {super.key}); + + final VoidCallback onPressed; + final IconData icon; + + @override + State<_DetailPageButton> createState() => _DetailPageButtonState(); +} + +class _DetailPageButtonState extends State<_DetailPageButton> { + bool tapInProgress = false; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTapDown: (details) { + setState(() => tapInProgress = true); + }, + onTapUp: (details) { + setState(() => tapInProgress = false); + widget.onPressed(); + }, + onTapCancel: () { + setState(() => tapInProgress = false); + }, + child: ClipOval( + child: FrostedBox( + child: Container( + width: 30, + height: 30, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + ), + child: Center( + child: ColorChangingIcon( + widget.icon, + duration: const Duration(milliseconds: 300), + color: tapInProgress + ? Styles.closeButtonPressed + : Styles.closeButtonUnpressed, + size: 20, + ), + ), + ), + ), + ), + ); + } +} diff --git a/veggieseasons/lib/widgets/veggie_card.dart b/veggieseasons/lib/widgets/veggie_card.dart new file mode 100644 index 0000000..ce7e537 --- /dev/null +++ b/veggieseasons/lib/widgets/veggie_card.dart @@ -0,0 +1,114 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import '../data/veggie.dart'; +import '../styles.dart'; + +/// A Card-like Widget that responds to tap events by animating changes to its +/// elevation and invoking an optional [onPressed] callback. +class PressableCard extends StatelessWidget { + const PressableCard({ + required this.child, + this.borderRadius = const BorderRadius.all(Radius.circular(16)), + this.onPressed, + super.key, + }); + + final VoidCallback? onPressed; + + final Widget child; + + final BorderRadius borderRadius; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onPressed, + child: Container( + decoration: BoxDecoration(borderRadius: borderRadius), + child: ClipRRect(borderRadius: borderRadius, child: child), + ), + ); + } +} + +class VeggieCard extends StatelessWidget { + const VeggieCard( + this.veggie, + this.isInSeason, + this.isPreferredCategory, { + super.key, + }); + + /// Veggie to be displayed by the card. + final Veggie veggie; + + /// If the veggie is in season, it's displayed more prominently and the + /// image is fully saturated. Otherwise, it's reduced and de-saturated. + final bool isInSeason; + + /// Whether [veggie] falls into one of user's preferred [VeggieCategory]s + final bool isPreferredCategory; + + Widget _buildDetails(BuildContext context) { + final themeData = CupertinoTheme.of(context); + return Container( + color: Colors.white, + child: Padding( + padding: const EdgeInsets.fromLTRB(20, 16, 16, 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(veggie.name, style: Styles.cardTitleText(themeData)), + const SizedBox(height: 8), + Text( + veggie.shortDescription, + style: Styles.cardDescriptionText(themeData), + ), + ], + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return PressableCard( + onPressed: () { + // GoRouter does not support relative routes, + // so navigate to the absolute route. + // see https://github.com/flutter/flutter/issues/108177 + context.go('/list/details/${veggie.id}'); + }, + child: Stack( + children: [ + Semantics( + label: 'A card background featuring ${veggie.name}', + child: Container( + height: isInSeason ? 300 : 150, + decoration: BoxDecoration( + image: DecorationImage( + fit: BoxFit.cover, + colorFilter: isInSeason + ? null + : Styles.desaturatedColorFilter, + image: AssetImage(veggie.imageAssetPath), + ), + ), + ), + ), + Positioned( + bottom: 0, + left: 0, + right: 0, + child: _buildDetails(context), + ), + ], + ), + ); + } +} diff --git a/veggieseasons/lib/widgets/veggie_headline.dart b/veggieseasons/lib/widgets/veggie_headline.dart new file mode 100644 index 0000000..d21cf01 --- /dev/null +++ b/veggieseasons/lib/widgets/veggie_headline.dart @@ -0,0 +1,117 @@ +// Copyright 2018 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:go_router/go_router.dart'; +import '../data/veggie.dart'; +import '../styles.dart'; + +class ZoomClipAssetImage extends StatelessWidget { + const ZoomClipAssetImage({ + required this.zoom, + this.height, + this.width, + required this.imageAsset, + super.key, + }); + + final double zoom; + final double? height; + final double? width; + final String imageAsset; + + @override + Widget build(BuildContext context) { + return Container( + height: height, + width: width, + alignment: Alignment.center, + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: OverflowBox( + maxHeight: height! * zoom, + maxWidth: width! * zoom, + child: Image.asset(imageAsset, fit: BoxFit.fill), + ), + ), + ); + } +} + +class VeggieHeadline extends StatelessWidget { + final Veggie veggie; + + const VeggieHeadline(this.veggie, {super.key}); + + List _buildSeasonDots(List seasons) { + var widgets = []; + + for (var season in seasons) { + widgets.add(const SizedBox(width: 4)); + widgets.add( + Container( + height: 10, + width: 10, + decoration: BoxDecoration( + color: Styles.seasonColors[season], + borderRadius: BorderRadius.circular(5), + ), + ), + ); + } + + return widgets; + } + + @override + Widget build(BuildContext context) { + final themeData = CupertinoTheme.of(context); + final String location = GoRouter.of( + context, + ).routerDelegate.currentConfiguration.uri.toString(); + + return GestureDetector( + onTap: () { + // GoRouter does not support relative routes, + // so navigate to the absolute route, which can be either + // `/favorites/details/${veggie.id}` or `/search/details/${veggie.id}` + // see https://github.com/flutter/flutter/issues/108177 + context.go('$location/details/${veggie.id}'); + }, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ZoomClipAssetImage( + imageAsset: veggie.imageAssetPath, + zoom: 2.4, + height: 72, + width: 72, + ), + const SizedBox(width: 8), + Flexible( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + veggie.name, + style: Styles.headlineName(themeData), + ), + ..._buildSeasonDots(veggie.seasons), + ], + ), + Text( + veggie.shortDescription, + style: themeData.textTheme.textStyle, + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/veggieseasons/lib/widgets/veggie_seasons_page.dart b/veggieseasons/lib/widgets/veggie_seasons_page.dart new file mode 100644 index 0000000..aac37df --- /dev/null +++ b/veggieseasons/lib/widgets/veggie_seasons_page.dart @@ -0,0 +1,45 @@ +// Copyright 2024, the Flutter project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; + +class VeggieSeasonsPage extends Page { + final Widget child; + + const VeggieSeasonsPage({ + super.key, + required this.child, + super.restorationId, + }); + + @override + VeggieSeasonsPageRoute createRoute(BuildContext context) => + VeggieSeasonsPageRoute(this); +} + +class VeggieSeasonsPageRoute extends PageRoute { + VeggieSeasonsPageRoute(VeggieSeasonsPage page) + : super(settings: page); + + VeggieSeasonsPage get _page => settings as VeggieSeasonsPage; + + @override + Color? get barrierColor => null; + + @override + String? get barrierLabel => null; + + @override + bool get maintainState => true; + + @override + Duration get transitionDuration => Duration.zero; + + @override + Widget buildPage( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) => _page.child; +} diff --git a/veggieseasons/macos/.gitignore b/veggieseasons/macos/.gitignore new file mode 100644 index 0000000..746adbb --- /dev/null +++ b/veggieseasons/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/veggieseasons/macos/Flutter/Flutter-Debug.xcconfig b/veggieseasons/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000..4b81f9b --- /dev/null +++ b/veggieseasons/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/veggieseasons/macos/Flutter/Flutter-Release.xcconfig b/veggieseasons/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000..5caa9d1 --- /dev/null +++ b/veggieseasons/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/veggieseasons/macos/Flutter/GeneratedPluginRegistrant.swift b/veggieseasons/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000..f717508 --- /dev/null +++ b/veggieseasons/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import shared_preferences_foundation +import window_size + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + WindowSizePlugin.register(with: registry.registrar(forPlugin: "WindowSizePlugin")) +} diff --git a/veggieseasons/macos/Podfile b/veggieseasons/macos/Podfile new file mode 100644 index 0000000..c795730 --- /dev/null +++ b/veggieseasons/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# 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', 'ephemeral', '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 Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/veggieseasons/macos/Runner.xcodeproj/project.pbxproj b/veggieseasons/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..3beb548 --- /dev/null +++ b/veggieseasons/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 0C591566BA30BFA6D780386A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4EE22A708C4E7F94406AFD15 /* Pods_Runner.framework */; }; + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + AEA6F424A1A42303F9A597C0 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DBED630FEBB9A18F27C8E814 /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* veggieseasons.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = veggieseasons.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 413A4F2B0013AFEC349AB2C5 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 4D8AF33CD5C878ED37254D67 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 4EE22A708C4E7F94406AFD15 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 67C24EB68B67E166AAF91AFC /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + A5460BC7374C6E7592B1FF3E /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + C1FB72C1E9B25422AFEB740F /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + C518FFB7BDFCCDF5D96D3B89 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + DBED630FEBB9A18F27C8E814 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AEA6F424A1A42303F9A597C0 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0C591566BA30BFA6D780386A /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 91771D8FA5A30CAEDA51E26A /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* veggieseasons.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 91771D8FA5A30CAEDA51E26A /* Pods */ = { + isa = PBXGroup; + children = ( + A5460BC7374C6E7592B1FF3E /* Pods-Runner.debug.xcconfig */, + C518FFB7BDFCCDF5D96D3B89 /* Pods-Runner.release.xcconfig */, + 4D8AF33CD5C878ED37254D67 /* Pods-Runner.profile.xcconfig */, + 413A4F2B0013AFEC349AB2C5 /* Pods-RunnerTests.debug.xcconfig */, + C1FB72C1E9B25422AFEB740F /* Pods-RunnerTests.release.xcconfig */, + 67C24EB68B67E166AAF91AFC /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4EE22A708C4E7F94406AFD15 /* Pods_Runner.framework */, + DBED630FEBB9A18F27C8E814 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + A9DCAE5A5FC2DAC764BF600F /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 6233C4FEDE0E579A6F92072D /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + 6AA72EDC93A2C61F5DA982D4 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* veggieseasons.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + 6233C4FEDE0E579A6F92072D /* [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; + }; + 6AA72EDC93A2C61F5DA982D4 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + A9DCAE5A5FC2DAC764BF600F /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 413A4F2B0013AFEC349AB2C5 /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.veggieseasons.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/veggieseasons.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/veggieseasons"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C1FB72C1E9B25422AFEB740F /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.veggieseasons.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/veggieseasons.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/veggieseasons"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 67C24EB68B67E166AAF91AFC /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.veggieseasons.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/veggieseasons.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/veggieseasons"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + 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_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + 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_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + 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_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + 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_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + 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_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + 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_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + 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_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/veggieseasons/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/veggieseasons/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/veggieseasons/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/veggieseasons/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/veggieseasons/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..4c21638 --- /dev/null +++ b/veggieseasons/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/veggieseasons/macos/Runner.xcworkspace/contents.xcworkspacedata b/veggieseasons/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..21a3cc1 --- /dev/null +++ b/veggieseasons/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/veggieseasons/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/veggieseasons/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/veggieseasons/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/veggieseasons/macos/Runner/AppDelegate.swift b/veggieseasons/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000..8e02df2 --- /dev/null +++ b/veggieseasons/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a2ec33f --- /dev/null +++ b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000..82b6f9d Binary files /dev/null and b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000..13b35eb Binary files /dev/null and b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000..0a3f5fa Binary files /dev/null and b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000..bdb5722 Binary files /dev/null and b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 0000000..f083318 Binary files /dev/null and b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000..326c0e7 Binary files /dev/null and b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000..2f1632c Binary files /dev/null and b/veggieseasons/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/veggieseasons/macos/Runner/Base.lproj/MainMenu.xib b/veggieseasons/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..80e867a --- /dev/null +++ b/veggieseasons/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/veggieseasons/macos/Runner/Configs/AppInfo.xcconfig b/veggieseasons/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000..04ab23a --- /dev/null +++ b/veggieseasons/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = veggieseasons + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.veggieseasons + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2024 dev.flutter. All rights reserved. diff --git a/veggieseasons/macos/Runner/Configs/Debug.xcconfig b/veggieseasons/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000..36b0fd9 --- /dev/null +++ b/veggieseasons/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/veggieseasons/macos/Runner/Configs/Release.xcconfig b/veggieseasons/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000..dff4f49 --- /dev/null +++ b/veggieseasons/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/veggieseasons/macos/Runner/Configs/Warnings.xcconfig b/veggieseasons/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000..42bcbf4 --- /dev/null +++ b/veggieseasons/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/veggieseasons/macos/Runner/DebugProfile.entitlements b/veggieseasons/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000..dddb8a3 --- /dev/null +++ b/veggieseasons/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/veggieseasons/macos/Runner/Info.plist b/veggieseasons/macos/Runner/Info.plist new file mode 100644 index 0000000..4789daa --- /dev/null +++ b/veggieseasons/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/veggieseasons/macos/Runner/MainFlutterWindow.swift b/veggieseasons/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000..3cc05eb --- /dev/null +++ b/veggieseasons/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/veggieseasons/macos/Runner/Release.entitlements b/veggieseasons/macos/Runner/Release.entitlements new file mode 100644 index 0000000..852fa1a --- /dev/null +++ b/veggieseasons/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/veggieseasons/macos/RunnerTests/RunnerTests.swift b/veggieseasons/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..61f3bd1 --- /dev/null +++ b/veggieseasons/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/veggieseasons/pubspec.yaml b/veggieseasons/pubspec.yaml new file mode 100644 index 0000000..cd87de0 --- /dev/null +++ b/veggieseasons/pubspec.yaml @@ -0,0 +1,82 @@ +name: veggieseasons +description: An iOS app that shows the fruits and veggies currently in season. +publish_to: none +version: 1.2.0 +resolution: workspace + +environment: + sdk: ^3.9.0-0 + +dependencies: + flutter: + sdk: flutter + cupertino_icons: ^1.0.2 + font_awesome_flutter: ^10.1.0 + intl: ^0.20.0 + provider: ^6.0.1 + shared_preferences: ^2.0.14 + window_size: + git: + url: https://github.com/google/flutter-desktop-embedding.git + path: plugins/window_size + # TODO: https://github.com/flutter/samples/issues/1838 + # go_router ^7.1.0 is breaking the state restoration tests + go_router: ^16.0.0 + +dev_dependencies: + analysis_defaults: + path: ../analysis_defaults + flutter_test: + sdk: flutter + flutter_launcher_icons: ^0.14.0 + +flutter: + assets: + - assets/images/apple.jpg + - assets/images/artichoke.jpg + - assets/images/asparagus.jpg + - assets/images/avocado.jpg + - assets/images/blackberry.jpg + - assets/images/cantaloupe.jpg + - assets/images/cauliflower.jpg + - assets/images/endive.jpg + - assets/images/fig.jpg + - assets/images/grape.jpg + - assets/images/green_bell_pepper.jpg + - assets/images/habanero.jpg + - assets/images/kale.jpg + - assets/images/kiwi.jpg + - assets/images/lemon.jpg + - assets/images/lime.jpg + - assets/images/mango.jpg + - assets/images/mushroom.jpg + - assets/images/nectarine.jpg + - assets/images/persimmon.jpg + - assets/images/plum.jpg + - assets/images/potato.jpg + - assets/images/radicchio.jpg + - assets/images/radish.jpg + - assets/images/squash.jpg + - assets/images/strawberry.jpg + - assets/images/tangelo.jpg + - assets/images/tomato.jpg + - assets/images/watermelon.jpg + - assets/images/orange_bell_pepper.jpg + + fonts: + - family: NotoSans + fonts: + - asset: assets/fonts/NotoSans-Regular.ttf + weight: 400 + - asset: assets/fonts/NotoSans-Bold.ttf + weight: 700 + - asset: assets/fonts/NotoSans-BoldItalic.ttf + weight: 700 + style: italic + - asset: assets/fonts/NotoSans-Italic.ttf + style: italic + weight: 400 + +flutter_icons: + ios: true + image_path: "assets/icon/launcher_icon.png" diff --git a/veggieseasons/test/widget_test.dart b/veggieseasons/test/widget_test.dart new file mode 100644 index 0000000..f1181b0 --- /dev/null +++ b/veggieseasons/test/widget_test.dart @@ -0,0 +1,11 @@ +// 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_test/flutter_test.dart'; + +void main() { + testWidgets('This test always passes', (tester) async {}); +} diff --git a/veggieseasons/web/icons/Icon-192.png b/veggieseasons/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/veggieseasons/web/icons/Icon-192.png differ diff --git a/veggieseasons/web/icons/Icon-512.png b/veggieseasons/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/veggieseasons/web/icons/Icon-512.png differ diff --git a/veggieseasons/web/index.html b/veggieseasons/web/index.html new file mode 100644 index 0000000..ee352d4 --- /dev/null +++ b/veggieseasons/web/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + veggieseasons + + + + + + diff --git a/veggieseasons/web/manifest.json b/veggieseasons/web/manifest.json new file mode 100644 index 0000000..c75ec99 --- /dev/null +++ b/veggieseasons/web/manifest.json @@ -0,0 +1,23 @@ +{ + "name": "veggieseasons", + "short_name": "veggieseasons", + "start_url": ".", + "display": "minimal-ui", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +}