├── android ├── gradle.properties ├── app │ ├── signing │ │ ├── debug.keystore │ │ └── debug.properties │ ├── src │ │ └── main │ │ │ ├── web_hi_res_512.png │ │ │ ├── res │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── values │ │ │ │ └── styles.xml │ │ │ └── drawable │ │ │ │ └── launch_background.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── yourcompany │ │ │ │ └── dartconf │ │ │ │ └── MainActivity.java │ │ │ └── AndroidManifest.xml │ └── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── settings.gradle ├── build.gradle ├── .gitignore ├── gradlew.bat └── gradlew ├── assets ├── dartconf.png └── google_la_map.png ├── docs └── flutter_01.png ├── ios ├── Flutter │ ├── Debug.xcconfig │ ├── Release.xcconfig │ ├── flutter_assets │ │ └── readme.md │ └── AppFrameworkInfo.plist ├── Runner │ ├── AppDelegate.h │ ├── Assets.xcassets │ │ ├── LaunchImage.imageset │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ ├── README.md │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ └── Contents.json │ ├── main.m │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ └── Info.plist ├── Runner.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ └── project.pbxproj ├── Runner.xcworkspace │ └── contents.xcworkspacedata ├── .gitignore └── Podfile ├── .travis.yml ├── AUTHORS ├── .metadata ├── .gitignore ├── .idea └── modules.xml ├── pubspec.yaml ├── tool └── travis.sh ├── lib ├── src │ ├── common.dart │ ├── map.dart │ ├── info.dart │ ├── feeds.dart │ └── schedule.dart └── main.dart ├── dart_conf.iml ├── android.iml ├── LICENSE ├── CONTRIBUTING.md └── readme.md /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /assets/dartconf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/assets/dartconf.png -------------------------------------------------------------------------------- /docs/flutter_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/docs/flutter_01.png -------------------------------------------------------------------------------- /assets/google_la_map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/assets/google_la_map.png -------------------------------------------------------------------------------- /android/app/signing/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/android/app/signing/debug.keystore -------------------------------------------------------------------------------- /android/app/src/main/web_hi_res_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/android/app/src/main/web_hi_res_512.png -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /android/app/signing/debug.properties: -------------------------------------------------------------------------------- 1 | storeFile=debug.keystore 2 | storePassword=android 3 | keyAlias=androiddebugkey 4 | keyPassword=android 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | script: 3 | - ./tool/travis.sh 4 | dart: 5 | - dev 6 | 7 | branches: 8 | only: 9 | - master 10 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /ios/Flutter/flutter_assets/readme.md: -------------------------------------------------------------------------------- 1 | This directory is used to hold flutter assets during a build. 2 | 3 | This file is just so git will track the directory. -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dart-archive/conference_app/master/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Below is a list of people and organizations that have contributed 2 | # to the project. Names should be added to the list like so: 3 | # 4 | # Name/Organization 5 | 6 | Google Inc. 7 | 8 | Ryan Edge -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4.1-all.zip 6 | -------------------------------------------------------------------------------- /ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char * argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 2135f3c0076f10f5a52f0399e57ce99a86dac124 8 | channel: master 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .atom/ 3 | .idea 4 | .gradle 5 | .packages 6 | .dart_tool/ 7 | .pub/ 8 | build/ 9 | ios/.generated/ 10 | ios/Podfile.lock 11 | packages 12 | pubspec.lock 13 | .flutter-plugins 14 | 15 | ios/Flutter/flutter_assets 16 | 17 | assets/app.token.txt 18 | ios/Flutter/flutter_assets/assets/app.token.txt 19 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | 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. -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 7 | [GeneratedPluginRegistrant registerWithRegistry:self]; 8 | // Override point for customization after application launch. 9 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 10 | } 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/yourcompany/dartconf/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.yourcompany.dartconf; 2 | 3 | import android.os.Bundle; 4 | 5 | import io.flutter.app.FlutterActivity; 6 | import io.flutter.plugins.GeneratedPluginRegistrant; 7 | 8 | public class MainActivity extends FlutterActivity { 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | GeneratedPluginRegistrant.registerWith(this); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: dart_conf_flutter 2 | description: A conference app for DartConf 2018. 3 | 4 | dependencies: 5 | cloud_firestore: ^0.5.1 6 | cupertino_icons: ^0.1.2 7 | flutter: 8 | sdk: flutter 9 | http: ^0.11.3+16 10 | intl: ^0.15.5 11 | url_launcher: ^3.0.0 12 | 13 | dev_dependencies: 14 | flutter_test: 15 | sdk: flutter 16 | 17 | flutter: 18 | uses-material-design: true 19 | assets: 20 | - assets/dartconf.png 21 | - assets/google_la_map.png 22 | - assets/app.token.txt 23 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withInputStream { stream -> plugins.load(stream) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /tool/travis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file 4 | # for details. All rights reserved. Use of this source code is governed by a 5 | # BSD-style license that can be found in the LICENSE file. 6 | 7 | # Fast fail the script on failures. 8 | set -e 9 | 10 | # Get flutter. 11 | (cd ..; git clone https://github.com/flutter/flutter.git) 12 | export PATH="../flutter/bin:$PATH" 13 | flutter --version 14 | 15 | # Provision pub packages. 16 | flutter packages get 17 | 18 | # Ensure the code analyzes cleanly. 19 | touch assets/app.token.txt 20 | flutter analyze 21 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | google() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.1.1' 9 | classpath 'com.google.gms:google-services:3.2.1' 10 | } 11 | } 12 | 13 | allprojects { 14 | repositories { 15 | jcenter() 16 | google() 17 | } 18 | } 19 | 20 | rootProject.buildDir = '../build' 21 | subprojects { 22 | project.buildDir = "${rootProject.buildDir}/${project.name}" 23 | project.evaluationDependsOn(':app') 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/common.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'package:flutter/material.dart'; 6 | 7 | final ThemeData _theme = new ThemeData(primarySwatch: Colors.blue); 8 | 9 | ThemeData get appTheme => _theme; 10 | 11 | Widget pad8([Widget child]) { 12 | return new Padding(padding: const EdgeInsets.all(8.0), child: child); 13 | } 14 | 15 | String addParagraphs(String str) { 16 | return str?.replaceAll('

', '\n')?.replaceAll(' ', '\n\n'); 17 | } 18 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | *.pbxuser 16 | *.mode1v3 17 | *.mode2v3 18 | *.perspectivev3 19 | 20 | !default.pbxuser 21 | !default.mode1v3 22 | !default.mode2v3 23 | !default.perspectivev3 24 | 25 | xcuserdata 26 | 27 | *.moved-aside 28 | 29 | *.pyc 30 | *sync/ 31 | Icon? 32 | .tags* 33 | 34 | /Flutter/app.flx 35 | /Flutter/app.zip 36 | /Flutter/App.framework 37 | /Flutter/Flutter.framework 38 | /Flutter/Generated.xcconfig 39 | /ServiceDefinitions.json 40 | 41 | Pods/ 42 | 43 | Runner/GoogleService-Info.plist 44 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | 19 | # Local configuration file (sdk path, etc) 20 | local.properties 21 | 22 | # Log Files 23 | *.log 24 | 25 | # IDEA/Android Studio ignores 26 | *.iml 27 | *.ipr 28 | *.iws 29 | /.idea/* 30 | 31 | # IDEA/Android Studio Ignore exceptions 32 | !/.idea/vcs.xml 33 | !/.idea/fileTemplates/ 34 | !/.idea/inspectionProfiles/ 35 | !/.idea/scopes/ 36 | !/.idea/codeStyleSettings.xml 37 | !/.idea/.name 38 | !/.idea/encodings.xml 39 | !/.idea/copyright/ 40 | !/.idea/compiler.xml 41 | 42 | # OSX 43 | *.DS_Store 44 | 45 | # Heap dump captures 46 | captures/ 47 | 48 | # App-specific files 49 | app/google-services.json 50 | app/src/main/java/io/flutter/plugins/* 51 | app/signing/release.keystore 52 | app/signing/release.properties 53 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | UIRequiredDeviceCapabilities 24 | 25 | arm64 26 | 27 | MinimumOSVersion 28 | 8.0 29 | 30 | 31 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | if ENV['FLUTTER_FRAMEWORK_DIR'] == nil 5 | abort('Please set FLUTTER_FRAMEWORK_DIR to the directory containing Flutter.framework') 6 | end 7 | 8 | target 'Runner' do 9 | # Pods for Runner 10 | 11 | # Flutter Pods 12 | pod 'Flutter', :path => ENV['FLUTTER_FRAMEWORK_DIR'] 13 | 14 | if File.exists? '../.flutter-plugins' 15 | flutter_root = File.expand_path('..') 16 | File.foreach('../.flutter-plugins') { |line| 17 | plugin = line.split(pattern='=') 18 | if plugin.length == 2 19 | name = plugin[0].strip() 20 | path = plugin[1].strip() 21 | resolved_path = File.expand_path("#{path}/ios", flutter_root) 22 | pod name, :path => resolved_path 23 | else 24 | puts "Invalid plugin specification: #{line}" 25 | end 26 | } 27 | end 28 | end 29 | 30 | post_install do |installer| 31 | installer.pods_project.targets.each do |target| 32 | target.build_configurations.each do |config| 33 | config.build_settings['ENABLE_BITCODE'] = 'NO' 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /dart_conf.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017, the Dart project authors. All rights reserved. 2 | Redistribution and use in source and binary forms, with or without 3 | modification, are permitted provided that the following conditions are 4 | met: 5 | 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above 9 | copyright notice, this list of conditions and the following 10 | disclaimer in the documentation and/or other materials provided 11 | with the distribution. 12 | * Neither the name of Google Inc. nor the names of its 13 | contributors may be used to endorse or promote products derived 14 | from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | DartConf 2018 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | arm64 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | UIViewControllerBasedStatusBarAppearance 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /lib/src/map.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:async'; 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:url_launcher/url_launcher.dart'; 9 | 10 | class MapPage extends StatefulWidget { 11 | static const String title = 'Map'; 12 | static const IconData icon = Icons.map; 13 | 14 | @override 15 | _MapPageState createState() => new _MapPageState(); 16 | } 17 | 18 | class _MapPageState extends State { 19 | @override 20 | Widget build(BuildContext context) { 21 | final ThemeData theme = Theme.of(context); 22 | 23 | return new Scaffold( 24 | appBar: new AppBar( 25 | title: new Text(MapPage.title), 26 | automaticallyImplyLeading: false, 27 | ), 28 | body: new SizedBox.expand( 29 | child: new Image.asset( 30 | 'assets/google_la_map.png', 31 | fit: BoxFit.cover, 32 | ), 33 | ), 34 | floatingActionButton: new Chip( 35 | label: new InkWell( 36 | onTap: _launchIntent, 37 | child: new Padding( 38 | padding: const EdgeInsets.all(4.0), 39 | child: new Text( 40 | 'Google Los Angeles\n340 Main St, Venice, CA 90291', 41 | style: theme.textTheme.subhead.apply( 42 | color: Colors.blue, decoration: TextDecoration.underline), 43 | ), 44 | ), 45 | ), 46 | ), 47 | ); 48 | } 49 | 50 | Future _launchIntent() async { 51 | const url = 'https://www.google.com/maps/place/Google/@33.9950762,' 52 | '-118.4784572,17z/data=!3m1!4b1!4m5!3m4!1s0x80c2bacf22ee5b65:' 53 | '0x95c465741fbb54b3!8m2!3d33.9950762!4d-118.4762685'; 54 | if (await canLaunch(url)) { 55 | await launch(url); 56 | } else { 57 | print("Error: could not launch URL."); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 15 | 19 | 26 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the small print at 2 | the end). 3 | 4 | ### Before you contribute 5 | 6 | Before we can use your code, you must sign the 7 | [Google Individual Contributor License Agreement][CLA] (CLA), which you can do 8 | online. The CLA is necessary mainly because you own the copyright to your 9 | changes, even after your contribution becomes part of our codebase, so we need 10 | your permission to use and distribute your code. We also need to be sure of 11 | various other things—for instance that you'll tell us if you know that your code 12 | infringes on other people's patents. You don't have to sign the CLA until after 13 | you've submitted your code for review and a member has approved it, but you must 14 | do it before we can put your code into our codebase. 15 | 16 | Before you start working on a larger contribution, you should get in touch with 17 | us first through the issue tracker with your idea so that we can help out and 18 | possibly guide you. Coordinating up front makes it much easier to avoid 19 | frustration later on. 20 | 21 | [CLA]: https://cla.developers.google.com/about/google-individual 22 | 23 | ### Code reviews 24 | 25 | All submissions, including submissions by project members, require review. We 26 | recommend [forking the repository][fork], making changes in your fork, and 27 | [sending us a pull request][pr] so we can review the changes and merge them into 28 | this repository. 29 | 30 | [fork]: https://help.github.com/articles/about-forks/ 31 | [pr]: https://help.github.com/articles/creating-a-pull-request/ 32 | 33 | Functional changes will require tests to be added or changed. The tests live in 34 | the `test/` directory, and are run with `pub run test`. If you need to create 35 | new tests, use the existing tests as a guideline for what they should look like. 36 | 37 | Before you send your pull request, make sure all the tests pass! 38 | 39 | ### File headers 40 | 41 | All files in the project must start with the following header. 42 | 43 | // Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file 44 | // for details. All rights reserved. Use of this source code is governed by a 45 | // BSD-style license that can be found in the LICENSE file. 46 | 47 | ### The small print 48 | 49 | Contributions made by corporations are covered by a different agreement than the 50 | one above, the 51 | [Software Grant and Corporate Contributor License Agreement][CCLA]. 52 | 53 | [CCLA]: https://developers.google.com/open-source/cla/corporate 54 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } -------------------------------------------------------------------------------- /lib/src/info.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:async'; 6 | 7 | import 'package:cloud_firestore/cloud_firestore.dart'; 8 | import 'package:flutter/material.dart'; 9 | 10 | import 'common.dart'; 11 | 12 | class InfoPage extends StatefulWidget { 13 | static const String title = 'Info'; 14 | static const IconData icon = Icons.info_outline; 15 | 16 | @override 17 | _InfoPageState createState() => new _InfoPageState(); 18 | } 19 | 20 | class _InfoPageState extends State { 21 | List infos; 22 | StreamSubscription sub; 23 | 24 | @override 25 | void initState() { 26 | super.initState(); 27 | 28 | final CollectionReference collection = 29 | Firestore.instance.collection('info'); 30 | sub = collection?.snapshots?.listen((QuerySnapshot snapshot) { 31 | setState(() { 32 | infos = snapshot.documents.map(InfoData.fromDocument).toList(); 33 | infos.sort(); 34 | }); 35 | }); 36 | } 37 | 38 | @override 39 | void dispose() { 40 | super.dispose(); 41 | 42 | sub?.cancel(); 43 | } 44 | 45 | @override 46 | Widget build(BuildContext context) { 47 | final ThemeData theme = Theme.of(context); 48 | Widget body; 49 | 50 | if (infos == null) { 51 | body = new Center( 52 | child: new CircularProgressIndicator(), 53 | ); 54 | } else { 55 | var _textToExpansionTile = (InfoData info) { 56 | return new ExpansionTile( 57 | title: new Text(info.title), 58 | key: new PageStorageKey(info.title), 59 | children: [ 60 | new Text(info.text, style: theme.textTheme.subhead), 61 | ].map(_pad).toList(), 62 | ); 63 | }; 64 | 65 | body = new ListView( 66 | children: infos.map(_textToExpansionTile).toList(), 67 | ); 68 | } 69 | 70 | return new Scaffold( 71 | appBar: new AppBar(title: new Text(InfoPage.title)), 72 | body: body, 73 | ); 74 | } 75 | } 76 | 77 | Widget _pad(Widget child) { 78 | return new Padding( 79 | padding: const EdgeInsets.only( 80 | left: 16.0, 81 | right: 16.0, 82 | bottom: 16.0, 83 | ), 84 | child: child, 85 | ); 86 | } 87 | 88 | class InfoData implements Comparable { 89 | static InfoData fromDocument(DocumentSnapshot doc) { 90 | return new InfoData(doc['title'], addParagraphs(doc['text']), doc['order']); 91 | } 92 | 93 | final String title; 94 | final String text; 95 | final int order; 96 | 97 | InfoData(this.title, this.text, this.order); 98 | 99 | @override 100 | int compareTo(InfoData other) { 101 | if (order == other.order) { 102 | return title.compareTo(other.title); 103 | } else { 104 | return order - other.order; 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:async'; 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:intl/date_symbol_data_local.dart'; 9 | 10 | import 'src/common.dart'; 11 | import 'src/feeds.dart'; 12 | import 'src/info.dart'; 13 | import 'src/map.dart'; 14 | import 'src/schedule.dart'; 15 | 16 | Future main() async { 17 | await initializeDateFormatting('en'); 18 | 19 | runApp(new DartConfApp()); 20 | } 21 | 22 | class DartConfApp extends StatefulWidget { 23 | @override 24 | DartConfAppState createState() { 25 | return new DartConfAppState(); 26 | } 27 | } 28 | 29 | class DartConfAppState extends State { 30 | static const Curve scrollCurve = Curves.fastOutSlowIn; 31 | static final Key key = new UniqueKey(); 32 | 33 | final PageController controller = new PageController(); 34 | 35 | int _selectedIndex = 0; 36 | final Key feedPageKey = new GlobalKey(debugLabel: 'feed page'); 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | final Color textColor = appTheme.textTheme.body1.color; 41 | final TextStyle textStyle = new TextStyle(color: textColor); 42 | 43 | return new MaterialApp( 44 | title: 'DartConf', 45 | theme: appTheme, 46 | home: new Scaffold( 47 | body: new PageView( 48 | controller: controller, 49 | children: [ 50 | new SchedulePage(key: key), 51 | new InfoPage(), 52 | new MapPage(), 53 | new FeedsPage(), 54 | ], 55 | ), 56 | bottomNavigationBar: new BottomNavigationBar( 57 | type: BottomNavigationBarType.fixed, 58 | currentIndex: _selectedIndex, 59 | onTap: (int index) { 60 | setState(() { 61 | _selectedIndex = index; 62 | controller.animateToPage( 63 | _selectedIndex, 64 | duration: kTabScrollDuration, 65 | curve: scrollCurve, 66 | ); 67 | }); 68 | }, 69 | items: [ 70 | new BottomNavigationBarItem( 71 | icon: new Icon(SchedulePage.icon, color: textColor), 72 | title: new Text(SchedulePage.title, style: textStyle), 73 | backgroundColor: appTheme.secondaryHeaderColor, 74 | ), 75 | new BottomNavigationBarItem( 76 | icon: new Icon(InfoPage.icon, color: textColor), 77 | title: new Text(InfoPage.title, style: textStyle), 78 | backgroundColor: appTheme.secondaryHeaderColor, 79 | ), 80 | new BottomNavigationBarItem( 81 | icon: new Icon(MapPage.icon, color: textColor), 82 | title: new Text(MapPage.title, style: textStyle), 83 | backgroundColor: appTheme.secondaryHeaderColor, 84 | ), 85 | new BottomNavigationBarItem( 86 | icon: new Icon(FeedsPage.icon, color: textColor), 87 | title: new Text(FeedsPage.title, style: textStyle), 88 | backgroundColor: appTheme.secondaryHeaderColor, 89 | ), 90 | ], 91 | ), 92 | ), 93 | ); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withInputStream { stream -> 5 | localProperties.load(stream) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException('Flutter SDK not found. Define location with flutter.sdk in the local.properties file.') 12 | } 13 | 14 | apply plugin: 'com.android.application' 15 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 16 | 17 | def loadSigningConfiguration(String name) { 18 | def propertiesFile = file("signing/${name}.properties") as File 19 | if (!propertiesFile.exists()) { 20 | throw new FileNotFoundException("""The properties file ${propertiesFile.absolutePath} is missing, 21 | did you remember to add the signing configuration to the project for $name? 22 | 23 | Please refer to the readme for further instructions.""") 24 | } 25 | 26 | def properties = new Properties() 27 | properties.load(new FileInputStream(propertiesFile)) 28 | return properties 29 | } 30 | 31 | def getKeystore(String fileName) { 32 | def keystoreFile = file("signing/${fileName}") as File 33 | if (!keystoreFile.exists()) { 34 | throw new FileNotFoundException("""The keystore file ${keystoreFile.absolutePath} is missing, 35 | but the signing configuration for the current build variant specifies it as the storeFile. 36 | Did you remember to add the keystore to the project for this build variant? 37 | 38 | Please refer to the readme for further instructions.""") 39 | } 40 | return keystoreFile 41 | } 42 | 43 | def isSigningConfigurationDefinedFor(String name) { 44 | return file("signing/${name}.properties").exists() 45 | } 46 | 47 | def reportMissingSigningConfiguration(String name) { 48 | logger.error(""" 49 | 50 | ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ 51 | The signing configuration for Android $name builds is not defined, 52 | please refer to the readme for further informations on how to set it up. 53 | ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ 54 | 55 | """) 56 | } 57 | 58 | android { 59 | compileSdkVersion 27 60 | 61 | lintOptions { 62 | disable 'InvalidPackage' 63 | } 64 | 65 | defaultConfig { 66 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 67 | applicationId 'com.yourcompany.dartconf' 68 | minSdkVersion 16 69 | targetSdkVersion 27 70 | versionCode 1 71 | versionName '1.0' 72 | } 73 | 74 | signingConfigs { 75 | debug { 76 | def configuration = loadSigningConfiguration('debug') 77 | storeFile getKeystore(configuration['storeFile']) 78 | storePassword configuration['storePassword'] 79 | keyAlias configuration['keyAlias'] 80 | keyPassword configuration['keyPassword'] 81 | } 82 | 83 | release { 84 | if (isSigningConfigurationDefinedFor('release')) { 85 | def configuration = loadSigningConfiguration('release') 86 | storeFile getKeystore(configuration['storeFile']) 87 | storePassword configuration['storePassword'] 88 | keyAlias configuration['keyAlias'] 89 | keyPassword configuration['keyPassword'] 90 | } else { 91 | reportMissingSigningConfiguration('release') 92 | } 93 | } 94 | } 95 | 96 | buildTypes { 97 | debug { 98 | signingConfig signingConfigs.debug 99 | } 100 | release { 101 | signingConfig signingConfigs.release 102 | } 103 | } 104 | } 105 | 106 | flutter { 107 | source '../..' 108 | } 109 | 110 | dependencies { 111 | api 'com.google.firebase:firebase-firestore:11.8.0' 112 | api 'com.google.firebase:firebase-core:11.8.0' 113 | } 114 | 115 | apply plugin: 'com.google.gms.google-services' 116 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # DartConf 2 | 3 | [![Build Status](https://travis-ci.org/dart-lang/conference_app.svg?branch=master)](https://travis-ci.org/dart-lang/conference_app) 4 | 5 | A conference app for DartConf 2018. 6 | 7 | ## App Overview 8 | 9 | This is a mobile app for DartConf 2018. The overall design is roughly modelled 10 | after the 2017 Google I/O app. It's organized into 4 separate pages: 11 | 12 | ![DartConf 2018 Atom screenshot](docs/flutter_01.png) 13 | 14 | ### Schedule page 15 | 16 | This is a page for the conference schedule (and the main landing page). It shows 17 | two tabs; one for the first day of the conference and one for the 2nd (Jan 23rd and 18 | Jan 24th). Each tab shows a chronological list of the conference sessions for that 19 | day. Each session shows as a material card. Clicking on a session will open the 20 | session in a separate page, and show more detailed information including the full 21 | session description. We use a hero animation when transitioning from the session 22 | card to the session page. 23 | 24 | The data for the sessions, including the full list of sessions, the title, presenters, 25 | date and time, duration, description, and presenter image, is backed by firebase. 26 | Editing any of this info in the firebase admin page will do a live update of all 27 | clients automatically. 28 | 29 | ### Info page 30 | 31 | This is a page for general conference information. It's broken into a handful of 32 | categories, and each category has a short amount of descriptive text. 33 | 34 | The data is backed by firebase; editing the category list or info item title 35 | or text in the firebase admin UI will update clients automatically. 36 | 37 | ### Map page 38 | 39 | This is a static image of the conference location. 40 | 41 | ### Feeds page 42 | 43 | This is a live Twitter feed of any tweets matching the search term 44 | `#dartconf OR #flutterio OR #angulardart`. Selecting a tweet will open the corresponding 45 | item directly at twitter.com. A pull-down gesture will refresh the tweet data. 46 | 47 | ## Build the app for development 48 | 49 | To build the app in debug mode for Android, you will need to provide the following files: 50 | 51 | * `assets/app.token.txt` Containing Twitter app credentials 52 | * `android/app/google-services.json` A Firebase project config file 53 | 54 | ### Creating the Twitter access token 55 | First create a [Twitter app](https://apps.twitter.com/) 56 | 57 | Follow Step 1 in the [docs](https://developer.twitter.com/en/docs/basics/authentication/overview/application-only) to create the `Base64 encoded bearer token credentials` 58 | 59 | Add this Base64 encoded token to `assets/app.token.txt` 60 | 61 | 62 | ## Build the app in release mode (Android) 63 | 64 | To build the app in release mode for Android, you will need to provide two files: 65 | 66 | * `android/app/signing/release.keystore` 67 | * `android/app/signing/release.properties` 68 | 69 | The first file is a standard Android keystore file that is used to sign the application, 70 | while the properties file contains the informations necessary to access the keystore and 71 | sign the builds. 72 | 73 | If you don't provide these two files, the app building will fail when you try to build or 74 | run a release version. The debug signing configuration is provided in the Git repo and as 75 | such no configuration is necessary to run Android debug builds. 76 | 77 | ### Create a signing configuration for release 78 | 79 | To generate a keystore, you need the JDK's `keytool` on your path, then run from the 80 | project root: 81 | 82 | ```sh 83 | $ keytool -genkey -v -keystore android/app/signing/release.keystore \ 84 | -storepass "{✏️ YOUR STORE PASSWORD}" \ 85 | -alias "{✏️ YOUR SIGNING KEY NAME, e.g., 'dartconf'}" \ 86 | -keypass "{✏️ YOUR SIGNING KEY PASSWORD}" \ 87 | -keyalg RSA -validity 14000 88 | ``` 89 | 90 | This will generate the signing keystore in `android/app/signing/release.keystore`. 91 | Next, you will need a properties file containing the signing configuration. You can 92 | create one by running from the project root: 93 | 94 | ```sh 95 | $ tee android/app/signing/release.properties < \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /lib/src/feeds.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:async'; 6 | import 'dart:convert' as convert show json; 7 | import 'dart:developer' show log; 8 | 9 | import 'package:flutter/material.dart'; 10 | import 'package:flutter/services.dart'; 11 | import 'package:http/http.dart' as http; 12 | import 'package:intl/intl.dart'; 13 | import 'package:url_launcher/url_launcher.dart'; 14 | 15 | // TODO: New entries should animate in (see AnimatedList). 16 | // TODO: Periodically refresh the feed info. 17 | // TODO: We'll need to be aware of the default client rate limit (450). 18 | 19 | final FeedManager feedManager = new FeedManager(); 20 | 21 | const String searchQuery = '#dartconf OR #flutterio OR #angulardart'; 22 | 23 | class FeedsPage extends StatefulWidget { 24 | static const String title = 'Feeds'; 25 | static const IconData icon = Icons.rss_feed; 26 | 27 | @override 28 | _FeedsPageState createState() => new _FeedsPageState(); 29 | } 30 | 31 | class _FeedsPageState extends State { 32 | bool _disposed = false; 33 | 34 | List feeds; 35 | StreamSubscription sub; 36 | 37 | @override 38 | void initState() { 39 | super.initState(); 40 | 41 | this.feeds = feedManager.feeds; 42 | 43 | feedManager.onFeedsChanged.listen((feeds) { 44 | if (!_disposed) { 45 | setState(() { 46 | this.feeds = feeds; 47 | }); 48 | } 49 | }); 50 | } 51 | 52 | @override 53 | void dispose() { 54 | super.dispose(); 55 | 56 | sub?.cancel(); 57 | 58 | _disposed = true; 59 | } 60 | 61 | @override 62 | Widget build(BuildContext context) { 63 | Widget body; 64 | 65 | if (feedManager.feeds == null) { 66 | feedManager.load().catchError((e) { 67 | if (!_disposed) { 68 | setState(() { 69 | showSnackBar(context, '$e'); 70 | }); 71 | } 72 | }); 73 | } 74 | 75 | if (feedManager.feeds == null) { 76 | body = new Center( 77 | child: new CircularProgressIndicator(), 78 | ); 79 | } else { 80 | body = new ListView.builder( 81 | padding: const EdgeInsets.only(top: 8.0), 82 | itemCount: feedManager.feeds.length, 83 | itemBuilder: (BuildContext context, int index) { 84 | return new FeedWidget(feedManager.feeds[index]); 85 | }, 86 | ); 87 | } 88 | 89 | return new Scaffold( 90 | appBar: new AppBar( 91 | title: new Text(FeedsPage.title), 92 | automaticallyImplyLeading: false, 93 | ), 94 | body: new RefreshIndicator( 95 | onRefresh: () { 96 | return feedManager.refresh().catchError((e) { 97 | if (!_disposed) { 98 | setState(() { 99 | showSnackBar(context, '$e'); 100 | }); 101 | } 102 | }); 103 | }, 104 | child: body, 105 | ), 106 | ); 107 | } 108 | 109 | void showSnackBar(BuildContext context, String text) { 110 | final ScaffoldState scaffoldState = Scaffold.of(context); 111 | scaffoldState.showSnackBar(new SnackBar(content: new Text(text))); 112 | } 113 | } 114 | 115 | Padding _pad() => const Padding(padding: const EdgeInsets.all(4.0)); 116 | 117 | class FeedWidget extends StatelessWidget { 118 | static final TextStyle authorStyle = const TextStyle( 119 | fontSize: 16.0, 120 | fontWeight: FontWeight.w500, 121 | ); 122 | static final TextStyle dateStyle = const TextStyle( 123 | fontSize: 16.0, 124 | fontWeight: FontWeight.w300, 125 | ); 126 | static final TextStyle descStyle = const TextStyle(fontSize: 16.0); 127 | 128 | final Feed feed; 129 | 130 | FeedWidget(this.feed) : super(key: new ObjectKey(feed.id_str)); 131 | 132 | @override 133 | Widget build(BuildContext context) { 134 | final CircleAvatar avatar = 135 | new CircleAvatar(child: new Text(feed.avatarText)); 136 | 137 | final List topRow = [ 138 | new Expanded( 139 | child: new Text( 140 | '@${feed.user}' ?? '', 141 | style: authorStyle, 142 | ), 143 | ), 144 | _pad(), 145 | ]; 146 | 147 | if (feed.urls.isNotEmpty) { 148 | topRow.add(new IconButton( 149 | icon: new Icon(Icons.open_in_new), 150 | onPressed: () => launch(feed.urls.first), 151 | )); 152 | } 153 | 154 | final List bottomRow = [ 155 | new Expanded( 156 | child: new Text( 157 | feed.taggedDescription, 158 | style: dateStyle, 159 | maxLines: 1, 160 | overflow: TextOverflow.ellipsis, 161 | ), 162 | ), 163 | _pad(), 164 | new Text( 165 | feed.createdAtDescription ?? '', 166 | style: dateStyle, 167 | ), 168 | ]; 169 | 170 | if (feed.favorite_count > 0) { 171 | bottomRow.add( 172 | new Padding( 173 | padding: const EdgeInsets.only(left: 8.0), 174 | child: new Icon(Icons.thumb_up, size: 16.0), 175 | ), 176 | ); 177 | bottomRow.add( 178 | new Padding( 179 | padding: const EdgeInsets.only(left: 4.0), 180 | child: new Text(feed.favorite_count.toString()), 181 | ), 182 | ); 183 | } 184 | 185 | return new Container( 186 | padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), 187 | child: new Material( 188 | type: MaterialType.card, 189 | elevation: 1.0, 190 | child: new Column( 191 | crossAxisAlignment: CrossAxisAlignment.start, 192 | children: [ 193 | new Padding( 194 | padding: const EdgeInsets.all(8.0), 195 | child: new Column( 196 | crossAxisAlignment: CrossAxisAlignment.start, 197 | children: [ 198 | new Row( 199 | children: [ 200 | avatar, 201 | _pad(), 202 | new Expanded( 203 | child: new Column( 204 | children: [ 205 | new Row(children: topRow), 206 | ], 207 | crossAxisAlignment: CrossAxisAlignment.start, 208 | ), 209 | ), 210 | ], 211 | ), 212 | const Padding(padding: const EdgeInsets.all(4.0)), 213 | new Text(feed.text, style: descStyle), 214 | const Divider(), 215 | new Row(children: bottomRow) 216 | ], 217 | ), 218 | ), 219 | ], 220 | ), 221 | ), 222 | ); 223 | } 224 | } 225 | 226 | class Feed implements Comparable { 227 | static Feed parse(dynamic json) { 228 | return new Feed( 229 | id_str: json['id_str'], 230 | user: json['user']['screen_name'], 231 | text: json['text'], 232 | created_at: _parseDates(json['created_at']), 233 | hashtags: json['entities']['hashtags'] 234 | .map((h) => h['text'].toString()) 235 | .toList() 236 | .cast(), 237 | user_mentions: json['entities']['user_mentions'] 238 | .map((h) => h['screen_name'].toString()) 239 | .toList() 240 | .cast(), 241 | urls: json['entities']['urls'] 242 | .map((u) => u['url'].toString()) 243 | .toList() 244 | .cast(), 245 | favorite_count: json['favorite_count'], 246 | ); 247 | } 248 | 249 | // String twitterFormat="EEE MMM dd HH:mm:ss ZZZZZ yyyy" 250 | static DateFormat twitterDateFormat = 251 | new DateFormat('EEE MMM dd HH:mm:ss', 'en'); 252 | 253 | static DateTime _parseDates(String text) { 254 | if (text.contains('+')) { 255 | text = text.substring(0, text.indexOf('+')).trim(); 256 | } 257 | return twitterDateFormat.parse(text); 258 | } 259 | 260 | // These field names are deliberately kept the same as the twitter feed API. 261 | 262 | final String id_str; // ignore: non_constant_identifier_names 263 | final String user; 264 | final String text; 265 | final List hashtags; 266 | final List user_mentions; // ignore: non_constant_identifier_names 267 | final List urls; 268 | final int favorite_count; // ignore: non_constant_identifier_names 269 | final DateTime created_at; // ignore: non_constant_identifier_names 270 | 271 | Feed({ 272 | this.id_str, // ignore: non_constant_identifier_names 273 | this.user, 274 | this.text, 275 | this.created_at, // ignore: non_constant_identifier_names 276 | this.hashtags: const [], 277 | this.user_mentions: const [], // ignore: non_constant_identifier_names 278 | this.urls: const [], 279 | this.favorite_count: 0, // ignore: non_constant_identifier_names 280 | }); 281 | 282 | String get avatarText => user.substring(0, 1).toUpperCase(); 283 | 284 | @override 285 | bool operator ==(other) => other is Feed && id_str == other.id_str; 286 | 287 | @override 288 | int get hashCode => id_str.hashCode; 289 | 290 | static DateFormat dateFormat = new DateFormat('LLL d'); 291 | static DateFormat timeFormat = new DateFormat.jm(); 292 | 293 | String get createdAtDescription { 294 | return '${dateFormat.format(created_at)}'; 295 | } 296 | 297 | String get taggedDescription { 298 | List tags = hashtags.toList()..sort(); 299 | return tags.map((h) => '#$h').join(' ').toLowerCase(); 300 | } 301 | 302 | bool get hasUrl => urls.isNotEmpty; 303 | 304 | @override 305 | int compareTo(Feed other) { 306 | return other.created_at.compareTo(created_at); 307 | } 308 | } 309 | 310 | class FeedManager { 311 | final http.Client httpClient = new http.Client(); 312 | 313 | List feeds; 314 | 315 | StreamController> _feedController = 316 | new StreamController.broadcast(); 317 | Future _loadFuture; 318 | String _bearerToken; 319 | 320 | FeedManager(); 321 | 322 | Stream> get onFeedsChanged => _feedController.stream; 323 | 324 | Future> load() { 325 | if (_loadFuture != null) { 326 | return _loadFuture; 327 | } 328 | 329 | feeds ??= []; 330 | 331 | _loadFuture = _load(); 332 | 333 | _loadFuture.then((feeds) { 334 | this.feeds = feeds; 335 | _feedController.add(feeds); 336 | return feeds; 337 | }).whenComplete(() { 338 | _loadFuture = null; 339 | }); 340 | 341 | return _loadFuture; 342 | } 343 | 344 | Future> _load() async { 345 | final Future bundleData = 346 | rootBundle.loadString('assets/app.token.txt'); 347 | final String token = (await bundleData)?.trim(); 348 | 349 | http.Response response; 350 | 351 | response = await httpClient.post( 352 | 'https://api.twitter.com/oauth2/token', 353 | body: 'grant_type=client_credentials', 354 | headers: { 355 | 'Authorization': 'Basic $token', 356 | 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 357 | }, 358 | ); 359 | 360 | dynamic json; 361 | 362 | final String accessTokenData = response.body; 363 | json = convert.json.decode(accessTokenData); 364 | 365 | if (json is! Map) { 366 | throw 'Unexpected response from server.'; 367 | } 368 | 369 | // either: 370 | // {"token_type":"bearer","access_token":"..."} 371 | // or: 372 | // {"errors":[{"code":99,"message":"Unable to verify your credentials", 373 | // "label":"authenticity_token_error"}]} 374 | Map m = json; 375 | 376 | if (m.containsKey('errors')) { 377 | throw _parseError(m['errors']); 378 | } else { 379 | _bearerToken = m['access_token']; 380 | 381 | return _query(); 382 | } 383 | } 384 | 385 | Future> _query() async { 386 | final String encodedQuery = Uri.encodeComponent(searchQuery); 387 | 388 | http.Response response; 389 | 390 | response = await httpClient.get( 391 | 'https://api.twitter.com/1.1/search/tweets.json?q=$encodedQuery', 392 | headers: { 393 | 'Authorization': 'Bearer $_bearerToken', 394 | 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 395 | }, 396 | ); 397 | 398 | dynamic result = convert.json.decode(response.body); 399 | 400 | int rateLimit = int.parse(response.headers['x-rate-limit-limit'] ?? '0'); 401 | int limitRemaining = 402 | int.parse(response.headers['x-rate-limit-remaining'] ?? '0'); 403 | int limitReset = int.parse(response.headers['x-rate-limit-reset'] ?? '0'); 404 | int secondsLeft = 405 | (limitReset ?? 0) - (new DateTime.now().millisecondsSinceEpoch ~/ 1000); 406 | // Log the headers for the rate limiting. 407 | log('rate limit $limitRemaining / $rateLimit (reset in ${secondsLeft}s)', 408 | name: 'rateLimit'); 409 | 410 | if ((result as Map).containsKey('errors')) { 411 | throw _parseError(result['errors']); 412 | } 413 | 414 | List items = (result['statuses'] as List).map(Feed.parse).toList(); 415 | items.sort(); 416 | return items; 417 | } 418 | 419 | String _parseError(dynamic errors) { 420 | try { 421 | return errors[0]['message']; 422 | } catch (e) { 423 | return '$errors'; 424 | } 425 | } 426 | 427 | Future refresh() async { 428 | List feeds = await _query(); 429 | this.feeds = feeds; 430 | _feedController.add(feeds); 431 | } 432 | } 433 | -------------------------------------------------------------------------------- /lib/src/schedule.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:async'; 6 | 7 | import 'package:cloud_firestore/cloud_firestore.dart'; 8 | import 'package:flutter/material.dart'; 9 | import 'package:intl/intl.dart'; 10 | 11 | import 'common.dart'; 12 | 13 | // TODO: Handle missing images. 14 | // TODO: The scroll position isn't being remembered after returning from looking 15 | // at a specific session. 16 | 17 | class SchedulePage extends StatefulWidget { 18 | static const String title = 'Schedule'; 19 | static const IconData icon = Icons.access_time; 20 | 21 | SchedulePage({Key key}) : super(key: key); 22 | 23 | @override 24 | _SchedulePageState createState() => new _SchedulePageState(); 25 | } 26 | 27 | class _SchedulePageState extends State { 28 | static const int defaultDuration = 30; 29 | List allSessions; 30 | StreamSubscription sub; 31 | 32 | @override 33 | void initState() { 34 | super.initState(); 35 | 36 | final CollectionReference collection = 37 | Firestore.instance.collection('schedules'); 38 | sub = collection?.snapshots?.listen((QuerySnapshot snapshot) { 39 | setState(() { 40 | allSessions = snapshot.documents.map(_toSession).toList(); 41 | }); 42 | }); 43 | } 44 | 45 | @override 46 | void dispose() { 47 | super.dispose(); 48 | 49 | sub?.cancel(); 50 | } 51 | 52 | @override 53 | Widget build(BuildContext context) { 54 | if (allSessions == null) { 55 | return new DefaultTabController( 56 | length: 2, 57 | child: new Scaffold( 58 | appBar: new AppBar( 59 | title: new Text('DartConf 2018'), 60 | automaticallyImplyLeading: false, 61 | bottom: new TabBar( 62 | tabs: [ 63 | new Tab(text: 'JAN 23'), 64 | new Tab(text: 'JAN 24'), 65 | ], 66 | ), 67 | ), 68 | body: new Center( 69 | child: new CircularProgressIndicator(), 70 | ), 71 | ), 72 | ); 73 | } 74 | 75 | return new DefaultTabController( 76 | length: 2, 77 | child: new Scaffold( 78 | appBar: new AppBar( 79 | title: new Text('DartConf 2018'), 80 | automaticallyImplyLeading: false, 81 | bottom: new TabBar( 82 | tabs: [ 83 | new Tab(text: 'JAN 23'), 84 | new Tab(text: 'JAN 24'), 85 | ], 86 | ), 87 | ), 88 | body: new TabBarView( 89 | children: [ 90 | buildListForSessions( 91 | context, 92 | allSessions 93 | .where((Session session) => session.date.day == 23) 94 | .toList() 95 | ..sort(), 96 | ), 97 | buildListForSessions( 98 | context, 99 | allSessions 100 | .where((Session session) => session.date.day == 24) 101 | .toList() 102 | ..sort(), 103 | ), 104 | ], 105 | ), 106 | ), 107 | ); 108 | } 109 | 110 | Widget buildListForSessions( 111 | BuildContext context, Iterable sessions) { 112 | final List listSessions = sessions.toList(); 113 | 114 | return new ListView.builder( 115 | padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), 116 | itemCount: listSessions.length, 117 | itemBuilder: (BuildContext context, int index) { 118 | Session session = listSessions[index]; 119 | 120 | if (session.isDivider) { 121 | return new DividerCardWidget(session); 122 | } else { 123 | return new SessionCardWidget(session); 124 | } 125 | }, 126 | ); 127 | } 128 | 129 | static Session _toSession(DocumentSnapshot snapshot) { 130 | DateTime dateTime = snapshot['datetime'] == null 131 | ? new DateTime(2018, 1, 23) 132 | : DateTime.parse(snapshot['datetime']); 133 | 134 | return new Session( 135 | snapshot['title'], 136 | snapshot['description'], 137 | dateTime, 138 | new Duration(minutes: snapshot['duration'] ?? defaultDuration), 139 | presenters: snapshot['authors'], 140 | imageUrl: snapshot['image'], 141 | ); 142 | } 143 | } 144 | 145 | class Session implements Comparable { 146 | Session( 147 | this.title, 148 | this.description, 149 | this.date, 150 | this.duration, { 151 | this.presenters, 152 | this.imageUrl, 153 | }); 154 | 155 | final String title; 156 | 157 | // nullable 158 | final String description; 159 | 160 | final DateTime date; 161 | 162 | // nullable 163 | final Duration duration; 164 | final String presenters; 165 | 166 | final String imageUrl; 167 | 168 | bool get isDivider => 169 | imageUrl == null && description == null && presenters == null; 170 | 171 | String get presentersDescription => presenters ?? ''; 172 | 173 | // nullable 174 | TimeOfDay get time { 175 | if (date == null) { 176 | return null; 177 | } 178 | 179 | return new TimeOfDay(hour: date.hour, minute: date.minute); 180 | } 181 | 182 | String get id => 183 | '${title.replaceAll(' ', '_')}-${date.day}-${time.hour}-${time.minute}'; 184 | 185 | String get descriptionParagraphs => addParagraphs(description) ?? ''; 186 | 187 | String toString() => title; 188 | 189 | @override 190 | int compareTo(Session other) => date.compareTo(other.date); 191 | 192 | @override 193 | bool operator ==(other) => other is Session && id == other.id; 194 | 195 | @override 196 | int get hashCode => id.hashCode; 197 | } 198 | 199 | final TextStyle titleStyle = 200 | const TextStyle(fontSize: 20.0, fontWeight: FontWeight.w600); 201 | final TextStyle dividerTitleStyle = 202 | const TextStyle(fontSize: 18.0, fontWeight: FontWeight.w600); 203 | final TextStyle detailsStyle = 204 | const TextStyle(fontWeight: FontWeight.w600, color: Colors.black54); 205 | final TextStyle descStyle = const TextStyle(fontSize: 16.0); 206 | final TextStyle subduedDescStyle = 207 | const TextStyle(fontSize: 16.0, color: Colors.black54); 208 | 209 | class DividerCardWidget extends StatelessWidget { 210 | DividerCardWidget(this.session); 211 | 212 | final Session session; 213 | 214 | @override 215 | Widget build(BuildContext context) { 216 | final Card card = new Card( 217 | child: new Column( 218 | crossAxisAlignment: CrossAxisAlignment.stretch, 219 | children: [ 220 | new Padding( 221 | padding: const EdgeInsets.all(8.0), 222 | child: new Column( 223 | crossAxisAlignment: CrossAxisAlignment.stretch, 224 | children: [ 225 | new Text( 226 | session.title ?? '', 227 | style: dividerTitleStyle, 228 | softWrap: false, 229 | overflow: TextOverflow.ellipsis, 230 | ), 231 | const Divider(), 232 | new Row(children: [ 233 | new Expanded( 234 | child: new Text( 235 | session.time.format(context), 236 | style: detailsStyle, 237 | ), 238 | ), 239 | new Text( 240 | session.duration == null || session.duration.inMinutes == 0 241 | ? '' 242 | : '${session.duration.inMinutes} min', 243 | style: detailsStyle, 244 | ), 245 | ]) 246 | ], 247 | ), 248 | ), 249 | ], 250 | ), 251 | ); 252 | 253 | return new Padding( 254 | padding: const EdgeInsets.symmetric(vertical: 8.0), 255 | child: card, 256 | ); 257 | } 258 | } 259 | 260 | class SessionCardWidget extends StatelessWidget { 261 | SessionCardWidget(this.session); 262 | 263 | static final double height = 322.0; 264 | 265 | final Session session; 266 | 267 | @override 268 | Widget build(BuildContext context) { 269 | Image image; 270 | 271 | if (session.imageUrl != null) { 272 | image = new Image.network( 273 | session.imageUrl, 274 | fit: BoxFit.cover, 275 | ); 276 | } else { 277 | image = new Image.asset( 278 | 'assets/dartconf.png', 279 | fit: BoxFit.cover, 280 | ); 281 | } 282 | 283 | final Card card = new Card( 284 | child: new Column( 285 | crossAxisAlignment: CrossAxisAlignment.stretch, 286 | children: [ 287 | new Hero( 288 | tag: 'session/image/${session.id}', 289 | child: new ConstrainedBox( 290 | constraints: new BoxConstraints(maxHeight: 200.0), 291 | child: image, 292 | ), 293 | ), 294 | new Padding( 295 | padding: const EdgeInsets.all(8.0), 296 | child: new Column( 297 | crossAxisAlignment: CrossAxisAlignment.stretch, 298 | children: [ 299 | new Text( 300 | session.title ?? '', 301 | style: titleStyle, 302 | softWrap: false, 303 | overflow: TextOverflow.ellipsis, 304 | ), 305 | new Text( 306 | session.presentersDescription, 307 | style: descStyle, 308 | ), 309 | const Padding(padding: const EdgeInsets.only(top: 8.0)), 310 | new Text( 311 | session.description ?? '', 312 | style: descStyle, 313 | maxLines: 3, 314 | overflow: TextOverflow.ellipsis, 315 | ), 316 | const Divider(), 317 | new Row( 318 | children: [ 319 | new Expanded( 320 | child: new Text(session.time.format(context), 321 | style: detailsStyle), 322 | ), 323 | new Text( 324 | session.duration == null || 325 | session.duration.inMinutes == 0 326 | ? '' 327 | : '${session.duration.inMinutes} min', 328 | style: detailsStyle, 329 | ) 330 | ], 331 | ), 332 | ], 333 | ), 334 | ), 335 | ], 336 | ), 337 | ); 338 | 339 | return new GestureDetector( 340 | onTap: () => showSessionPage(context, session), 341 | child: new Padding( 342 | padding: const EdgeInsets.symmetric(vertical: 8.0), 343 | child: card, 344 | ), 345 | ); 346 | } 347 | 348 | void showSessionPage(BuildContext context, Session session) { 349 | Navigator.push( 350 | context, 351 | new MaterialPageRoute( 352 | settings: const RouteSettings(name: '/sessions/session'), 353 | builder: (BuildContext context) { 354 | return new Theme( 355 | data: Theme.of(context), 356 | child: new SessionPage(session), 357 | ); 358 | }, 359 | ), 360 | ); 361 | } 362 | } 363 | 364 | class SessionPage extends StatelessWidget { 365 | static final dateFormat = new DateFormat.MMMd(); 366 | 367 | final Session session; 368 | 369 | SessionPage(this.session); 370 | 371 | @override 372 | Widget build(BuildContext context) { 373 | Image image; 374 | 375 | if (session.imageUrl != null) { 376 | image = new Image.network( 377 | session.imageUrl, 378 | fit: BoxFit.cover, 379 | ); 380 | } else { 381 | image = new Image.asset( 382 | 'assets/dartconf.png', 383 | fit: BoxFit.cover, 384 | ); 385 | } 386 | 387 | return new Scaffold( 388 | body: new CustomScrollView( 389 | slivers: [ 390 | new SliverAppBar( 391 | expandedHeight: 250.0, 392 | backgroundColor: Colors.transparent, 393 | flexibleSpace: new FlexibleSpaceBar( 394 | //title: const Text('Demo'), 395 | background: new Hero( 396 | tag: 'session/image/${session.id}', 397 | child: image, 398 | ), 399 | ), 400 | ), 401 | new SliverToBoxAdapter( 402 | child: new Padding( 403 | padding: new EdgeInsets.all(16.0), 404 | child: new Column( 405 | crossAxisAlignment: CrossAxisAlignment.start, 406 | children: [ 407 | new Text( 408 | session.title, 409 | style: titleStyle, 410 | ), 411 | new Text( 412 | session.presentersDescription, 413 | style: descStyle, 414 | ), 415 | new Text( 416 | '${dateFormat.format(session.date)}, ' 417 | '${session.time.format(context)}, ' 418 | '${session.duration.inMinutes} min', 419 | ), 420 | pad8(), 421 | new Text(session.descriptionParagraphs, style: descStyle), 422 | ], 423 | ), 424 | ), 425 | ), 426 | ], 427 | ), 428 | ); 429 | } 430 | } 431 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 14 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 15 | 45C907C22005C47C0099C12E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 45C907C12005C47C0099C12E /* GoogleService-Info.plist */; }; 16 | 4AF01BAC1FD353B2001A8288 /* (null) in Resources */ = {isa = PBXBuildFile; }; 17 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 18 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 19 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 20 | 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; }; 21 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 22 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 23 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 24 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 25 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 26 | 9CE301A189F6C0FAF8F3E8D5 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 89266BC5DB7913D9CD69ED0E /* libPods-Runner.a */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXCopyFilesBuildPhase section */ 30 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 31 | isa = PBXCopyFilesBuildPhase; 32 | buildActionMask = 2147483647; 33 | dstPath = ""; 34 | dstSubfolderSpec = 10; 35 | files = ( 36 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 37 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 38 | ); 39 | name = "Embed Frameworks"; 40 | runOnlyForDeploymentPostprocessing = 0; 41 | }; 42 | /* End PBXCopyFilesBuildPhase section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 46 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 47 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; 48 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 49 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 50 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 51 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 52 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 53 | 89266BC5DB7913D9CD69ED0E /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 55 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 56 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 57 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 59 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 60 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 61 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 62 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 71 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 72 | 9CE301A189F6C0FAF8F3E8D5 /* libPods-Runner.a in Frameworks */, 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | /* End PBXFrameworksBuildPhase section */ 77 | 78 | /* Begin PBXGroup section */ 79 | 2A505E8CCF27CBDD5441195D /* Pods */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | ); 83 | name = Pods; 84 | sourceTree = ""; 85 | }; 86 | 59C3E25A344F493E20148FBF /* Frameworks */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 89266BC5DB7913D9CD69ED0E /* libPods-Runner.a */, 90 | ); 91 | name = Frameworks; 92 | sourceTree = ""; 93 | }; 94 | 9740EEB11CF90186004384FC /* Flutter */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 3B80C3931E831B6300D905FE /* App.framework */, 98 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 99 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, 100 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 101 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 102 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 103 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 104 | ); 105 | name = Flutter; 106 | sourceTree = ""; 107 | }; 108 | 97C146E51CF9000F007C117D = { 109 | isa = PBXGroup; 110 | children = ( 111 | 9740EEB11CF90186004384FC /* Flutter */, 112 | 97C146F01CF9000F007C117D /* Runner */, 113 | 97C146EF1CF9000F007C117D /* Products */, 114 | 2A505E8CCF27CBDD5441195D /* Pods */, 115 | 59C3E25A344F493E20148FBF /* Frameworks */, 116 | ); 117 | sourceTree = ""; 118 | }; 119 | 97C146EF1CF9000F007C117D /* Products */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 97C146EE1CF9000F007C117D /* Runner.app */, 123 | ); 124 | name = Products; 125 | sourceTree = ""; 126 | }; 127 | 97C146F01CF9000F007C117D /* Runner */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 45C907C12005C47C0099C12E /* GoogleService-Info.plist */, 131 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 132 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 133 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 134 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 135 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 136 | 97C147021CF9000F007C117D /* Info.plist */, 137 | 97C146F11CF9000F007C117D /* Supporting Files */, 138 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 139 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 140 | ); 141 | path = Runner; 142 | sourceTree = ""; 143 | }; 144 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 97C146F21CF9000F007C117D /* main.m */, 148 | ); 149 | name = "Supporting Files"; 150 | sourceTree = ""; 151 | }; 152 | /* End PBXGroup section */ 153 | 154 | /* Begin PBXNativeTarget section */ 155 | 97C146ED1CF9000F007C117D /* Runner */ = { 156 | isa = PBXNativeTarget; 157 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 158 | buildPhases = ( 159 | EF005E14A8FB86604FA14D27 /* [CP] Check Pods Manifest.lock */, 160 | 9740EEB61CF901F6004384FC /* Run Script */, 161 | 97C146EA1CF9000F007C117D /* Sources */, 162 | 97C146EB1CF9000F007C117D /* Frameworks */, 163 | 97C146EC1CF9000F007C117D /* Resources */, 164 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 165 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 166 | 7BF156049221FF92587E7843 /* [CP] Embed Pods Frameworks */, 167 | 0BEE1B74E17759924AE181FE /* [CP] Copy Pods Resources */, 168 | ); 169 | buildRules = ( 170 | ); 171 | dependencies = ( 172 | ); 173 | name = Runner; 174 | productName = Runner; 175 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 176 | productType = "com.apple.product-type.application"; 177 | }; 178 | /* End PBXNativeTarget section */ 179 | 180 | /* Begin PBXProject section */ 181 | 97C146E61CF9000F007C117D /* Project object */ = { 182 | isa = PBXProject; 183 | attributes = { 184 | LastUpgradeCheck = 0910; 185 | ORGANIZATIONNAME = "The Chromium Authors"; 186 | TargetAttributes = { 187 | 97C146ED1CF9000F007C117D = { 188 | CreatedOnToolsVersion = 7.3.1; 189 | }; 190 | }; 191 | }; 192 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 193 | compatibilityVersion = "Xcode 3.2"; 194 | developmentRegion = English; 195 | hasScannedForEncodings = 0; 196 | knownRegions = ( 197 | en, 198 | Base, 199 | ); 200 | mainGroup = 97C146E51CF9000F007C117D; 201 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 202 | projectDirPath = ""; 203 | projectRoot = ""; 204 | targets = ( 205 | 97C146ED1CF9000F007C117D /* Runner */, 206 | ); 207 | }; 208 | /* End PBXProject section */ 209 | 210 | /* Begin PBXResourcesBuildPhase section */ 211 | 97C146EC1CF9000F007C117D /* Resources */ = { 212 | isa = PBXResourcesBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | 4AF01BAC1FD353B2001A8288 /* (null) in Resources */, 216 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 217 | 45C907C22005C47C0099C12E /* GoogleService-Info.plist in Resources */, 218 | 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */, 219 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 220 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 221 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 222 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 223 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | }; 227 | /* End PBXResourcesBuildPhase section */ 228 | 229 | /* Begin PBXShellScriptBuildPhase section */ 230 | 0BEE1B74E17759924AE181FE /* [CP] Copy Pods Resources */ = { 231 | isa = PBXShellScriptBuildPhase; 232 | buildActionMask = 2147483647; 233 | files = ( 234 | ); 235 | inputPaths = ( 236 | "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", 237 | $PODS_CONFIGURATION_BUILD_DIR/gRPC/gRPCCertificates.bundle, 238 | ); 239 | name = "[CP] Copy Pods Resources"; 240 | outputPaths = ( 241 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", 242 | ); 243 | runOnlyForDeploymentPostprocessing = 0; 244 | shellPath = /bin/sh; 245 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; 246 | showEnvVarsInLog = 0; 247 | }; 248 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 249 | isa = PBXShellScriptBuildPhase; 250 | buildActionMask = 2147483647; 251 | files = ( 252 | ); 253 | inputPaths = ( 254 | ); 255 | name = "Thin Binary"; 256 | outputPaths = ( 257 | ); 258 | runOnlyForDeploymentPostprocessing = 0; 259 | shellPath = /bin/sh; 260 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 261 | }; 262 | 7BF156049221FF92587E7843 /* [CP] Embed Pods Frameworks */ = { 263 | isa = PBXShellScriptBuildPhase; 264 | buildActionMask = 2147483647; 265 | files = ( 266 | ); 267 | inputPaths = ( 268 | "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", 269 | "${PODS_ROOT}/../../../../../flutter/flutter/bin/cache/artifacts/engine/ios/Flutter.framework", 270 | ); 271 | name = "[CP] Embed Pods Frameworks"; 272 | outputPaths = ( 273 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", 274 | ); 275 | runOnlyForDeploymentPostprocessing = 0; 276 | shellPath = /bin/sh; 277 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 278 | showEnvVarsInLog = 0; 279 | }; 280 | 9740EEB61CF901F6004384FC /* Run Script */ = { 281 | isa = PBXShellScriptBuildPhase; 282 | buildActionMask = 2147483647; 283 | files = ( 284 | ); 285 | inputPaths = ( 286 | ); 287 | name = "Run Script"; 288 | outputPaths = ( 289 | ); 290 | runOnlyForDeploymentPostprocessing = 0; 291 | shellPath = /bin/sh; 292 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 293 | }; 294 | EF005E14A8FB86604FA14D27 /* [CP] Check Pods Manifest.lock */ = { 295 | isa = PBXShellScriptBuildPhase; 296 | buildActionMask = 2147483647; 297 | files = ( 298 | ); 299 | inputPaths = ( 300 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 301 | "${PODS_ROOT}/Manifest.lock", 302 | ); 303 | name = "[CP] Check Pods Manifest.lock"; 304 | outputPaths = ( 305 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | shellPath = /bin/sh; 309 | 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"; 310 | showEnvVarsInLog = 0; 311 | }; 312 | /* End PBXShellScriptBuildPhase section */ 313 | 314 | /* Begin PBXSourcesBuildPhase section */ 315 | 97C146EA1CF9000F007C117D /* Sources */ = { 316 | isa = PBXSourcesBuildPhase; 317 | buildActionMask = 2147483647; 318 | files = ( 319 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 320 | 97C146F31CF9000F007C117D /* main.m in Sources */, 321 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 322 | ); 323 | runOnlyForDeploymentPostprocessing = 0; 324 | }; 325 | /* End PBXSourcesBuildPhase section */ 326 | 327 | /* Begin PBXVariantGroup section */ 328 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 329 | isa = PBXVariantGroup; 330 | children = ( 331 | 97C146FB1CF9000F007C117D /* Base */, 332 | ); 333 | name = Main.storyboard; 334 | sourceTree = ""; 335 | }; 336 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 337 | isa = PBXVariantGroup; 338 | children = ( 339 | 97C147001CF9000F007C117D /* Base */, 340 | ); 341 | name = LaunchScreen.storyboard; 342 | sourceTree = ""; 343 | }; 344 | /* End PBXVariantGroup section */ 345 | 346 | /* Begin XCBuildConfiguration section */ 347 | 97C147031CF9000F007C117D /* Debug */ = { 348 | isa = XCBuildConfiguration; 349 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 350 | buildSettings = { 351 | ALWAYS_SEARCH_USER_PATHS = NO; 352 | CLANG_ANALYZER_NONNULL = YES; 353 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 354 | CLANG_CXX_LIBRARY = "libc++"; 355 | CLANG_ENABLE_MODULES = YES; 356 | CLANG_ENABLE_OBJC_ARC = YES; 357 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 358 | CLANG_WARN_BOOL_CONVERSION = YES; 359 | CLANG_WARN_COMMA = YES; 360 | CLANG_WARN_CONSTANT_CONVERSION = YES; 361 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 362 | CLANG_WARN_EMPTY_BODY = YES; 363 | CLANG_WARN_ENUM_CONVERSION = YES; 364 | CLANG_WARN_INFINITE_RECURSION = YES; 365 | CLANG_WARN_INT_CONVERSION = YES; 366 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 367 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 368 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 369 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 370 | CLANG_WARN_STRICT_PROTOTYPES = YES; 371 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 372 | CLANG_WARN_UNREACHABLE_CODE = YES; 373 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 374 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 375 | COPY_PHASE_STRIP = NO; 376 | DEBUG_INFORMATION_FORMAT = dwarf; 377 | ENABLE_STRICT_OBJC_MSGSEND = YES; 378 | ENABLE_TESTABILITY = YES; 379 | GCC_C_LANGUAGE_STANDARD = gnu99; 380 | GCC_DYNAMIC_NO_PIC = NO; 381 | GCC_NO_COMMON_BLOCKS = YES; 382 | GCC_OPTIMIZATION_LEVEL = 0; 383 | GCC_PREPROCESSOR_DEFINITIONS = ( 384 | "DEBUG=1", 385 | "$(inherited)", 386 | ); 387 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 388 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 389 | GCC_WARN_UNDECLARED_SELECTOR = YES; 390 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 391 | GCC_WARN_UNUSED_FUNCTION = YES; 392 | GCC_WARN_UNUSED_VARIABLE = YES; 393 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 394 | MTL_ENABLE_DEBUG_INFO = YES; 395 | ONLY_ACTIVE_ARCH = YES; 396 | SDKROOT = iphoneos; 397 | TARGETED_DEVICE_FAMILY = "1,2"; 398 | }; 399 | name = Debug; 400 | }; 401 | 97C147041CF9000F007C117D /* Release */ = { 402 | isa = XCBuildConfiguration; 403 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 404 | buildSettings = { 405 | ALWAYS_SEARCH_USER_PATHS = NO; 406 | CLANG_ANALYZER_NONNULL = YES; 407 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 408 | CLANG_CXX_LIBRARY = "libc++"; 409 | CLANG_ENABLE_MODULES = YES; 410 | CLANG_ENABLE_OBJC_ARC = YES; 411 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 412 | CLANG_WARN_BOOL_CONVERSION = YES; 413 | CLANG_WARN_COMMA = YES; 414 | CLANG_WARN_CONSTANT_CONVERSION = YES; 415 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 416 | CLANG_WARN_EMPTY_BODY = YES; 417 | CLANG_WARN_ENUM_CONVERSION = YES; 418 | CLANG_WARN_INFINITE_RECURSION = YES; 419 | CLANG_WARN_INT_CONVERSION = YES; 420 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 421 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 422 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 423 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 424 | CLANG_WARN_STRICT_PROTOTYPES = YES; 425 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 426 | CLANG_WARN_UNREACHABLE_CODE = YES; 427 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 428 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 429 | COPY_PHASE_STRIP = NO; 430 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 431 | ENABLE_NS_ASSERTIONS = NO; 432 | ENABLE_STRICT_OBJC_MSGSEND = YES; 433 | GCC_C_LANGUAGE_STANDARD = gnu99; 434 | GCC_NO_COMMON_BLOCKS = YES; 435 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 436 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 437 | GCC_WARN_UNDECLARED_SELECTOR = YES; 438 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 439 | GCC_WARN_UNUSED_FUNCTION = YES; 440 | GCC_WARN_UNUSED_VARIABLE = YES; 441 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 442 | MTL_ENABLE_DEBUG_INFO = NO; 443 | SDKROOT = iphoneos; 444 | TARGETED_DEVICE_FAMILY = "1,2"; 445 | VALIDATE_PRODUCT = YES; 446 | }; 447 | name = Release; 448 | }; 449 | 97C147061CF9000F007C117D /* Debug */ = { 450 | isa = XCBuildConfiguration; 451 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 452 | buildSettings = { 453 | ARCHS = arm64; 454 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 455 | ENABLE_BITCODE = NO; 456 | FRAMEWORK_SEARCH_PATHS = ( 457 | "$(inherited)", 458 | "$(PROJECT_DIR)/Flutter", 459 | ); 460 | INFOPLIST_FILE = Runner/Info.plist; 461 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 462 | LIBRARY_SEARCH_PATHS = ( 463 | "$(inherited)", 464 | "$(PROJECT_DIR)/Flutter", 465 | ); 466 | PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.dartConf; 467 | PRODUCT_NAME = "$(TARGET_NAME)"; 468 | }; 469 | name = Debug; 470 | }; 471 | 97C147071CF9000F007C117D /* Release */ = { 472 | isa = XCBuildConfiguration; 473 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 474 | buildSettings = { 475 | ARCHS = arm64; 476 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 477 | ENABLE_BITCODE = NO; 478 | FRAMEWORK_SEARCH_PATHS = ( 479 | "$(inherited)", 480 | "$(PROJECT_DIR)/Flutter", 481 | ); 482 | INFOPLIST_FILE = Runner/Info.plist; 483 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 484 | LIBRARY_SEARCH_PATHS = ( 485 | "$(inherited)", 486 | "$(PROJECT_DIR)/Flutter", 487 | ); 488 | PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.dartConf; 489 | PRODUCT_NAME = "$(TARGET_NAME)"; 490 | }; 491 | name = Release; 492 | }; 493 | /* End XCBuildConfiguration section */ 494 | 495 | /* Begin XCConfigurationList section */ 496 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 497 | isa = XCConfigurationList; 498 | buildConfigurations = ( 499 | 97C147031CF9000F007C117D /* Debug */, 500 | 97C147041CF9000F007C117D /* Release */, 501 | ); 502 | defaultConfigurationIsVisible = 0; 503 | defaultConfigurationName = Release; 504 | }; 505 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 506 | isa = XCConfigurationList; 507 | buildConfigurations = ( 508 | 97C147061CF9000F007C117D /* Debug */, 509 | 97C147071CF9000F007C117D /* Release */, 510 | ); 511 | defaultConfigurationIsVisible = 0; 512 | defaultConfigurationName = Release; 513 | }; 514 | /* End XCConfigurationList section */ 515 | }; 516 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 517 | } 518 | --------------------------------------------------------------------------------