├── .gitignore
├── .metadata
├── README.md
├── android
├── app
│ ├── build.gradle
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ └── com
│ │ │ └── flutterkhi
│ │ │ └── app
│ │ │ └── flutterpk
│ │ │ └── MainActivity.kt
│ │ └── res
│ │ ├── drawable
│ │ └── launch_background.xml
│ │ ├── 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
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
├── feature.png
├── flutterKarachi.png
├── ic_person.png
├── ic_phone_setup.png
├── icon
│ └── icon.png
├── loader.png
└── map.png
├── data
├── convert.dart
└── firebase-export.json
├── ios
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ └── contents.xcworkspacedata
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── 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
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── lib
├── caches
│ ├── EventDate.dart
│ ├── location.dart
│ └── user.dart
├── contribution
│ └── contribution_dialog.dart
├── dialogs
│ └── custom_error_dialog.dart
├── feedback
│ └── feedback.dart
├── global.dart
├── helpers
│ ├── formatters.dart
│ ├── regex-helpers.dart
│ └── shared_preferences.dart
├── home
│ ├── home_master.dart
│ ├── login.dart
│ └── onboarding.dart
├── main.dart
├── profile
│ └── profile_dialog.dart
├── registration
│ └── registration.dart
├── schedule
│ ├── model.dart
│ ├── schedule_page.dart
│ └── session_detail.dart
├── theme.dart
├── util.dart
├── venue_detail.dart
├── venue_model.dart
└── widgets
│ ├── capsule_text.dart
│ ├── custom_app_bar.dart
│ ├── dots_indicator.dart
│ ├── full_screen_loader.dart
│ └── sprung_box.dart
├── pubspec.yaml
└── test
└── widget_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.lock
4 | *.log
5 | *.pyc
6 | *.swp
7 | .DS_Store
8 | .atom/
9 | .buildlog/
10 | .history
11 | .svn/
12 |
13 | # IntelliJ related
14 | *.iml
15 | *.ipr
16 | *.iws
17 | .idea/
18 |
19 | # Visual Studio Code related
20 | .vscode/
21 |
22 | # Flutter/Dart/Pub related
23 | **/doc/api/
24 | .dart_tool/
25 | .flutter-plugins
26 | .packages
27 | .pub-cache/
28 | .pub/
29 | build/
30 |
31 | # Android related
32 | **/android/**/gradle-wrapper.jar
33 | **/android/.gradle
34 | **/android/captures/
35 | **/android/gradlew
36 | **/android/gradlew.bat
37 | **/android/local.properties
38 | **/android/**/GeneratedPluginRegistrant.java
39 | **/android/app/google-services.json
40 |
41 | # iOS/XCode related
42 | **/ios/**/*.mode1v3
43 | **/ios/**/*.mode2v3
44 | **/ios/**/*.moved-aside
45 | **/ios/**/*.pbxuser
46 | **/ios/**/*.perspectivev3
47 | **/ios/**/*sync/
48 | **/ios/**/.sconsign.dblite
49 | **/ios/**/.tags*
50 | **/ios/**/.vagrant/
51 | **/ios/**/DerivedData/
52 | **/ios/**/Icon?
53 | **/ios/**/Pods/
54 | **/ios/**/.symlinks/
55 | **/ios/**/profile
56 | **/ios/**/xcuserdata
57 | **/ios/.generated/
58 | **/ios/Flutter/App.framework
59 | **/ios/Flutter/Flutter.framework
60 | **/ios/Flutter/Generated.xcconfig
61 | **/ios/Flutter/app.flx
62 | **/ios/Flutter/app.zip
63 | **/ios/Flutter/flutter_assets/
64 | **/ios/ServiceDefinitions.json
65 | **/ios/Runner/GeneratedPluginRegistrant.*
66 | **/ios/Runner/GoogleService-Info.plist
67 |
68 |
69 | # Exceptions to above rules.
70 | !**/ios/**/default.mode1v3
71 | !**/ios/**/default.mode2v3
72 | !**/ios/**/default.pbxuser
73 | !**/ios/**/default.perspectivev3
74 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
75 |
--------------------------------------------------------------------------------
/.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: 4cd87705b7e13783da99356a820728c9d3f95130
8 | channel: master
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter Pakistan App
2 | Flutter Live Extended is organized by Flutter Pakistan community in Karachi and it is based on Flutter Live event.
3 |
4 | This project is the Flutter app for the event. Feel free to fork this repo to customize the app for your own event.
5 |
6 | ## Inspiration
7 | The app takes a lot from [Google I/O Android app](https://github.com/google/iosched) while trimming down the stuff that was not needed. It also adds a few features as described in next section.
8 |
9 | # Features
10 | The app displays a list of sessions with an option to see the details about sessions and speakers. Users can also register for the event using the app and at event day, it lets users mark their attendance using QR code. The app uses Google Sign-in to fetch user details and to enable event registration through the app.
11 |
12 | The app also displays a map of the venue with an option to navigate using the installed maps app.
13 |
14 | # Development Environment
15 | The app is written entirely in Flutter and should compile and run on stable Flutter versions (tested till 1.2).
16 |
17 | ## Firebase
18 | The app makes considerable use of following Firebase components:
19 | * [Cloud Firestore](https://firebase.google.com/docs/firestore/) is the source of all data being shown on the app including session and speaker details, and user registration.
20 | * [Firebase Authentication](https://firebase.google.com/docs/auth/) is used to let the user sign-in using their Google ID.
21 |
22 | ### Setting up
23 | This repo does not contain some required Firebase setup. Follow [this guide](https://firebase.google.com/docs/flutter/setup) to setup Cloud Firestore for this app. There's also a good [video walkthrough](https://www.youtube.com/watch?v=DqJ_KjFzL9I) for setting up.
24 |
25 | ### Importing Firebase data
26 | The app depends on an already setup Firestore data in order to run properly which is present in `/data/firebase-export.json`. To import this data, follow these steps:
27 | 1. Install [Firestore Import/Export utility](https://www.npmjs.com/package/node-firestore-import-export)
28 | 2. [Export your Firebase private key](https://www.npmjs.com/package/node-firestore-import-export#retrieving-google-cloud-account-credentials), it will be automatically downloaded to your computer. Copy this file to the `/data` folder. Rename this file to `firebase-credentials.json`.
29 | 3. Open terminal and go to `/data` folder.
30 | 4. Run the following command
31 | ```
32 | $ firestore-import -a firebase-credentials.json -b firebase-export.json
33 | ```
34 | 5. After this command is executed successfully, go to your Database section of your Firebase console to make sure that the data is created there.
35 |
36 | ### Exporting Firebase data
37 | You can also export Firestore data using the following command:
38 | ```
39 | $ firestore-export -a firebase-credentials.json -b firebase-export.json -p
40 | ```
41 | This will export the data into `firebase-export.json` file.
42 |
43 | One common use case is to get all users and export them to CSV. There's a Dart script included in the `data` folder and it can be used as shown below:
44 | ```
45 | $ dart convert.dart firebase-export.json
46 | ```
47 | This will create an `export.csv` in the same folder which you can then use with Microsoft Excel, Google Sheets etc.
48 |
49 | # Getting started with Flutter
50 | A few resources to get you started if this is your first Flutter project:
51 |
52 | - [Lab: Write your first Flutter app](https://flutter.io/docs/get-started/codelab)
53 | - [Cookbook: Useful Flutter samples](https://flutter.io/docs/cookbook)
54 |
55 | For help getting started with Flutter, view our
56 | [online documentation](https://flutter.io/docs), which offers tutorials,
57 | samples, guidance on mobile development, and a full API reference.
58 |
59 | # Copyright
60 |
61 | ```
62 | Copyright 2019 Flutter Pakistan. All rights reserved.
63 |
64 | Licensed under the Apache License, Version 2.0 (the "License");
65 | you may not use this file except in compliance with the License.
66 | You may obtain a copy of the License at
67 |
68 | http://www.apache.org/licenses/LICENSE-2.0
69 |
70 | Unless required by applicable law or agreed to in writing, software
71 | distributed under the License is distributed on an "AS IS" BASIS,
72 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
73 | See the License for the specific language governing permissions and
74 | limitations under the License.
75 | ```
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
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 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 28
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
41 | applicationId "com.flutterkhi.app.flutterpk"
42 | minSdkVersion 16
43 | targetSdkVersion 27
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
47 | multiDexEnabled true
48 | }
49 |
50 | buildTypes {
51 | release {
52 | // TODO: Add your own signing config for the release build.
53 | // Signing with the debug keys for now, so `flutter run --release` works.
54 | signingConfig signingConfigs.debug
55 | }
56 | }
57 | }
58 |
59 | flutter {
60 | source '../..'
61 | }
62 |
63 | dependencies {
64 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
65 | implementation "android.arch.core:runtime:1.1.1"
66 | implementation "android.arch.core:common:1.1.1"
67 | implementation 'com.android.support:multidex:1.0.3'
68 | testImplementation 'junit:junit:4.12'
69 | androidTestImplementation 'androidx.test:runner:1.1.0'
70 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
71 | }
72 | apply plugin: 'com.google.gms.google-services'
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
8 |
9 |
10 |
15 |
19 |
21 |
28 |
32 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/flutterkhi/app/flutterpk/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.flutterkhi.app.flutterpk
2 |
3 | import android.os.Bundle
4 |
5 | import io.flutter.app.FlutterActivity
6 | import io.flutter.plugins.GeneratedPluginRegistrant
7 |
8 | class MainActivity: FlutterActivity() {
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 | GeneratedPluginRegistrant.registerWith(this)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.21'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.3.0'
10 | classpath 'com.google.gms:google-services:4.2.0'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | }
20 | }
21 |
22 | rootProject.buildDir = '../build'
23 | subprojects {
24 | project.buildDir = "${rootProject.buildDir}/${project.name}"
25 | }
26 | subprojects {
27 | project.evaluationDependsOn(':app')
28 | }
29 |
30 | task clean(type: Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.0-all.zip
7 |
--------------------------------------------------------------------------------
/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.withReader('UTF-8') { reader -> plugins.load(reader) }
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 |
--------------------------------------------------------------------------------
/assets/feature.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/assets/feature.png
--------------------------------------------------------------------------------
/assets/flutterKarachi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/assets/flutterKarachi.png
--------------------------------------------------------------------------------
/assets/ic_person.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/assets/ic_person.png
--------------------------------------------------------------------------------
/assets/ic_phone_setup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/assets/ic_phone_setup.png
--------------------------------------------------------------------------------
/assets/icon/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/assets/icon/icon.png
--------------------------------------------------------------------------------
/assets/loader.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/assets/loader.png
--------------------------------------------------------------------------------
/assets/map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/assets/map.png
--------------------------------------------------------------------------------
/data/convert.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 | import 'dart:io';
3 |
4 | void main(List args) {
5 | var file = File.fromUri(Uri.parse(args[0]));
6 | print('Reading file: ${file.path}');
7 | var content = file.readAsStringSync();
8 | var data = json.decode(content);
9 | var users = data['__collections__']['users'] as Map;
10 | print('Total users: ${users.keys.length}');
11 |
12 | var lines = [];
13 | lines.add(
14 | 'name,email,phone,is_present,is_registered,designation,occupation,institute_work,contribution');
15 | for (String key in users.keys) {
16 | var user = users[key];
17 |
18 | if (user['email'] == null) continue;
19 |
20 | var values = [
21 | user['name'],
22 | user['email'],
23 | user['mobileNumber'],
24 | (user['isPresent'] as bool).toString(),
25 | (user['isRegistered'] as bool).toString(),
26 | user['registration'] == null ? '' : user['registration']['designation'],
27 | user['registration'] == null ? '' : user['registration']['occupation'],
28 | user['registration'] == null
29 | ? ''
30 | : user['registration']['workOrInstitute'],
31 | user['contribution'] == null ? '' : user['contribution'].toString(),
32 | ];
33 | var line = values.join(',');
34 | print(line);
35 | lines.add(line);
36 | }
37 |
38 | print('Writing ${lines.length} records to file');
39 | var outFile = File.fromUri(Uri.parse('export.csv'));
40 | outFile.createSync();
41 | outFile.writeAsStringSync(lines.join('\r\n'));
42 |
43 | print('Done');
44 | }
45 |
--------------------------------------------------------------------------------
/data/firebase-export.json:
--------------------------------------------------------------------------------
1 | {
2 | "__collections__": {
3 | "attendance": {
4 | "16032019": {
5 | "attendanceCount": 0,
6 | "__collections__": {
7 | "attendees": {}
8 | }
9 | }
10 | },
11 | "dates": {
12 | "WJqsWCMmpTga6K4sbNz0": {
13 | "date": {
14 | "__datatype__": "timestamp",
15 | "value": {
16 | "_seconds": 1552676400,
17 | "_nanoseconds": 0
18 | }
19 | },
20 | "eventTitle": "Flutter live extended '19",
21 | "venue": {
22 | "location": {
23 | "latitude": 24.86369,
24 | "longitude": 67.075474
25 | },
26 | "title": "10Pearls",
27 | "city": "Karachi",
28 | "imageUrl": "https://pakvocation.com/wp-content/uploads/2017/12/10PEARLS.png",
29 | "address": "8th floor, Parsa Tower, Main Shahrah-e-Faisal, Karachi"
30 | },
31 | "__collections__": {
32 | "sessions": {
33 | "Q2a930CWsxrTU3aXjBbK": {
34 | "id": "pairCode",
35 | "speakers": [
36 | "sana",
37 | "taha"
38 | ],
39 | "startDateTime": {
40 | "__datatype__": "timestamp",
41 | "value": {
42 | "_seconds": 1552717500,
43 | "_nanoseconds": 0
44 | }
45 | },
46 | "speakerId": "taha",
47 | "title": "Flutter development - Live code",
48 | "endDateTime": {
49 | "__datatype__": "timestamp",
50 | "value": {
51 | "_seconds": 1552719600,
52 | "_nanoseconds": 0
53 | }
54 | },
55 | "color": "teal",
56 | "description": "A live code action by two Flutter developers, showcasing the delightful development experience while creating a complete application.",
57 | "textColor": "white",
58 | "__collections__": {}
59 | },
60 | "SDhaXrZZyMrVxLMVtWLM": {
61 | "textColor": "white",
62 | "id": "dart",
63 | "speakers": [
64 | "waleed"
65 | ],
66 | "startDateTime": {
67 | "__datatype__": "timestamp",
68 | "value": {
69 | "_seconds": 1552714500,
70 | "_nanoseconds": 0
71 | }
72 | },
73 | "speakerId": "waleed",
74 | "title": "Design with Flutter",
75 | "endDateTime": {
76 | "__datatype__": "timestamp",
77 | "value": {
78 | "_seconds": 1552716900,
79 | "_nanoseconds": 0
80 | }
81 | },
82 | "color": "blueGrey",
83 | "description": "A talk on how Flutter goes a step ahead in helping designers get along with developers in order to achieve rapid development.",
84 | "__collections__": {}
85 | },
86 | "ZmOtQvgTqbbpcq0OsT3z": {
87 | "endDateTime": {
88 | "__datatype__": "timestamp",
89 | "value": {
90 | "_seconds": 1552735800,
91 | "_nanoseconds": 0
92 | }
93 | },
94 | "color": "brown",
95 | "description": "Live code a UI on Flutter. UI challenge will be given and the attendees will be coding the UI then and there!",
96 | "textColor": "white",
97 | "id": "uiChallenge",
98 | "speakers": [
99 | "auby",
100 | "waleed"
101 | ],
102 | "startDateTime": {
103 | "__datatype__": "timestamp",
104 | "value": {
105 | "_seconds": 1552726800,
106 | "_nanoseconds": 0
107 | }
108 | },
109 | "speakerId": "waleed",
110 | "title": "Flutter UI challenge",
111 | "__collections__": {}
112 | },
113 | "jjerkNAOg54TZErlH91p": {
114 | "id": "break",
115 | "startDateTime": {
116 | "__datatype__": "timestamp",
117 | "value": {
118 | "_seconds": 1552723200,
119 | "_nanoseconds": 0
120 | }
121 | },
122 | "title": "Prayer & refreshments",
123 | "endDateTime": {
124 | "__datatype__": "timestamp",
125 | "value": {
126 | "_seconds": 1552726800,
127 | "_nanoseconds": 0
128 | }
129 | },
130 | "color": "amber",
131 | "textColor": "black",
132 | "__collections__": {}
133 | },
134 | "vsTQp4eUDeEMdlYhH6hz": {
135 | "speakers": [
136 | "waheeda",
137 | "hussain"
138 | ],
139 | "startDateTime": {
140 | "__datatype__": "timestamp",
141 | "value": {
142 | "_seconds": 1552719900,
143 | "_nanoseconds": 0
144 | }
145 | },
146 | "speakerId": "waheeda",
147 | "title": "CI/CD with Codemagic",
148 | "endDateTime": {
149 | "__datatype__": "timestamp",
150 | "value": {
151 | "_seconds": 1552721700,
152 | "_nanoseconds": 0
153 | }
154 | },
155 | "color": "lightBlue",
156 | "description": "An introduction and hands on, on how Codemagic helps flutter developers achieve continuous integration and continuous delivery.",
157 | "textColor": "white",
158 | "id": "cicd",
159 | "__collections__": {}
160 | },
161 | "y9bKNPQoYIxt3zRB31PZ": {
162 | "id": "end",
163 | "speakers": [
164 | "auby"
165 | ],
166 | "startDateTime": {
167 | "__datatype__": "timestamp",
168 | "value": {
169 | "_seconds": 1552722000,
170 | "_nanoseconds": 0
171 | }
172 | },
173 | "speakerId": "auby",
174 | "title": "Ending note",
175 | "endDateTime": {
176 | "__datatype__": "timestamp",
177 | "value": {
178 | "_seconds": 1552723200,
179 | "_nanoseconds": 0
180 | }
181 | },
182 | "color": "indigoAccent",
183 | "description": "Some valuable announcements and updates about the next events.",
184 | "textColor": "white",
185 | "__collections__": {}
186 | },
187 | "yvAhvc07yrZwjIX9pIdK": {
188 | "textColor": "white",
189 | "id": "keynote",
190 | "speakers": [
191 | "auby"
192 | ],
193 | "startDateTime": {
194 | "__datatype__": "timestamp",
195 | "value": {
196 | "_seconds": 1552712400,
197 | "_nanoseconds": 0
198 | }
199 | },
200 | "speakerId": "auby",
201 | "title": "Keynote - introduction",
202 | "endDateTime": {
203 | "__datatype__": "timestamp",
204 | "value": {
205 | "_seconds": 1552714200,
206 | "_nanoseconds": 0
207 | }
208 | },
209 | "color": "green",
210 | "description": "Learn about the latest product and platform innovations at Flutter Live Extended Keynote led by Asadullah Bin Yousuf.",
211 | "__collections__": {}
212 | }
213 | }
214 | }
215 | }
216 | },
217 | "speakers": {
218 | "auby": {
219 | "photoUrl": "https://media.licdn.com/dms/image/C5603AQGLlMu1gNs1Vg/profile-displayphoto-shrink_200_200/0?e=1553126400&v=beta&t=0pGeAs9jYDYdyEnwqhwzdMxLECM-RsGVXqVezRbA0BM",
220 | "name": "Asadullah bin Yousuf",
221 | "description": "Asadullah is generally seen as a tech advocate and he has a passion to build high-quality software products. Mobile app is one of his focus areas and he has ample experience for developing on both major platforms i.e. iOS and Android. He is an active member of the global Flutter community and contributes through Medium articles, twitter, and community talks.",
222 | "__collections__": {}
223 | },
224 | "hussain": {
225 | "photoUrl": "https://media.licdn.com/dms/image/C4E03AQGbcgyRLHMQZQ/profile-displayphoto-shrink_800_800/0?e=1557360000&v=beta&t=VDRNZXn_BqYKP0FWx9T10luqh7n2tT9P_z373QFdHSQ",
226 | "name": "Hussain Marvi",
227 | "description": "Hussain Marvi has been associated with 10Pearls as a Senior Software Developer for 3 years and has an industry experience of more than 5 years. He’s been developing mobile apps using cutting-edge cross-platform mobile technologies like Xamarin, React Native, Flutter and Native Android apps. ",
228 | "__collections__": {}
229 | },
230 | "sana": {
231 | "description": "Sana Zehra is a software engineer involved in designing and development of software products. She is a lifelong learner and a technology enthusiast; with her experience in various back end technologies and cloud platform, she is involved in developing payment processing products at TPS Pakistan.",
232 | "photoUrl": "https://media.licdn.com/dms/image/C4D03AQHl0iIo5VYg5Q/profile-displayphoto-shrink_800_800/0?e=1556755200&v=beta&t=rkFpZZyQmw1IhM_g5Weu_wl9f3mnwTW2YAo_cTyZU3k",
233 | "name": "Sana Zehra",
234 | "__collections__": {}
235 | },
236 | "taha": {
237 | "description": "Taha develops leading edge digital financial services based mobile applications at TPS Pakistan. He is a technology enthusiast, has good taste in design and loves problem solving. At present he is beginning to give back to community.",
238 | "photoUrl": "https://farm8.staticflickr.com/7882/46360905165_91bfebb04a_m.jpg",
239 | "name": "Syed Taha Ali",
240 | "__collections__": {}
241 | },
242 | "waheeda": {
243 | "photoUrl": "https://drive.google.com/file/d/1M_tWrSGdAL9H7egFFHOHql3esEaFnZEB/view",
244 | "name": "Waheeda Ghani",
245 | "description": "Waheeda Ghani is part of the IT industry for more than 10 years. She has worked on Native iOS apps and some cross platform technologies including Xamarin, React Native, and Flutter. She also worked on gaming platforms like Unity 3D and Cocos2d. She is currently working at 10Pearls as a Technical Lead. ",
246 | "__collections__": {}
247 | },
248 | "waleed": {
249 | "photoUrl": "https://media.licdn.com/dms/image/C4E03AQEjyERQaPjT7g/profile-displayphoto-shrink_800_800/0?e=1557360000&v=beta&t=BRPeTP8fS9Xl7ujmiUqt9-eajcio8C0ixKo5XGTrEVs",
250 | "name": "Waleed Arshad",
251 | "description": "Waleed Arshad is a mobile technologist, a core developer and one of the youngest contributor to Flutter global community in Pakistan. He mainly focuses on developing cross-platform mobile applications for both iOS and Android, and is inclined towards consistently coping up with leading-edge technology orientations. He has been a part of IBM Pakistan as a Cloud Application Developer, and is currently working as a core mobile application developer at TPS Worldwide.",
252 | "__collections__": {}
253 | }
254 | },
255 | "users": {}
256 | }
257 | }
--------------------------------------------------------------------------------
/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 | MinimumOSVersion
24 | 8.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | platform :ios, '9.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def parse_KV_file(file, separator='=')
14 | file_abs_path = File.expand_path(file)
15 | if !File.exists? file_abs_path
16 | return [];
17 | end
18 | pods_ary = []
19 | skip_line_start_symbols = ["#", "/"]
20 | File.foreach(file_abs_path) { |line|
21 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
22 | plugin = line.split(pattern=separator)
23 | if plugin.length == 2
24 | podname = plugin[0].strip()
25 | path = plugin[1].strip()
26 | podpath = File.expand_path("#{path}", file_abs_path)
27 | pods_ary.push({:name => podname, :path => podpath});
28 | else
29 | puts "Invalid plugin specification: #{line}"
30 | end
31 | }
32 | return pods_ary
33 | end
34 |
35 | target 'Runner' do
36 | use_frameworks!
37 |
38 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
39 | # referring to absolute paths on developers' machines.
40 | system('rm -rf .symlinks')
41 | system('mkdir -p .symlinks/plugins')
42 |
43 | # Flutter Pods
44 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
45 | if generated_xcode_build_settings.empty?
46 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first."
47 | end
48 | generated_xcode_build_settings.map { |p|
49 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
50 | symlink = File.join('.symlinks', 'flutter')
51 | File.symlink(File.dirname(p[:path]), symlink)
52 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
53 | end
54 | }
55 |
56 | # Plugin Pods
57 | plugin_pods = parse_KV_file('../.flutter-plugins')
58 | plugin_pods.map { |p|
59 | symlink = File.join('.symlinks', 'plugins', p[:name])
60 | File.symlink(p[:path], symlink)
61 | pod p[:name], :path => File.join(symlink, 'ios')
62 | }
63 | end
64 |
65 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
66 | install! 'cocoapods', :disable_input_output_paths => true
67 |
68 | post_install do |installer|
69 | installer.pods_project.targets.each do |target|
70 | target.build_configurations.each do |config|
71 | config.build_settings['ENABLE_BITCODE'] = 'NO'
72 | end
73 | end
74 | end
75 |
--------------------------------------------------------------------------------
/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 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 85FCAC6223A27F2300C14861 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 85FCAC6123A27F2300C14861 /* GoogleService-Info.plist */; };
14 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
15 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
16 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
17 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
18 | EC66248BD24BCCF793EE3784 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC457D08BFA24CCDC94DDA1D /* Pods_Runner.framework */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXCopyFilesBuildPhase section */
22 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
23 | isa = PBXCopyFilesBuildPhase;
24 | buildActionMask = 2147483647;
25 | dstPath = "";
26 | dstSubfolderSpec = 10;
27 | files = (
28 | );
29 | name = "Embed Frameworks";
30 | runOnlyForDeploymentPostprocessing = 0;
31 | };
32 | /* End PBXCopyFilesBuildPhase section */
33 |
34 | /* Begin PBXFileReference section */
35 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
36 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
37 | 1DEC670CD989438AC1A31068 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
38 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
39 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
40 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
41 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
42 | 85FCAC6123A27F2300C14861 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; };
43 | 8677228A59CE8584A8902005 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
44 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
45 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
46 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
47 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
48 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
49 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
50 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
51 | DEB10806EF1341A259FD8688 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
52 | FC457D08BFA24CCDC94DDA1D /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
53 | /* End PBXFileReference section */
54 |
55 | /* Begin PBXFrameworksBuildPhase section */
56 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
57 | isa = PBXFrameworksBuildPhase;
58 | buildActionMask = 2147483647;
59 | files = (
60 | EC66248BD24BCCF793EE3784 /* Pods_Runner.framework in Frameworks */,
61 | );
62 | runOnlyForDeploymentPostprocessing = 0;
63 | };
64 | /* End PBXFrameworksBuildPhase section */
65 |
66 | /* Begin PBXGroup section */
67 | 24F8E09D7B1877FC42F22A76 /* Pods */ = {
68 | isa = PBXGroup;
69 | children = (
70 | 1DEC670CD989438AC1A31068 /* Pods-Runner.debug.xcconfig */,
71 | DEB10806EF1341A259FD8688 /* Pods-Runner.release.xcconfig */,
72 | 8677228A59CE8584A8902005 /* Pods-Runner.profile.xcconfig */,
73 | );
74 | path = Pods;
75 | sourceTree = "";
76 | };
77 | 9740EEB11CF90186004384FC /* Flutter */ = {
78 | isa = PBXGroup;
79 | children = (
80 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
81 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
82 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
83 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
84 | );
85 | name = Flutter;
86 | sourceTree = "";
87 | };
88 | 97C146E51CF9000F007C117D = {
89 | isa = PBXGroup;
90 | children = (
91 | 9740EEB11CF90186004384FC /* Flutter */,
92 | 97C146F01CF9000F007C117D /* Runner */,
93 | 97C146EF1CF9000F007C117D /* Products */,
94 | 24F8E09D7B1877FC42F22A76 /* Pods */,
95 | D70B043E5722EFE37BA9A4D1 /* Frameworks */,
96 | );
97 | sourceTree = "";
98 | };
99 | 97C146EF1CF9000F007C117D /* Products */ = {
100 | isa = PBXGroup;
101 | children = (
102 | 97C146EE1CF9000F007C117D /* Runner.app */,
103 | );
104 | name = Products;
105 | sourceTree = "";
106 | };
107 | 97C146F01CF9000F007C117D /* Runner */ = {
108 | isa = PBXGroup;
109 | children = (
110 | 85FCAC6123A27F2300C14861 /* GoogleService-Info.plist */,
111 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
112 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
113 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
114 | 97C147021CF9000F007C117D /* Info.plist */,
115 | 97C146F11CF9000F007C117D /* Supporting Files */,
116 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
117 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
118 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
119 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
120 | );
121 | path = Runner;
122 | sourceTree = "";
123 | };
124 | 97C146F11CF9000F007C117D /* Supporting Files */ = {
125 | isa = PBXGroup;
126 | children = (
127 | );
128 | name = "Supporting Files";
129 | sourceTree = "";
130 | };
131 | D70B043E5722EFE37BA9A4D1 /* Frameworks */ = {
132 | isa = PBXGroup;
133 | children = (
134 | FC457D08BFA24CCDC94DDA1D /* Pods_Runner.framework */,
135 | );
136 | name = Frameworks;
137 | sourceTree = "";
138 | };
139 | /* End PBXGroup section */
140 |
141 | /* Begin PBXNativeTarget section */
142 | 97C146ED1CF9000F007C117D /* Runner */ = {
143 | isa = PBXNativeTarget;
144 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
145 | buildPhases = (
146 | B45E9BA58BEBC4DDC3363DD8 /* [CP] Check Pods Manifest.lock */,
147 | 9740EEB61CF901F6004384FC /* Run Script */,
148 | 97C146EA1CF9000F007C117D /* Sources */,
149 | 97C146EB1CF9000F007C117D /* Frameworks */,
150 | 97C146EC1CF9000F007C117D /* Resources */,
151 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
152 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
153 | 0306BB140847055D6597D110 /* [CP] Embed Pods Frameworks */,
154 | 34645FEE4F10BAE08C0B828E /* [CP] Copy Pods Resources */,
155 | );
156 | buildRules = (
157 | );
158 | dependencies = (
159 | );
160 | name = Runner;
161 | productName = Runner;
162 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
163 | productType = "com.apple.product-type.application";
164 | };
165 | /* End PBXNativeTarget section */
166 |
167 | /* Begin PBXProject section */
168 | 97C146E61CF9000F007C117D /* Project object */ = {
169 | isa = PBXProject;
170 | attributes = {
171 | LastUpgradeCheck = 0910;
172 | ORGANIZATIONNAME = "The Chromium Authors";
173 | TargetAttributes = {
174 | 97C146ED1CF9000F007C117D = {
175 | CreatedOnToolsVersion = 7.3.1;
176 | LastSwiftMigration = 0910;
177 | };
178 | };
179 | };
180 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
181 | compatibilityVersion = "Xcode 3.2";
182 | developmentRegion = English;
183 | hasScannedForEncodings = 0;
184 | knownRegions = (
185 | English,
186 | en,
187 | Base,
188 | );
189 | mainGroup = 97C146E51CF9000F007C117D;
190 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
191 | projectDirPath = "";
192 | projectRoot = "";
193 | targets = (
194 | 97C146ED1CF9000F007C117D /* Runner */,
195 | );
196 | };
197 | /* End PBXProject section */
198 |
199 | /* Begin PBXResourcesBuildPhase section */
200 | 97C146EC1CF9000F007C117D /* Resources */ = {
201 | isa = PBXResourcesBuildPhase;
202 | buildActionMask = 2147483647;
203 | files = (
204 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
205 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
206 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
207 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
208 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
209 | 85FCAC6223A27F2300C14861 /* GoogleService-Info.plist in Resources */,
210 | );
211 | runOnlyForDeploymentPostprocessing = 0;
212 | };
213 | /* End PBXResourcesBuildPhase section */
214 |
215 | /* Begin PBXShellScriptBuildPhase section */
216 | 0306BB140847055D6597D110 /* [CP] Embed Pods Frameworks */ = {
217 | isa = PBXShellScriptBuildPhase;
218 | buildActionMask = 2147483647;
219 | files = (
220 | );
221 | inputPaths = (
222 | );
223 | name = "[CP] Embed Pods Frameworks";
224 | outputPaths = (
225 | );
226 | runOnlyForDeploymentPostprocessing = 0;
227 | shellPath = /bin/sh;
228 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
229 | showEnvVarsInLog = 0;
230 | };
231 | 34645FEE4F10BAE08C0B828E /* [CP] Copy Pods Resources */ = {
232 | isa = PBXShellScriptBuildPhase;
233 | buildActionMask = 2147483647;
234 | files = (
235 | );
236 | inputPaths = (
237 | );
238 | name = "[CP] Copy Pods Resources";
239 | outputPaths = (
240 | );
241 | runOnlyForDeploymentPostprocessing = 0;
242 | shellPath = /bin/sh;
243 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
244 | showEnvVarsInLog = 0;
245 | };
246 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
247 | isa = PBXShellScriptBuildPhase;
248 | buildActionMask = 2147483647;
249 | files = (
250 | );
251 | inputPaths = (
252 | );
253 | name = "Thin Binary";
254 | outputPaths = (
255 | );
256 | runOnlyForDeploymentPostprocessing = 0;
257 | shellPath = /bin/sh;
258 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
259 | };
260 | 9740EEB61CF901F6004384FC /* Run Script */ = {
261 | isa = PBXShellScriptBuildPhase;
262 | buildActionMask = 2147483647;
263 | files = (
264 | );
265 | inputPaths = (
266 | );
267 | name = "Run Script";
268 | outputPaths = (
269 | );
270 | runOnlyForDeploymentPostprocessing = 0;
271 | shellPath = /bin/sh;
272 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
273 | };
274 | B45E9BA58BEBC4DDC3363DD8 /* [CP] Check Pods Manifest.lock */ = {
275 | isa = PBXShellScriptBuildPhase;
276 | buildActionMask = 2147483647;
277 | files = (
278 | );
279 | inputFileListPaths = (
280 | );
281 | inputPaths = (
282 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
283 | "${PODS_ROOT}/Manifest.lock",
284 | );
285 | name = "[CP] Check Pods Manifest.lock";
286 | outputFileListPaths = (
287 | );
288 | outputPaths = (
289 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
290 | );
291 | runOnlyForDeploymentPostprocessing = 0;
292 | shellPath = /bin/sh;
293 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
294 | showEnvVarsInLog = 0;
295 | };
296 | /* End PBXShellScriptBuildPhase section */
297 |
298 | /* Begin PBXSourcesBuildPhase section */
299 | 97C146EA1CF9000F007C117D /* Sources */ = {
300 | isa = PBXSourcesBuildPhase;
301 | buildActionMask = 2147483647;
302 | files = (
303 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
304 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
305 | );
306 | runOnlyForDeploymentPostprocessing = 0;
307 | };
308 | /* End PBXSourcesBuildPhase section */
309 |
310 | /* Begin PBXVariantGroup section */
311 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
312 | isa = PBXVariantGroup;
313 | children = (
314 | 97C146FB1CF9000F007C117D /* Base */,
315 | );
316 | name = Main.storyboard;
317 | sourceTree = "";
318 | };
319 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
320 | isa = PBXVariantGroup;
321 | children = (
322 | 97C147001CF9000F007C117D /* Base */,
323 | );
324 | name = LaunchScreen.storyboard;
325 | sourceTree = "";
326 | };
327 | /* End PBXVariantGroup section */
328 |
329 | /* Begin XCBuildConfiguration section */
330 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
331 | isa = XCBuildConfiguration;
332 | buildSettings = {
333 | ALWAYS_SEARCH_USER_PATHS = NO;
334 | CLANG_ANALYZER_NONNULL = YES;
335 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
336 | CLANG_CXX_LIBRARY = "libc++";
337 | CLANG_ENABLE_MODULES = YES;
338 | CLANG_ENABLE_OBJC_ARC = YES;
339 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
340 | CLANG_WARN_BOOL_CONVERSION = YES;
341 | CLANG_WARN_COMMA = YES;
342 | CLANG_WARN_CONSTANT_CONVERSION = YES;
343 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
344 | CLANG_WARN_EMPTY_BODY = YES;
345 | CLANG_WARN_ENUM_CONVERSION = YES;
346 | CLANG_WARN_INFINITE_RECURSION = YES;
347 | CLANG_WARN_INT_CONVERSION = YES;
348 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
349 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
350 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
351 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
352 | CLANG_WARN_STRICT_PROTOTYPES = YES;
353 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
354 | CLANG_WARN_UNREACHABLE_CODE = YES;
355 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
356 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
357 | COPY_PHASE_STRIP = NO;
358 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
359 | ENABLE_NS_ASSERTIONS = NO;
360 | ENABLE_STRICT_OBJC_MSGSEND = YES;
361 | GCC_C_LANGUAGE_STANDARD = gnu99;
362 | GCC_NO_COMMON_BLOCKS = YES;
363 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
364 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
365 | GCC_WARN_UNDECLARED_SELECTOR = YES;
366 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
367 | GCC_WARN_UNUSED_FUNCTION = YES;
368 | GCC_WARN_UNUSED_VARIABLE = YES;
369 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
370 | MTL_ENABLE_DEBUG_INFO = NO;
371 | SDKROOT = iphoneos;
372 | TARGETED_DEVICE_FAMILY = "1,2";
373 | VALIDATE_PRODUCT = YES;
374 | };
375 | name = Profile;
376 | };
377 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
378 | isa = XCBuildConfiguration;
379 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
380 | buildSettings = {
381 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
382 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
383 | DEVELOPMENT_TEAM = S8QB4VV633;
384 | ENABLE_BITCODE = NO;
385 | FRAMEWORK_SEARCH_PATHS = (
386 | "$(inherited)",
387 | "$(PROJECT_DIR)/Flutter",
388 | );
389 | INFOPLIST_FILE = Runner/Info.plist;
390 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
391 | LIBRARY_SEARCH_PATHS = (
392 | "$(inherited)",
393 | "$(PROJECT_DIR)/Flutter",
394 | );
395 | PRODUCT_BUNDLE_IDENTIFIER = com.flutterkhi.app.flutterPk;
396 | PRODUCT_NAME = "$(TARGET_NAME)";
397 | SWIFT_VERSION = 4.0;
398 | VERSIONING_SYSTEM = "apple-generic";
399 | };
400 | name = Profile;
401 | };
402 | 97C147031CF9000F007C117D /* Debug */ = {
403 | isa = XCBuildConfiguration;
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;
431 | ENABLE_STRICT_OBJC_MSGSEND = YES;
432 | ENABLE_TESTABILITY = YES;
433 | GCC_C_LANGUAGE_STANDARD = gnu99;
434 | GCC_DYNAMIC_NO_PIC = NO;
435 | GCC_NO_COMMON_BLOCKS = YES;
436 | GCC_OPTIMIZATION_LEVEL = 0;
437 | GCC_PREPROCESSOR_DEFINITIONS = (
438 | "DEBUG=1",
439 | "$(inherited)",
440 | );
441 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
442 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
443 | GCC_WARN_UNDECLARED_SELECTOR = YES;
444 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
445 | GCC_WARN_UNUSED_FUNCTION = YES;
446 | GCC_WARN_UNUSED_VARIABLE = YES;
447 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
448 | MTL_ENABLE_DEBUG_INFO = YES;
449 | ONLY_ACTIVE_ARCH = YES;
450 | SDKROOT = iphoneos;
451 | TARGETED_DEVICE_FAMILY = "1,2";
452 | };
453 | name = Debug;
454 | };
455 | 97C147041CF9000F007C117D /* Release */ = {
456 | isa = XCBuildConfiguration;
457 | buildSettings = {
458 | ALWAYS_SEARCH_USER_PATHS = NO;
459 | CLANG_ANALYZER_NONNULL = YES;
460 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
461 | CLANG_CXX_LIBRARY = "libc++";
462 | CLANG_ENABLE_MODULES = YES;
463 | CLANG_ENABLE_OBJC_ARC = YES;
464 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
465 | CLANG_WARN_BOOL_CONVERSION = YES;
466 | CLANG_WARN_COMMA = YES;
467 | CLANG_WARN_CONSTANT_CONVERSION = YES;
468 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
469 | CLANG_WARN_EMPTY_BODY = YES;
470 | CLANG_WARN_ENUM_CONVERSION = YES;
471 | CLANG_WARN_INFINITE_RECURSION = YES;
472 | CLANG_WARN_INT_CONVERSION = YES;
473 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
474 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
475 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
476 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
477 | CLANG_WARN_STRICT_PROTOTYPES = YES;
478 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
479 | CLANG_WARN_UNREACHABLE_CODE = YES;
480 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
481 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
482 | COPY_PHASE_STRIP = NO;
483 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
484 | ENABLE_NS_ASSERTIONS = NO;
485 | ENABLE_STRICT_OBJC_MSGSEND = YES;
486 | GCC_C_LANGUAGE_STANDARD = gnu99;
487 | GCC_NO_COMMON_BLOCKS = YES;
488 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
489 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
490 | GCC_WARN_UNDECLARED_SELECTOR = YES;
491 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
492 | GCC_WARN_UNUSED_FUNCTION = YES;
493 | GCC_WARN_UNUSED_VARIABLE = YES;
494 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
495 | MTL_ENABLE_DEBUG_INFO = NO;
496 | SDKROOT = iphoneos;
497 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
498 | TARGETED_DEVICE_FAMILY = "1,2";
499 | VALIDATE_PRODUCT = YES;
500 | };
501 | name = Release;
502 | };
503 | 97C147061CF9000F007C117D /* Debug */ = {
504 | isa = XCBuildConfiguration;
505 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
506 | buildSettings = {
507 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
508 | CLANG_ENABLE_MODULES = YES;
509 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
510 | ENABLE_BITCODE = NO;
511 | FRAMEWORK_SEARCH_PATHS = (
512 | "$(inherited)",
513 | "$(PROJECT_DIR)/Flutter",
514 | );
515 | INFOPLIST_FILE = Runner/Info.plist;
516 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
517 | LIBRARY_SEARCH_PATHS = (
518 | "$(inherited)",
519 | "$(PROJECT_DIR)/Flutter",
520 | );
521 | PRODUCT_BUNDLE_IDENTIFIER = com.flutterkhi.app.flutterPk;
522 | PRODUCT_NAME = "$(TARGET_NAME)";
523 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
524 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
525 | SWIFT_SWIFT3_OBJC_INFERENCE = On;
526 | SWIFT_VERSION = 4.0;
527 | VERSIONING_SYSTEM = "apple-generic";
528 | };
529 | name = Debug;
530 | };
531 | 97C147071CF9000F007C117D /* Release */ = {
532 | isa = XCBuildConfiguration;
533 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
534 | buildSettings = {
535 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
536 | CLANG_ENABLE_MODULES = YES;
537 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
538 | ENABLE_BITCODE = NO;
539 | FRAMEWORK_SEARCH_PATHS = (
540 | "$(inherited)",
541 | "$(PROJECT_DIR)/Flutter",
542 | );
543 | INFOPLIST_FILE = Runner/Info.plist;
544 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
545 | LIBRARY_SEARCH_PATHS = (
546 | "$(inherited)",
547 | "$(PROJECT_DIR)/Flutter",
548 | );
549 | PRODUCT_BUNDLE_IDENTIFIER = com.flutterkhi.app.flutterPk;
550 | PRODUCT_NAME = "$(TARGET_NAME)";
551 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
552 | SWIFT_SWIFT3_OBJC_INFERENCE = On;
553 | SWIFT_VERSION = 4.0;
554 | VERSIONING_SYSTEM = "apple-generic";
555 | };
556 | name = Release;
557 | };
558 | /* End XCBuildConfiguration section */
559 |
560 | /* Begin XCConfigurationList section */
561 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
562 | isa = XCConfigurationList;
563 | buildConfigurations = (
564 | 97C147031CF9000F007C117D /* Debug */,
565 | 97C147041CF9000F007C117D /* Release */,
566 | 249021D3217E4FDB00AE95B9 /* Profile */,
567 | );
568 | defaultConfigurationIsVisible = 0;
569 | defaultConfigurationName = Release;
570 | };
571 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
572 | isa = XCConfigurationList;
573 | buildConfigurations = (
574 | 97C147061CF9000F007C117D /* Debug */,
575 | 97C147071CF9000F007C117D /* Release */,
576 | 249021D4217E4FDB00AE95B9 /* Profile */,
577 | );
578 | defaultConfigurationIsVisible = 0;
579 | defaultConfigurationName = Release;
580 | };
581 | /* End XCConfigurationList section */
582 | };
583 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
584 | }
585 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 | import GoogleMaps
4 |
5 | @UIApplicationMain
6 | @objc class AppDelegate: FlutterAppDelegate {
7 | override func application(
8 | _ application: UIApplication,
9 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
10 | ) -> Bool {
11 | GMSServices.provideAPIKey("YOUR API KEY HERE")
12 | GeneratedPluginRegistrant.register(with: self)
13 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/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 | "size" : "1024x1024",
113 | "idiom" : "ios-marketing",
114 | "filename" : "Icon-App-1024x1024@1x.png",
115 | "scale" : "1x"
116 | }
117 | ],
118 | "info" : {
119 | "version" : 1,
120 | "author" : "xcode"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/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/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Flutter-Karachi/flutter_pk/19a5897718ce0fd64601f776e41e590749a0801c/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/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.
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 | CFBundleURLTypes
8 |
9 |
10 | CFBundleTypeRole
11 | Editor
12 | CFBundleURLSchemes
13 |
14 |
15 |
16 | com.googleusercontent.apps.1023750933650-k9qf3i4loubvia00oeq102c0bv10j4tn
17 |
18 |
19 |
20 | CFBundleExecutable
21 | $(EXECUTABLE_NAME)
22 | CFBundleIdentifier
23 | $(PRODUCT_BUNDLE_IDENTIFIER)
24 | CFBundleInfoDictionaryVersion
25 | 6.0
26 | CFBundleName
27 | flutter_pk
28 | CFBundlePackageType
29 | APPL
30 | CFBundleShortVersionString
31 | $(FLUTTER_BUILD_NAME)
32 | CFBundleSignature
33 | ????
34 | CFBundleVersion
35 | $(FLUTTER_BUILD_NUMBER)
36 | LSRequiresIPhoneOS
37 |
38 | UILaunchStoryboardName
39 | LaunchScreen
40 | UIMainStoryboardFile
41 | Main
42 | io.flutter.embedded_views_preview
43 | yes
44 | UISupportedInterfaceOrientations
45 |
46 | UIInterfaceOrientationPortrait
47 | UIInterfaceOrientationLandscapeLeft
48 | UIInterfaceOrientationLandscapeRight
49 |
50 | UISupportedInterfaceOrientations~ipad
51 |
52 | UIInterfaceOrientationPortrait
53 | UIInterfaceOrientationPortraitUpsideDown
54 | UIInterfaceOrientationLandscapeLeft
55 | UIInterfaceOrientationLandscapeRight
56 |
57 | UIViewControllerBasedStatusBarAppearance
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/lib/caches/EventDate.dart:
--------------------------------------------------------------------------------
1 | class EventDateTimeCache {
2 | DateTime _eventDateTime;
3 |
4 | DateTime get eventDateTime => _eventDateTime;
5 |
6 | void setDateTime(DateTime eventDateTime) {
7 | _eventDateTime = eventDateTime;
8 | }
9 |
10 | void clear() {
11 | _eventDateTime = null;
12 | }
13 | }
--------------------------------------------------------------------------------
/lib/caches/location.dart:
--------------------------------------------------------------------------------
1 |
2 | class LocationCache {
3 | String _longitude;
4 | String _latitude;
5 |
6 | String get longitude => _longitude;
7 | String get latitude => _latitude;
8 |
9 | void setLocation(String longitude, String latitude) {
10 | _longitude = longitude;
11 | _latitude = latitude;
12 | }
13 |
14 | void clear() {
15 | _longitude = null;
16 | _latitude = null;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/caches/user.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 |
3 | class UserCache {
4 | InAppUser _user;
5 |
6 | InAppUser get user => _user;
7 |
8 | Future getUser(String id, {bool useCached = true}) async {
9 | if (_user != null && useCached) {
10 | return _user;
11 | }
12 | _user = InAppUser.fromSnapshot(
13 | await FirebaseFirestore.instance.collection('users').document(id).get());
14 | return _user;
15 | }
16 |
17 | void clear() => _user = null;
18 | }
19 |
20 | class InAppUser {
21 | final String id;
22 | final String name;
23 | final String email;
24 | final String photoUrl;
25 | final String mobileNumber;
26 | final bool isRegistered;
27 | final bool isContributor;
28 | final bool isPresent;
29 | final DocumentReference reference;
30 |
31 | Contribution contribution;
32 |
33 | InAppUser({
34 | this.name,
35 | this.id,
36 | this.email,
37 | this.reference,
38 | this.photoUrl,
39 | this.isRegistered = false,
40 | this.isContributor = false,
41 | this.isPresent = false,
42 | this.mobileNumber,
43 | });
44 |
45 | InAppUser.fromMap(Map map, {this.reference})
46 | : id = map['id'],
47 | name = map['name'],
48 | email = map['email'],
49 | photoUrl = map['photoUrl'],
50 | isRegistered = map['isRegistered'],
51 | isContributor = map['isContributor'],
52 | isPresent = map['isPresent'],
53 | mobileNumber = map['mobileNumber'] {
54 | if (isContributor) contribution = Contribution.fromMap(map['contribution']);
55 | }
56 |
57 | Map toJson() => {
58 | "id": id,
59 | "name": name,
60 | "email": email,
61 | "photoUrl": photoUrl,
62 | "isRegistered": isRegistered,
63 | "mobileNumber": mobileNumber,
64 | "isPresent": isPresent,
65 | "isContributor": isContributor
66 | };
67 |
68 | InAppUser.fromSnapshot(DocumentSnapshot snapshot)
69 | : this.fromMap(snapshot.data(), reference: snapshot.reference);
70 | }
71 |
72 | class Contribution {
73 | final bool isVolunteer;
74 | final bool isLogisticsAdministrator;
75 | final bool isSpeaker;
76 | final bool isSocialMediaMarketingPerson;
77 |
78 | Contribution({
79 | this.isSocialMediaMarketingPerson,
80 | this.isLogisticsAdministrator,
81 | this.isSpeaker,
82 | this.isVolunteer,
83 | });
84 |
85 | Contribution.fromMap(Map map)
86 | : isSpeaker = map['speaker'],
87 | isSocialMediaMarketingPerson = map['socialMediaMarketing'],
88 | isLogisticsAdministrator = map['administrationAndLogistics'],
89 | isVolunteer = map['volunteer'];
90 |
91 | Map toJson() => {
92 | "socialMediaMarketing": isSocialMediaMarketingPerson,
93 | "speaker": isSpeaker,
94 | "administrationAndLogistics": isLogisticsAdministrator,
95 | "volunteer": isVolunteer
96 | };
97 | }
98 |
--------------------------------------------------------------------------------
/lib/contribution/contribution_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_pk/global.dart';
4 | import 'package:rflutter_alert/rflutter_alert.dart';
5 |
6 | class FullScreenContributionDialog extends StatefulWidget {
7 | @override
8 | FullScreenContributionDialogState createState() {
9 | return new FullScreenContributionDialogState();
10 | }
11 | }
12 |
13 | class FullScreenContributionDialogState
14 | extends State {
15 | bool _isVolunteer = false;
16 | bool _isLogisticsAdministrator = false;
17 | bool _isSpeaker = false;
18 | bool _isSocialMediaMarketingPerson = false;
19 | bool _isError = false;
20 |
21 | @override
22 | void initState() {
23 | super.initState();
24 | }
25 |
26 | @override
27 | Widget build(BuildContext context) {
28 | return Scaffold(
29 | body: SafeArea(
30 | child: Column(
31 | crossAxisAlignment: CrossAxisAlignment.center,
32 | children: [
33 | _buildCustomAppBarSpace(context),
34 | _buildBody(),
35 | ],
36 | ),
37 | ),
38 | );
39 | }
40 |
41 | Padding _buildCustomAppBarSpace(BuildContext context) {
42 | return Padding(
43 | padding: const EdgeInsets.only(top: 16.0),
44 | child: Row(
45 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
46 | children: [
47 | Expanded(
48 | child: FlatButton(
49 | child: Text('SKIP'),
50 | color: Colors.transparent,
51 | textColor: Colors.transparent,
52 | onPressed: () {},
53 | ),
54 | ),
55 | Text('Community contribution'),
56 | Expanded(
57 | child: Align(
58 | alignment: Alignment.centerRight,
59 | child: FlatButton(
60 | child: Text(
61 | 'SKIP',
62 | style: Theme.of(context).textTheme.subhead.copyWith(
63 | color: Colors.grey,
64 | ),
65 | ),
66 | onPressed: () => Navigator.of(context).pop(),
67 | ),
68 | ),
69 | )
70 | ],
71 | ),
72 | );
73 | }
74 |
75 | Widget _buildBody() {
76 | return Expanded(
77 | child: Column(
78 | mainAxisAlignment: MainAxisAlignment.center,
79 | crossAxisAlignment: CrossAxisAlignment.center,
80 | children: [
81 | _buildGraphic(),
82 | _buildQuestion(),
83 | _buildSelection(),
84 | ],
85 | ),
86 | );
87 | }
88 |
89 | Padding _buildQuestion() {
90 | return Padding(
91 | padding: const EdgeInsets.all(8.0),
92 | child: Text(
93 | 'In what capacity do you want to contribute to the Flutter community?',
94 | style: Theme.of(context).textTheme.title,
95 | textAlign: TextAlign.center,
96 | ),
97 | );
98 | }
99 |
100 | Widget _buildSelection() {
101 | return Expanded(
102 | child: ListView(
103 | children: [
104 | CheckboxListTile(
105 | title: Text('Volunteer'),
106 | value: _isVolunteer,
107 | onChanged: (bool value) {
108 | setState(() => _isError = false);
109 | setState(() => _isVolunteer = value);
110 | },
111 | ),
112 | CheckboxListTile(
113 | title: Text('Administration & Logistics'),
114 | value: _isLogisticsAdministrator,
115 | onChanged: (bool value) {
116 | setState(() => _isError = false);
117 | setState(() => _isLogisticsAdministrator = value);
118 | },
119 | ),
120 | CheckboxListTile(
121 | title: Text('Speaker'),
122 | value: _isSpeaker,
123 | onChanged: (bool value) {
124 | setState(() => _isError = false);
125 | setState(() => _isSpeaker = value);
126 | },
127 | ),
128 | CheckboxListTile(
129 | title: Text('Social media marketing'),
130 | value: _isSocialMediaMarketingPerson,
131 | onChanged: (bool value) {
132 | setState(() => _isError = false);
133 | setState(() => _isSocialMediaMarketingPerson = value);
134 | },
135 | ),
136 | Padding(
137 | padding: const EdgeInsets.only(right: 8.0),
138 | child: Align(
139 | alignment: Alignment.centerRight,
140 | child: FlatButton(
141 | child: Row(
142 | mainAxisAlignment: MainAxisAlignment.end,
143 | children: [
144 | Text('CONTINUE'),
145 | Icon(
146 | Icons.arrow_forward,
147 | size: 24.0,
148 | )
149 | ],
150 | ),
151 | textColor: Theme.of(context).primaryColor,
152 | onPressed: _submitDetails,
153 | ),
154 | ),
155 | ),
156 | Padding(
157 | padding: const EdgeInsets.all(16.0),
158 | child: _isError
159 | ? Text(
160 | 'Please select at least one option. You can also SKIP this step from the top right corner of this screen',
161 | style: TextStyle(color: Colors.red),
162 | textAlign: TextAlign.center,
163 | )
164 | : Container(),
165 | ),
166 | ],
167 | ),
168 | );
169 | }
170 |
171 | void _submitDetails() async {
172 | if (!_validate()) return;
173 | try {
174 | FirebaseFirestore.instance.runTransaction((transaction) async {
175 | await transaction.update(userCache.user.reference, {
176 | 'isContributor': true,
177 | 'contribution': {
178 | 'volunteer': _isVolunteer,
179 | 'speaker': _isSpeaker,
180 | 'administrationAndLogistics': _isLogisticsAdministrator,
181 | 'socialMediMarketing': _isSocialMediaMarketingPerson,
182 | }
183 | });
184 | });
185 | await userCache.getUser(userCache.user.id, useCached: false);
186 | Navigator.of(context).pop();
187 | } catch (ex) {
188 | print(ex);
189 | Alert(
190 | context: context,
191 | type: AlertType.error,
192 | title: "Oops!",
193 | desc: "An error has occurred",
194 | buttons: [
195 | DialogButton(
196 | child: Text("Dismiss",
197 | style: Theme.of(context).textTheme.title.copyWith(
198 | color: Colors.white,
199 | )),
200 | color: Colors.red,
201 | onPressed: () {
202 | Navigator.of(context).pop();
203 | },
204 | )
205 | ],
206 | ).show();
207 | }
208 | }
209 |
210 | Row _buildGraphic() {
211 | return Row(
212 | mainAxisAlignment: MainAxisAlignment.center,
213 | crossAxisAlignment: CrossAxisAlignment.end,
214 | children: [
215 | Stack(
216 | children: [
217 | Center(
218 | child: Icon(
219 | Icons.tab,
220 | color: Theme.of(context).primaryColor,
221 | size: 80.0,
222 | ),
223 | ),
224 | Center(
225 | child: Padding(
226 | padding: const EdgeInsets.only(top: 24.0, left: 16.0),
227 | child: Image(
228 | image: AssetImage(
229 | 'assets/flutterKarachi.png',
230 | ),
231 | height: 40.0,
232 | width: 40.0,
233 | ),
234 | ),
235 | )
236 | ],
237 | ),
238 | Padding(
239 | padding: const EdgeInsets.only(left: 8.0),
240 | child: Stack(
241 | children: [
242 | Center(
243 | child: Icon(
244 | Icons.desktop_mac,
245 | color: Theme.of(context).primaryColor,
246 | size: 150.0,
247 | ),
248 | ),
249 | Center(
250 | child: Padding(
251 | padding: const EdgeInsets.only(top: 28.0, left: 42.0),
252 | child: Image(
253 | image: AssetImage(
254 | 'assets/flutterKarachi.png',
255 | ),
256 | height: 60.0,
257 | width: 60.0,
258 | ),
259 | ),
260 | )
261 | ],
262 | ),
263 | ),
264 | Stack(
265 | children: [
266 | Center(
267 | child: Icon(
268 | Icons.phone_iphone,
269 | color: Theme.of(context).primaryColor,
270 | size: 80.0,
271 | ),
272 | ),
273 | Center(
274 | child: Padding(
275 | padding: const EdgeInsets.only(top: 16.0, left: 19.0),
276 | child: Image(
277 | image: AssetImage(
278 | 'assets/flutterKarachi.png',
279 | ),
280 | height: 40.0,
281 | width: 40.0,
282 | ),
283 | ),
284 | )
285 | ],
286 | ),
287 | ],
288 | );
289 | }
290 |
291 | bool _validate() {
292 | if (!_isSocialMediaMarketingPerson &&
293 | !_isSpeaker &&
294 | !_isLogisticsAdministrator &&
295 | !_isVolunteer) {
296 | setState(() => _isError = true);
297 | return false;
298 | }
299 |
300 | return true;
301 | }
302 | }
303 |
--------------------------------------------------------------------------------
/lib/dialogs/custom_error_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | void showErrorDialog(String title, String message, BuildContext context) async {
4 | await showDialog(
5 | child: Center(
6 | child: SizedBox(
7 | height: 200.0,
8 | width: MediaQuery.of(context).size.width - 100,
9 | child: Stack(
10 | children: [
11 | Container(
12 | decoration: BoxDecoration(
13 | color: Colors.transparent,
14 | borderRadius: BorderRadius.circular(10.0),
15 | ),
16 | ),
17 | Center(
18 | child: Stack(
19 | alignment: Alignment.center,
20 | children: [
21 | Padding(
22 | padding: const EdgeInsets.only(top: 30.0),
23 | child: Container(
24 | decoration: BoxDecoration(
25 | color: Colors.white,
26 | borderRadius: BorderRadius.circular(15.0),
27 | border: Border.all(
28 | color: Theme.of(context).primaryColor)),
29 | child: Padding(
30 | padding: const EdgeInsets.only(top: 40.0),
31 | child: Column(
32 | mainAxisAlignment: MainAxisAlignment.start,
33 | children: [
34 | Text(
35 | title,
36 | style: Theme.of(context).textTheme.title,
37 | ),
38 | Padding(
39 | padding: const EdgeInsets.only(
40 | top: 24.0,
41 | left: 16.0,
42 | right: 16.0,
43 | ),
44 | child: Center(
45 | child: Text(
46 | message,
47 | style: Theme.of(context).textTheme.subhead,
48 | textAlign: TextAlign.center,
49 | ),
50 | ),
51 | ),
52 | ],
53 | ),
54 | ),
55 | ),
56 | ),
57 | Padding(
58 | padding: const EdgeInsets.only(bottom: 64.0),
59 | child: Align(
60 | alignment: Alignment.topCenter,
61 | child: GestureDetector(
62 | child: CircleAvatar(
63 | backgroundColor: Theme.of(context).primaryColorLight,
64 | foregroundColor: Colors.white,
65 | child: Image(image: AssetImage('assets/flutterKarachi.png'),),
66 | radius: 30.0,
67 | ),
68 | onTap: () => Navigator.of(context).pop(),
69 | ),
70 | ),
71 | ),
72 | ],
73 | ),
74 | ),
75 | ],
76 | ),
77 | ),
78 | ),
79 | context: context,
80 | );
81 | }
82 |
--------------------------------------------------------------------------------
/lib/feedback/feedback.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_pk/global.dart';
4 | import 'package:flutter_pk/schedule/model.dart';
5 | import 'package:flutter_pk/theme.dart';
6 | import 'package:flutter_pk/widgets/full_screen_loader.dart';
7 | import 'package:rflutter_alert/rflutter_alert.dart';
8 | import 'package:smooth_star_rating/smooth_star_rating.dart';
9 |
10 | class FullScreenFeedbackDialog extends StatefulWidget {
11 | final Session session;
12 | FullScreenFeedbackDialog({this.session});
13 | @override
14 | FullScreenFeedbackDialogState createState() {
15 | return FullScreenFeedbackDialogState();
16 | }
17 | }
18 |
19 | class FullScreenFeedbackDialogState extends State {
20 | double rating = 0.0;
21 | bool _isLoading = false;
22 | @override
23 | Widget build(BuildContext context) {
24 | // TODO: implement build
25 | return Scaffold(
26 | backgroundColor: ColorDictionary.stringToColor[widget.session.color],
27 | body: Stack(
28 | children: [
29 | SafeArea(
30 | child: Column(
31 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
32 | children: [
33 | Row(
34 | children: [
35 | IconButton(
36 | icon: Icon(
37 | Icons.clear,
38 | color: ColorDictionary
39 | .stringToColor[widget.session.textColor],
40 | ),
41 | onPressed: () => Navigator.of(context).pop(),
42 | ),
43 | ],
44 | ),
45 | Expanded(
46 | child: Column(
47 | mainAxisAlignment: MainAxisAlignment.center,
48 | children: [
49 | Icon(
50 | Icons.rate_review,
51 | size: 100.0,
52 | color: ColorDictionary
53 | .stringToColor[widget.session.textColor],
54 | ),
55 | Padding(
56 | padding: const EdgeInsets.only(left: 16.0, right: 16.0),
57 | child: Text(
58 | 'Your feedback adds value to the quality of upcoming events!',
59 | textAlign: TextAlign.center,
60 | style: TextStyle(
61 | fontSize: 16.0,
62 | color: ColorDictionary
63 | .stringToColor[widget.session.textColor],
64 | ),
65 | ),
66 | ),
67 | Padding(
68 | padding: const EdgeInsets.only(top: 8.0),
69 | child: Text(
70 | 'Rate this session',
71 | textAlign: TextAlign.center,
72 | style: TextStyle(
73 | fontSize: 16.0,
74 | color: ColorDictionary
75 | .stringToColor[widget.session.textColor],
76 | ),
77 | ),
78 | ),
79 | Padding(
80 | padding: const EdgeInsets.all(16.0),
81 | child: Container(
82 | decoration: BoxDecoration(
83 | color: ColorDictionary
84 | .stringToColor[widget.session.textColor],
85 | borderRadius: BorderRadius.circular(10.0)),
86 | child: ListTile(
87 | title: Center(
88 | child: Text(
89 | widget.session.title,
90 | style: TextStyle(
91 | fontWeight: FontWeight.bold,
92 | color: ColorDictionary
93 | .stringToColor[widget.session.color],
94 | ),
95 | ),
96 | ),
97 | ),
98 | ),
99 | ),
100 | SmoothStarRating(
101 | allowHalfRating: true,
102 | onRatingChanged: (value) {
103 | setState(() {
104 | rating = value;
105 | });
106 | },
107 | starCount: 5,
108 | rating: rating,
109 | size: 40.0,
110 | color: ColorDictionary
111 | .stringToColor[widget.session.textColor],
112 | borderColor: ColorDictionary
113 | .stringToColor[widget.session.textColor],
114 | ),
115 | Padding(
116 | padding: const EdgeInsets.only(top: 16.0),
117 | child: Align(
118 | alignment: Alignment.centerRight,
119 | child: FlatButton(
120 | child: Row(
121 | mainAxisAlignment: MainAxisAlignment.end,
122 | children: [
123 | Text(
124 | 'CONTINUE',
125 | style: TextStyle(
126 | color: ColorDictionary.stringToColor[
127 | widget.session.textColor],
128 | ),
129 | ),
130 | Icon(
131 | Icons.arrow_forward,
132 | size: 24.0,
133 | color: ColorDictionary
134 | .stringToColor[widget.session.textColor],
135 | )
136 | ],
137 | ),
138 | textColor: Theme.of(context).primaryColor,
139 | onPressed: _submitFeedback,
140 | ),
141 | ),
142 | )
143 | ],
144 | ),
145 | )
146 | ],
147 | ),
148 | ),
149 | _isLoading ? FullScreenLoader() : Container()
150 | ],
151 | ),
152 | );
153 | }
154 |
155 | void _submitFeedback() async {
156 | setState(() => _isLoading = true);
157 | try {
158 | CollectionReference reference =
159 | FirebaseFirestore.instance.collection(FireStoreKeys.userCollection);
160 | await reference.doc(userCache.user.id).setData(
161 | {
162 | 'feedback': {widget.session.id: rating}
163 | },
164 | SetOptions(
165 | merge: true
166 | )
167 | );
168 | Alert(
169 | context: context,
170 | type: AlertType.success,
171 | title: "Thank you!",
172 | desc: "Your feedback has been recorded",
173 | buttons: [
174 | DialogButton(
175 | child: Text("Cool!",
176 | style: Theme.of(context).textTheme.title.copyWith(
177 | color: Colors.white,
178 | )),
179 | color: ColorDictionary.stringToColor[widget.session.color],
180 | onPressed: () {
181 | Navigator.of(context).pop();
182 | Navigator.of(context).popUntil(
183 | ModalRoute.withName(Routes.home_master),
184 | );
185 | },
186 | )
187 | ],
188 | ).show();
189 | } catch (ex) {
190 | print(ex);
191 | Alert(
192 | context: context,
193 | type: AlertType.error,
194 | title: "Oops!",
195 | desc: "An error has occurred",
196 | buttons: [
197 | DialogButton(
198 | child: Text("Dismiss",
199 | style: Theme.of(context).textTheme.title.copyWith(
200 | color: Colors.white,
201 | )),
202 | color: Colors.red,
203 | onPressed: () {
204 | Navigator.of(context).pop();
205 | },
206 | )
207 | ],
208 | ).show();
209 | } finally {
210 | setState(() => _isLoading = false);
211 | }
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/lib/global.dart:
--------------------------------------------------------------------------------
1 | import 'package:firebase_auth/firebase_auth.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_pk/caches/EventDate.dart';
4 | import 'package:flutter_pk/caches/location.dart';
5 | import 'package:flutter_pk/caches/user.dart';
6 | import 'package:google_sign_in/google_sign_in.dart';
7 | import 'package:shared_preferences/shared_preferences.dart';
8 |
9 | abstract class Routes {
10 | static const String home_master = '/home_master';
11 | static const String main = '/main';
12 | }
13 |
14 | abstract class GlobalConstants {
15 | static const int phoneNumberMaxLength = 13;
16 | static const String breakId = 'break';
17 | static const int entryMaxLength = 50;
18 | static const String qrKey = "thisisahighlyencryptedaubykhanstringthatisbeingusedforfluttermeetupqrscan";
19 | static const String addNumberDisplayText =
20 | 'Add your phone number in order to receive event updates.';
21 | static const String editNumberDisplayText =
22 | 'Looks like you have a number registered against your account. You can use the same number to receive event confirmations or you can update it.';
23 | }
24 |
25 | abstract class SharedPreferencesKeys {
26 | static const String firebaseUserId = 'uid';
27 | }
28 |
29 | abstract class FireStoreKeys {
30 | static const String userCollection = 'users';
31 | static const String dateCollection = 'dates';
32 | static const String sessionCollection = 'sessions';
33 | static const String speakerCollection = 'speakers';
34 | static const String attendanceCollection = 'attendance';
35 | static const String attendeesCollection = 'attendees';
36 | static const String dateReferenceString = '16032019';
37 | }
38 |
39 | final GoogleSignIn googleSignIn = GoogleSignIn();
40 | final FirebaseAuth auth = FirebaseAuth.instance;
41 | final Future sharedPreferences =
42 | SharedPreferences.getInstance();
43 |
44 | UserCache userCache = new UserCache();
45 |
46 | LocationCache locationCache = new LocationCache();
47 |
48 | EventDateTimeCache eventDateTimeCache = new EventDateTimeCache();
49 |
--------------------------------------------------------------------------------
/lib/helpers/formatters.dart:
--------------------------------------------------------------------------------
1 | import 'package:intl/intl.dart';
2 |
3 | abstract class DateFormats {
4 | static String shortUiDateTimeFormat = 'MMM dd, yyyy, h:mm a';
5 | static String shortUiDateFormat = 'MMM dd, yyyy';
6 | static String shortUiTimeFormat = 'h:mm a';
7 | }
8 |
9 | String formatDate(DateTime date, String format) {
10 | var formatter = new DateFormat(format);
11 | return formatter.format(date);
12 | }
--------------------------------------------------------------------------------
/lib/helpers/regex-helpers.dart:
--------------------------------------------------------------------------------
1 | abstract class RegexHelpers {
2 | static RegExp phoneNumberRegex = RegExp(r"^[+][0-9]*$");
3 | }
--------------------------------------------------------------------------------
/lib/helpers/shared_preferences.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_pk/global.dart';
2 | import 'package:shared_preferences/shared_preferences.dart';
3 |
4 | class SharedPreferencesHandler {
5 | SharedPreferences _prefs;
6 | Future get prefs async {
7 | if (_prefs == null) {
8 | _prefs = await sharedPreferences;
9 | }
10 |
11 | return _prefs;
12 | }
13 |
14 | Future setPreference(String key, String value) async {
15 | await prefs.then((item) {
16 | item.setString(key, value);
17 | });
18 | }
19 |
20 | Future getValue(String key) async {
21 | return await prefs.then((item) {
22 | return item.get(key);
23 | });
24 | }
25 |
26 | Future clearPreferences() async {
27 | await prefs.then((item) {
28 | item.clear();
29 | });
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/home/home_master.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:cloud_firestore/cloud_firestore.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter/services.dart';
6 | import 'package:flutter_pk/caches/user.dart';
7 | import 'package:flutter_pk/venue_detail.dart';
8 | import 'package:flutter_pk/global.dart';
9 | import 'package:barcode_scan/barcode_scan.dart';
10 | import 'package:flutter_pk/registration/registration.dart';
11 | import 'package:flutter_pk/widgets/full_screen_loader.dart';
12 | import 'package:url_launcher/url_launcher.dart';
13 | import 'package:rflutter_alert/rflutter_alert.dart';
14 | import 'package:flutter_pk/schedule/schedule_page.dart';
15 |
16 | class HomePageMaster extends StatefulWidget {
17 | @override
18 | HomePageMasterState createState() {
19 | return new HomePageMasterState();
20 | }
21 | }
22 |
23 | class HomePageMasterState extends State {
24 | int _selectedIndex = 0;
25 | String floatingButtonLabel = 'Register';
26 | IconData floatingButtonIcon = Icons.group_work;
27 | bool _isLoading = false;
28 | bool _isUserPresent = false;
29 | InAppUser _user = new InAppUser();
30 | List widgets = [
31 | SchedulePage(),
32 | Center(
33 | child: Text('Hello two'),
34 | ),
35 | VenueDetailPage()
36 | ];
37 |
38 | @override
39 | void initState() {
40 | // TODO: implement initState
41 | super.initState();
42 | _setUser(true);
43 | }
44 |
45 | @override
46 | Widget build(BuildContext context) {
47 | // TODO: implement build
48 | return AnnotatedRegion(
49 | value: SystemUiOverlayStyle.dark,
50 | sized: false,
51 | child: Scaffold(
52 | floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
53 | floatingActionButton: _isLoading
54 | ? null
55 | : FloatingActionButton.extended(
56 | onPressed: _floatingButtonTapModerator,
57 | icon: Icon(floatingButtonIcon),
58 | label: Text(floatingButtonLabel),
59 | ),
60 | body: Stack(
61 | children: [
62 | widgets.elementAt(_selectedIndex),
63 | _isLoading ? FullScreenLoader() : Container()
64 | ],
65 | ),
66 | bottomNavigationBar: _isLoading
67 | ? null
68 | : BottomNavigationBar(
69 | onTap: (value) {
70 | floatingButtonLabel =
71 | _user.isRegistered ? 'Scan QR' : 'Register';
72 | floatingButtonIcon = _user.isRegistered
73 | ? Icons.center_focus_weak
74 | : Icons.group_work;
75 | if (value == 2) {
76 | floatingButtonLabel = 'Navigate';
77 | floatingButtonIcon = Icons.my_location;
78 | }
79 | if (value != 1)
80 | setState(() {
81 | _selectedIndex = value;
82 | });
83 | },
84 | currentIndex: _selectedIndex,
85 | items: [
86 | BottomNavigationBarItem(
87 | icon: Icon(Icons.date_range), title: Text('Schedule')),
88 | BottomNavigationBarItem(
89 | icon: Icon(
90 | Icons.date_range,
91 | color: Colors.transparent,
92 | ),
93 | title: Text(' ')),
94 | BottomNavigationBarItem(
95 | icon: Icon(Icons.location_on), title: Text('Venue')),
96 | ],
97 | ),
98 | ),
99 | );
100 | }
101 |
102 | void _floatingButtonTapModerator() {
103 | if (_selectedIndex == 2) {
104 | _navigateToGoogleMaps();
105 | } else if (_user.isRegistered) {
106 | if (!_isUserPresent) {
107 | if (DateTime.now().isBefore(eventDateTimeCache.eventDateTime)) {
108 | Alert(
109 | context: context,
110 | type: AlertType.info,
111 | title: "Information!",
112 | desc: "You will be able to scan a QR on the event day!\nCheers!",
113 | buttons: [
114 | DialogButton(
115 | child: Text("Cool!",
116 | style: Theme.of(context).textTheme.title.copyWith(
117 | color: Colors.white,
118 | )),
119 | color: Colors.green,
120 | onPressed: () {
121 | Navigator.of(context).pop();
122 | },
123 | )
124 | ],
125 | ).show();
126 | } else {
127 | _scanQr();
128 | }
129 | } else {
130 | Alert(
131 | context: context,
132 | type: AlertType.info,
133 | title: "Information!",
134 | desc: "You are already marked present! \nEnjoy the event!",
135 | buttons: [
136 | DialogButton(
137 | child: Text("Cool!",
138 | style: Theme.of(context).textTheme.title.copyWith(
139 | color: Colors.white,
140 | )),
141 | color: Colors.green,
142 | onPressed: () {
143 | Navigator.of(context).pop();
144 | },
145 | )
146 | ],
147 | ).show();
148 | }
149 | } else {
150 | _navigateToRegistration(context);
151 | }
152 | }
153 |
154 | void _navigateToGoogleMaps() async {
155 | bool isIOS = Theme.of(context).platform == TargetPlatform.iOS;
156 | String googleUrl = '';
157 | if (isIOS) {
158 | googleUrl =
159 | 'comgooglemapsurl://maps.google.com/maps?f=d&daddr=${locationCache.latitude},${locationCache.longitude}&sspn=0.2,0.1';
160 | String appleMapsUrl =
161 | 'https://maps.apple.com/?sll=${locationCache.latitude},${locationCache.longitude}';
162 | if (await canLaunch("comgooglemaps://")) {
163 | print('launching com googleUrl');
164 | await launch(googleUrl);
165 | } else if (await canLaunch(appleMapsUrl)) {
166 | print('launching apple url');
167 | await launch(appleMapsUrl);
168 | } else {
169 | await launch(
170 | 'https://www.google.com/maps/search/?api=1&query=${locationCache.latitude},${locationCache.longitude}');
171 | }
172 | } else {
173 | googleUrl =
174 | 'google.navigation:q=${locationCache.latitude},${locationCache.longitude}&mode=d';
175 | if (await canLaunch(googleUrl)) {
176 | await launch(googleUrl);
177 | } else {
178 | await launch(
179 | 'https://www.google.com/maps/search/?api=1&query=${locationCache.latitude},${locationCache.longitude}');
180 | }
181 | }
182 | }
183 |
184 | Future _scanQr() async {
185 | try {
186 | var qrDataString = await BarcodeScanner.scan();
187 | print(qrDataString.rawContent);
188 | if (qrDataString.rawContent == GlobalConstants.qrKey) {
189 | setState(() {
190 | _isLoading = true;
191 | });
192 | DocumentReference attendanceReference = Firestore.instance
193 | .collection(FireStoreKeys.attendanceCollection)
194 | .document(FireStoreKeys.dateReferenceString);
195 |
196 | CollectionReference attendeeCollectionReference =
197 | attendanceReference.collection(FireStoreKeys.attendeesCollection);
198 |
199 | int attendanceCount;
200 | await Firestore.instance
201 | .collection(FireStoreKeys.attendanceCollection)
202 | .document(FireStoreKeys.dateReferenceString)
203 | .get()
204 | .then((onValue) {
205 | attendanceCount = onValue.data()['attendanceCount'];
206 | });
207 |
208 | await attendanceReference.set(
209 | {'attendanceCount': attendanceCount + 1}, SetOptions(merge: true));
210 |
211 | await attendeeCollectionReference.doc(userCache.user.id).set(
212 | {'userName': userCache.user.name},
213 | SetOptions(merge: true),
214 | );
215 | CollectionReference reference =
216 | Firestore.instance.collection(FireStoreKeys.userCollection);
217 |
218 | await reference
219 | .doc(userCache.user.id)
220 | .set({"isPresent": true}, SetOptions(merge: true));
221 | _setUser(true);
222 | Alert(
223 | context: context,
224 | type: AlertType.success,
225 | title: "Yayy!",
226 | desc: "You have been marked present! Enjoy the event!",
227 | buttons: [
228 | DialogButton(
229 | child: Text("Cool!",
230 | style: Theme.of(context).textTheme.title.copyWith(
231 | color: Colors.white,
232 | )),
233 | color: Colors.green,
234 | onPressed: () {
235 | setState(() {
236 | _isUserPresent = true;
237 | });
238 | Navigator.of(context).pop();
239 | },
240 | )
241 | ],
242 | ).show();
243 | } else {
244 | Alert(
245 | context: context,
246 | type: AlertType.warning,
247 | title: "Oops!",
248 | desc: "Looks like you scanned an invalid QR",
249 | buttons: [
250 | DialogButton(
251 | child: Text("Dismiss",
252 | style: Theme.of(context).textTheme.title.copyWith(
253 | color: Colors.white,
254 | )),
255 | color: Colors.blueGrey,
256 | onPressed: () {
257 | Navigator.of(context).pop();
258 | },
259 | )
260 | ],
261 | ).show();
262 | }
263 | } catch (ex) {
264 | print(ex);
265 | Alert(
266 | context: context,
267 | type: AlertType.error,
268 | title: "Oops!",
269 | desc: "An error has occurred",
270 | buttons: [
271 | DialogButton(
272 | child: Text("Dismiss",
273 | style: Theme.of(context).textTheme.title.copyWith(
274 | color: Colors.white,
275 | )),
276 | color: Colors.red,
277 | onPressed: () {
278 | Navigator.of(context).pop();
279 | },
280 | )
281 | ],
282 | ).show();
283 | } finally {
284 | setState(() {
285 | _isLoading = false;
286 | });
287 | }
288 | }
289 |
290 | Future _navigateToRegistration(BuildContext context) async {
291 | await Navigator.of(context).push(
292 | MaterialPageRoute(
293 | builder: (context) => RegistrationPage(),
294 | fullscreenDialog: true,
295 | ),
296 | );
297 | var user = await userCache.getUser(userCache.user.id, useCached: false);
298 | setState(() {
299 | _user = user;
300 | });
301 | _setUser(false);
302 | }
303 |
304 | Future _setUser(bool useCached) async {
305 | var user = await userCache.getUser(
306 | userCache.user.id,
307 | useCached: useCached,
308 | );
309 | setState(() {
310 | _user = user;
311 | _isUserPresent = user.isPresent;
312 | floatingButtonLabel = _user.isRegistered ? 'Scan QR' : 'Register';
313 | floatingButtonIcon =
314 | _user.isRegistered ? Icons.center_focus_weak : Icons.group_work;
315 | });
316 | }
317 | }
318 |
--------------------------------------------------------------------------------
/lib/home/login.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:firebase_auth/firebase_auth.dart';
3 | import 'package:flutter_pk/caches/user.dart';
4 | import 'package:flutter_pk/global.dart';
5 | import 'package:google_sign_in/google_sign_in.dart';
6 |
7 | class LoginApi {
8 | Future initiateLogin() async {
9 | var user = await signInWithGoogle();
10 |
11 | await _setUserToFireStore(user.user);
12 |
13 | return user.user.uid;
14 | }
15 |
16 | Future signInWithGoogle() async {
17 |
18 | // Trigger the authentication flow
19 | final GoogleSignInAccount googleUser = await GoogleSignIn().signIn();
20 |
21 | // Obtain the auth details from the request
22 | final GoogleSignInAuthentication googleAuth =
23 | await googleUser.authentication;
24 |
25 | // Create a new credential
26 | final GoogleAuthCredential credential = GoogleAuthProvider.credential(
27 | accessToken: googleAuth.accessToken,
28 | idToken: googleAuth.idToken,
29 | );
30 |
31 | // Once signed in, return the UserCredential
32 | return await FirebaseAuth.instance.signInWithCredential(credential);
33 | }
34 |
35 | Future _setUserToFireStore(User user) async {
36 | CollectionReference reference =
37 | FirebaseFirestore.instance.collection(FireStoreKeys.userCollection);
38 |
39 | await reference.doc(user.uid).get().then((snap) async {
40 | if (!snap.exists) {
41 | InAppUser _user = InAppUser(
42 | name: user.displayName,
43 | mobileNumber: user.phoneNumber,
44 | id: user.uid,
45 | photoUrl: user.photoUrl,
46 | email: user.email);
47 |
48 | await reference
49 | .doc(user.uid)
50 | .set(_user.toJson(), SetOptions(merge: true));
51 | }
52 | });
53 | }
54 |
55 | Future _handleGoogleSignIn() async {
56 | GoogleSignInAccount googleUser = await googleSignIn.signIn();
57 | GoogleSignInAuthentication googleAuth = await googleUser.authentication;
58 | return googleAuth;
59 | }
60 |
61 | // initialize() {
62 | // Firestore.instance.settings(
63 | // // TODO: Update this according to the new implementation
64 | //// timestampsInSnapshotsEnabled: true,
65 | // );
66 | // }
67 | }
68 |
--------------------------------------------------------------------------------
/lib/home/onboarding.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_pk/helpers/shared_preferences.dart';
3 | import 'package:flutter_pk/home/login.dart';
4 | import 'package:flutter_swiper/flutter_swiper.dart';
5 | import 'package:rflutter_alert/rflutter_alert.dart';
6 | import 'package:sprung/sprung.dart';
7 |
8 | import '../contribution/contribution_dialog.dart';
9 | import '../global.dart';
10 | import '../widgets/full_screen_loader.dart';
11 | import '../widgets/sprung_box.dart';
12 |
13 | class OnboardingPage extends StatefulWidget {
14 | OnboardingPage({Key key, this.title}) : super(key: key);
15 | final String title;
16 |
17 | @override
18 | _OnboardingPageState createState() => _OnboardingPageState();
19 | }
20 |
21 | class _OnboardingPageState extends State {
22 | bool _isLoading = false;
23 | bool _showSwipeText = false;
24 | bool _isFetchingSharedPreferences = false;
25 | SharedPreferencesHandler preferences;
26 |
27 | LoginApi api = LoginApi();
28 |
29 | @override
30 | void initState() {
31 | // TODO: implement initState
32 | super.initState();
33 |
34 | preferences = SharedPreferencesHandler();
35 |
36 | _getSharedPreferences();
37 | }
38 |
39 | @override
40 | Widget build(BuildContext context) {
41 | return Stack(
42 | children: [
43 | Scaffold(
44 | body: _buildBody(context),
45 | ),
46 | _isLoading ? FullScreenLoader() : Container()
47 | ],
48 | );
49 | }
50 |
51 | SafeArea _buildBody(BuildContext context) {
52 | return SafeArea(
53 | child: new Swiper.children(
54 | autoplay: false,
55 | loop: false,
56 | physics: _isFetchingSharedPreferences
57 | ? NeverScrollableScrollPhysics()
58 | : ScrollPhysics(),
59 | pagination: _isFetchingSharedPreferences
60 | ? SwiperPagination()
61 | : new SwiperPagination(
62 | margin: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 30.0),
63 | builder: new DotSwiperPaginationBuilder(
64 | color: Theme.of(context).hintColor,
65 | activeColor: Theme.of(context).primaryColor,
66 | size: 10.0,
67 | activeSize: 15.0),
68 | ),
69 | children: [
70 | _buildFirstSwiperControlPage(context),
71 | _buildSecondSwiperControlPage(context),
72 | ],
73 | ),
74 | );
75 | }
76 |
77 | Center _buildSecondSwiperControlPage(BuildContext context) {
78 | return Center(
79 | child: Column(
80 | mainAxisAlignment: MainAxisAlignment.spaceAround,
81 | children: [
82 | Padding(
83 | padding: const EdgeInsets.only(left: 64.0, right: 64.0),
84 | child: _isLoading
85 | ? Container()
86 | : Image(
87 | image: AssetImage('assets/loader.png'),
88 | ),
89 | ),
90 | Column(
91 | children: [
92 | Text(
93 | 'Register | Attend | Build',
94 | style: Theme.of(context).textTheme.title,
95 | ),
96 | Padding(
97 | padding:
98 | const EdgeInsets.only(top: 32.0, left: 32.0, right: 32.0),
99 | child: Text(
100 | 'Get information about events, their agendas and register yourself as an attendee',
101 | textAlign: TextAlign.center,
102 | ),
103 | ),
104 | Padding(
105 | padding: const EdgeInsets.only(top: 32.0, bottom: 32.0),
106 | child: RaisedButton(
107 | onPressed: _handleSignIn,
108 | textColor: Colors.white,
109 | child: Text('Get started'),
110 | ),
111 | )
112 | ],
113 | ),
114 | ],
115 | ),
116 | );
117 | }
118 |
119 | Center _buildFirstSwiperControlPage(BuildContext context) {
120 | return Center(
121 | child: Column(
122 | crossAxisAlignment: CrossAxisAlignment.center,
123 | mainAxisAlignment: MainAxisAlignment.spaceAround,
124 | children: [
125 | SprungBox(
126 | callback: (bool value) {},
127 | ),
128 | Column(
129 | children: [
130 | Text(
131 | 'Welcome to Flutter Pakistan',
132 | style: Theme.of(context).textTheme.title,
133 | ),
134 | AnimatedCrossFade(
135 | crossFadeState: _showSwipeText
136 | ? CrossFadeState.showFirst
137 | : CrossFadeState.showSecond,
138 | duration: Duration(milliseconds: 800),
139 | firstChild: Padding(
140 | padding: const EdgeInsets.only(top: 32.0),
141 | child: Text('Swipe left to proceed'),
142 | ),
143 | secondChild: Padding(
144 | padding: const EdgeInsets.only(top: 32.0),
145 | child: Text(
146 | 'Please wait ...',
147 | ),
148 | ),
149 | ),
150 | ],
151 | ),
152 | ],
153 | ),
154 | );
155 | }
156 |
157 | Future _handleSignIn() async {
158 | userCache.clear();
159 | await preferences.clearPreferences();
160 |
161 | setState(() => _isLoading = true);
162 |
163 | try {
164 | String userId = await api.initiateLogin();
165 | await preferences.setPreference(
166 | SharedPreferencesKeys.firebaseUserId, userId);
167 | await userCache.getUser(userId);
168 |
169 | if (!userCache.user.isContributor) {
170 | await Navigator.of(context).push(
171 | MaterialPageRoute(
172 | builder: (context) => FullScreenContributionDialog(),
173 | fullscreenDialog: true,
174 | ),
175 | );
176 | }
177 |
178 | Navigator.of(context).pushNamedAndRemoveUntil(
179 | Routes.home_master,
180 | ModalRoute.withName(Routes.main),
181 | );
182 | } catch (ex) {
183 | print(ex);
184 | Alert(
185 | context: context,
186 | type: AlertType.error,
187 | title: "Oops!",
188 | desc: "An error has occurred",
189 | buttons: [
190 | DialogButton(
191 | child: Text("Dismiss",
192 | style: Theme.of(context).textTheme.title.copyWith(
193 | color: Colors.white,
194 | )),
195 | color: Colors.red,
196 | onPressed: () {
197 | Navigator.of(context).pop();
198 | },
199 | )
200 | ],
201 | ).show();
202 | } finally {
203 | setState(() => _isLoading = false);
204 | }
205 | }
206 |
207 | void _getSharedPreferences() async {
208 | setState(() => _isFetchingSharedPreferences = true);
209 | try {
210 | var userId = await preferences.getValue(
211 | SharedPreferencesKeys.firebaseUserId);
212 | if (userId != null) {
213 | await userCache.getUser(userId);
214 | await Navigator.of(context).pushNamedAndRemoveUntil(
215 | Routes.home_master,
216 | ModalRoute.withName(Routes.main),
217 | );
218 | }
219 | } catch (ex) {
220 | print(ex);
221 | Alert(
222 | context: context,
223 | type: AlertType.error,
224 | title: "Oops!",
225 | desc: "An error has occurred",
226 | buttons: [
227 | DialogButton(
228 | child: Text("Dismiss",
229 | style: Theme.of(context).textTheme.title.copyWith(
230 | color: Colors.white,
231 | )),
232 | color: Colors.red,
233 | onPressed: () {
234 | Navigator.of(context).pop();
235 | },
236 | )
237 | ],
238 | ).show();
239 | } finally {
240 | setState(() {
241 | _isFetchingSharedPreferences = false;
242 | _showSwipeText = true;
243 | });
244 | }
245 | }
246 | }
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:firebase_core/firebase_core.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter/services.dart';
4 | import 'package:flutter_pk/global.dart';
5 | import 'package:flutter_pk/home/onboarding.dart';
6 | import 'package:flutter_pk/home/home_master.dart';
7 | import 'package:flutter_pk/theme.dart';
8 |
9 | void main() async {
10 | WidgetsFlutterBinding.ensureInitialized();
11 | await Firebase.initializeApp();
12 | runApp(MyApp());
13 | }
14 |
15 | class MyApp extends StatelessWidget {
16 | @override
17 | Widget build(BuildContext context) {
18 | SystemChrome.setSystemUIOverlayStyle(
19 | SystemUiOverlayStyle.dark,
20 | );
21 | return MaterialApp(
22 | debugShowCheckedModeBanner: false,
23 | title: 'Flutter Pakistan',
24 | theme: theme,
25 | home: OnboardingPage(title: 'Flutter Pakistan'),
26 | routes: {
27 | Routes.home_master: (context) => new HomePageMaster(),
28 | Routes.main: (context) => OnboardingPage()
29 | },
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/profile/profile_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_pk/caches/user.dart';
5 | import 'package:flutter_pk/contribution/contribution_dialog.dart';
6 | import 'package:flutter_pk/global.dart';
7 | import 'package:flutter_pk/helpers/shared_preferences.dart';
8 | import 'package:rflutter_alert/rflutter_alert.dart';
9 |
10 | class FullScreenProfileDialog extends StatefulWidget {
11 | @override
12 | FullScreenProfileDialogState createState() {
13 | return new FullScreenProfileDialogState();
14 | }
15 | }
16 |
17 | class FullScreenProfileDialogState extends State {
18 | InAppUser _user = new InAppUser();
19 | SharedPreferencesHandler preferences;
20 |
21 | @override
22 | void initState() {
23 | // TODO: implement initState
24 | super.initState();
25 | preferences = SharedPreferencesHandler();
26 | _setUser();
27 | }
28 |
29 | @override
30 | Widget build(BuildContext context) {
31 | return Scaffold(
32 | body: SafeArea(
33 | child: Column(
34 | crossAxisAlignment: CrossAxisAlignment.center,
35 | children: [
36 | _buildCustomAppBarSpace(context),
37 | _buildBody(),
38 | ],
39 | ),
40 | ),
41 | );
42 | }
43 |
44 | Padding _buildCustomAppBarSpace(BuildContext context) {
45 | return Padding(
46 | padding: const EdgeInsets.all(8.0),
47 | child: Padding(
48 | padding: const EdgeInsets.only(top: 16.0),
49 | child: Row(
50 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
51 | children: [
52 | GestureDetector(
53 | child: Icon(Icons.clear),
54 | onTap: () => Navigator.of(context).pop(),
55 | ),
56 | GestureDetector(
57 | child: Text(
58 | 'SIGN OUT',
59 | style: Theme.of(context).textTheme.subhead.copyWith(
60 | color: Theme.of(context).accentColor,
61 | ),
62 | ),
63 | onTap: () async {
64 | try {
65 | await googleSignIn.signOut();
66 | await auth.signOut();
67 | preferences.clearPreferences();
68 | userCache.clear();
69 | Navigator.of(context).pushNamedAndRemoveUntil(
70 | Routes.main,
71 | ModalRoute.withName(Routes.home_master),
72 | );
73 | } catch (ex) {
74 | print(ex);
75 | Alert(
76 | context: context,
77 | type: AlertType.error,
78 | title: "Oops!",
79 | desc: "An error has occurred",
80 | buttons: [
81 | DialogButton(
82 | child: Text("Dismiss",
83 | style: Theme.of(context).textTheme.title.copyWith(
84 | color: Colors.white,
85 | )),
86 | color: Colors.red,
87 | onPressed: () {
88 | Navigator.of(context).pop();
89 | Navigator.of(context).pop();
90 | },
91 | )
92 | ],
93 | ).show();
94 | }
95 | },
96 | )
97 | ],
98 | ),
99 | ),
100 | );
101 | }
102 |
103 | Widget _buildBody() {
104 | return Expanded(
105 | child: Column(
106 | crossAxisAlignment: CrossAxisAlignment.center,
107 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
108 | children: [
109 | Column(
110 | children: [
111 | Container(
112 | height: 70.0,
113 | width: 70.0,
114 | decoration: new BoxDecoration(
115 | shape: BoxShape.circle,
116 | image: new DecorationImage(
117 | fit: BoxFit.fill,
118 | image: NetworkImage(_user.photoUrl),
119 | ),
120 | ),
121 | ),
122 | Padding(
123 | padding: const EdgeInsets.only(top: 8.0),
124 | child: Text(
125 | _user.name,
126 | style: Theme.of(context)
127 | .textTheme
128 | .title
129 | .copyWith(color: Colors.grey),
130 | ),
131 | ),
132 | Text(
133 | _user.email,
134 | style: Theme.of(context)
135 | .textTheme
136 | .subhead
137 | .copyWith(color: Colors.black38),
138 | ),
139 | ],
140 | ),
141 | Padding(
142 | padding: const EdgeInsets.all(32.0),
143 | child: Text(
144 | 'You can provide session feedback after the event day ends.',
145 | textAlign: TextAlign.center,
146 | ),
147 | ),
148 | Expanded(
149 | child: Column(
150 | mainAxisAlignment: MainAxisAlignment.center,
151 | children: [],
152 | ),
153 | ),
154 | !_user.isContributor
155 | ? ListTile(
156 | title: Center(child: Text('Want to contribute?')),
157 | onTap: () async {
158 | await Navigator.of(context).push(
159 | MaterialPageRoute(
160 | builder: (context) => FullScreenContributionDialog(),
161 | fullscreenDialog: true,
162 | ),
163 | );
164 | var user = await userCache.getUser(
165 | userCache.user.id,
166 | useCached: false,
167 | );
168 | Timer(Duration(seconds: 2), () {
169 | setState(() {
170 | _user = user;
171 | });
172 | _setUser();
173 | });
174 | },
175 | )
176 | : Container(),
177 | Padding(
178 | padding: const EdgeInsets.only(left: 16.0, right: 16.0),
179 | child: SizedBox(
180 | height: 50.0,
181 | child: Image(
182 | image: AssetImage('assets/feature.png'),
183 | ),
184 | ),
185 | ),
186 | Padding(
187 | padding: const EdgeInsets.all(16.0),
188 | child: Text('Built with Flutter & Material'),
189 | ),
190 | ],
191 | ),
192 | );
193 | }
194 |
195 | Future _setUser() async {
196 | var user = await userCache.getUser(userCache.user.id);
197 | setState(() {
198 | _user = user;
199 | });
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/lib/registration/registration.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_pk/global.dart';
4 | import 'package:flutter_pk/helpers/regex-helpers.dart';
5 | import 'package:flutter_pk/widgets/dots_indicator.dart';
6 | import 'package:rflutter_alert/rflutter_alert.dart';
7 | import 'package:flutter_pk/widgets/full_screen_loader.dart';
8 |
9 | class RegistrationPage extends StatefulWidget {
10 | @override
11 | RegistrationPageState createState() {
12 | return new RegistrationPageState();
13 | }
14 | }
15 |
16 | class RegistrationPageState extends State {
17 | PageController controller = PageController();
18 | final GlobalKey _mobileNumberFormKey = new GlobalKey();
19 | final GlobalKey _studentProfessionalFormKey =
20 | new GlobalKey();
21 | final GlobalKey _designationFormKey = new GlobalKey();
22 | FocusNode focusNode = FocusNode();
23 | TextEditingController mobileNumberController = TextEditingController();
24 | TextEditingController designationController = TextEditingController();
25 | TextEditingController studentProfessionalController = TextEditingController();
26 | int pageViewItemCount = 3;
27 | bool _isStudent = false;
28 | bool _isLoading = false;
29 |
30 | @override
31 | void initState() {
32 | // TODO: implement initState
33 | super.initState();
34 | mobileNumberController.text = userCache.user.mobileNumber == null
35 | ? '+92'
36 | : userCache.user.mobileNumber;
37 | }
38 |
39 | @override
40 | Widget build(BuildContext context) {
41 | // TODO: implement build
42 | return Stack(
43 | children: [
44 | Scaffold(
45 | body: SafeArea(
46 | child: Column(
47 | mainAxisAlignment: MainAxisAlignment.start,
48 | crossAxisAlignment: CrossAxisAlignment.center,
49 | children: [
50 | Row(
51 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
52 | children: [
53 | IconButton(
54 | icon: Icon(Icons.clear),
55 | onPressed: () => Navigator.of(context).pop(),
56 | ),
57 | Text(
58 | 'Registration',
59 | style: Theme.of(context).textTheme.title,
60 | ),
61 | SizedBox(width: 48),
62 | ],
63 | ),
64 | Expanded(
65 | child: PageView(
66 | controller: controller,
67 | children: [
68 | userCache.user.mobileNumber == null
69 | ? _buildNumberSetupView(
70 | context,
71 | GlobalConstants.addNumberDisplayText,
72 | )
73 | : _buildNumberSetupView(
74 | context,
75 | GlobalConstants.editNumberDisplayText,
76 | ),
77 | _buildStudentProfessionalView(),
78 | _buildWorkInstituteEntryView(),
79 | _buildDesignationEntryView()
80 | ],
81 | physics: NeverScrollableScrollPhysics(),
82 | scrollDirection: Axis.horizontal,
83 | ),
84 | ),
85 | DotsIndicator(
86 | controller: controller,
87 | itemCount: pageViewItemCount,
88 | activeColor: Theme.of(context).primaryColor,
89 | inactiveColor: Colors.grey,
90 | ),
91 | ],
92 | ),
93 | ),
94 | ),
95 | _isLoading ? FullScreenLoader() : Container()
96 | ],
97 | );
98 | }
99 |
100 | Widget _buildNumberSetupView(BuildContext context, String displayText) {
101 | return Center(
102 | child: SingleChildScrollView(
103 | child: Column(
104 | mainAxisSize: MainAxisSize.min,
105 | mainAxisAlignment: MainAxisAlignment.center,
106 | children: [
107 | Padding(
108 | padding: const EdgeInsets.only(left: 128.0, right: 128.0),
109 | child: Center(
110 | child: Image(
111 | image: AssetImage('assets/ic_phone_setup.png'),
112 | color: Theme.of(context).primaryColor,
113 | width: 120,
114 | ),
115 | ),
116 | ),
117 | Padding(
118 | padding: const EdgeInsets.only(
119 | top: 16.0,
120 | bottom: 16.0,
121 | left: 32.0,
122 | right: 32.0,
123 | ),
124 | child: Text(
125 | displayText,
126 | textAlign: TextAlign.center,
127 | style: Theme.of(context).textTheme.subhead,
128 | ),
129 | ),
130 | Form(
131 | key: _mobileNumberFormKey,
132 | child: ListTile(
133 | title: TextFormField(
134 | focusNode: focusNode,
135 | controller: mobileNumberController,
136 | maxLength: GlobalConstants.phoneNumberMaxLength,
137 | validator: (value) => _validatePhoneNumber(value),
138 | keyboardType: TextInputType.phone,
139 | decoration: InputDecoration(
140 | border: OutlineInputBorder(
141 | borderRadius: BorderRadius.circular(10.0)),
142 | hintText: 'Enter mobile number',
143 | labelText: 'Mobile number'),
144 | ),
145 | ),
146 | ),
147 | Divider(),
148 | Row(
149 | children: [
150 | Expanded(
151 | child: FlatButton(
152 | child: Row(
153 | mainAxisAlignment: MainAxisAlignment.end,
154 | children: [
155 | Text('NEXT'),
156 | Icon(
157 | Icons.arrow_forward,
158 | size: 24.0,
159 | )
160 | ],
161 | ),
162 | textColor: Theme.of(context).primaryColor,
163 | onPressed: () {
164 | if (_mobileNumberFormKey.currentState.validate()) {
165 | focusNode.unfocus();
166 | controller.animateToPage(1,
167 | duration: Duration(milliseconds: 500),
168 | curve: Curves.fastOutSlowIn);
169 | }
170 | },
171 | ),
172 | )
173 | ],
174 | )
175 | ],
176 | ),
177 | ),
178 | );
179 | }
180 |
181 | Center _buildStudentProfessionalView() {
182 | return Center(
183 | child: SingleChildScrollView(
184 | child: Column(
185 | mainAxisSize: MainAxisSize.min,
186 | mainAxisAlignment: MainAxisAlignment.center,
187 | children: [
188 | Center(
189 | child: IconTheme(
190 | data: IconThemeData(color: Colors.blueGrey),
191 | child: Row(
192 | mainAxisAlignment: MainAxisAlignment.center,
193 | children: [
194 | Icon(
195 | Icons.work,
196 | size: 48.0,
197 | ),
198 | SizedBox(width: 8),
199 | Icon(
200 | Icons.laptop_mac,
201 | size: 80.0,
202 | ),
203 | SizedBox(width: 8),
204 | Icon(
205 | Icons.school,
206 | size: 48.0,
207 | ),
208 | ],
209 | ),
210 | ),
211 | ),
212 | Padding(
213 | padding: const EdgeInsets.only(
214 | top: 16.0,
215 | bottom: 16.0,
216 | left: 32.0,
217 | right: 32.0,
218 | ),
219 | child: Text(
220 | 'Which one of the following best describes you?',
221 | textAlign: TextAlign.center,
222 | style: Theme.of(context).textTheme.title,
223 | ),
224 | ),
225 | ButtonBar(
226 | mainAxisSize: MainAxisSize.min,
227 | children: [
228 | RaisedButton(
229 | child: Text('STUDENT'),
230 | onPressed: () {
231 | setState(() {
232 | _isStudent = true;
233 | pageViewItemCount = 3;
234 | });
235 | controller.animateToPage(2,
236 | duration: Duration(milliseconds: 500),
237 | curve: Curves.fastOutSlowIn);
238 | },
239 | ),
240 | RaisedButton(
241 | child: Text('PROFESSIONAL'),
242 | onPressed: () {
243 | setState(() {
244 | _isStudent = false;
245 | pageViewItemCount = 4;
246 | });
247 | controller.animateToPage(2,
248 | duration: Duration(milliseconds: 500),
249 | curve: Curves.fastOutSlowIn);
250 | },
251 | ),
252 | ],
253 | ),
254 | Divider(),
255 | Row(
256 | children: [
257 | Expanded(
258 | child: FlatButton(
259 | child: Row(
260 | mainAxisAlignment: MainAxisAlignment.start,
261 | children: [
262 | Icon(
263 | Icons.arrow_back,
264 | size: 24.0,
265 | ),
266 | Text('BACK'),
267 | ],
268 | ),
269 | textColor: Theme.of(context).primaryColor,
270 | onPressed: () {
271 | controller.animateToPage(0,
272 | duration: Duration(milliseconds: 500),
273 | curve: Curves.fastOutSlowIn);
274 | },
275 | ),
276 | )
277 | ],
278 | )
279 | ],
280 | ),
281 | ),
282 | );
283 | }
284 |
285 | Center _buildWorkInstituteEntryView() {
286 | return Center(
287 | child: SingleChildScrollView(
288 | child: Column(
289 | mainAxisSize: MainAxisSize.min,
290 | mainAxisAlignment: MainAxisAlignment.center,
291 | children: [
292 | Icon(
293 | _isStudent ? Icons.school : Icons.work,
294 | size: 100.0,
295 | color: Theme.of(context).primaryColor,
296 | ),
297 | Padding(
298 | padding: const EdgeInsets.only(
299 | top: 16.0,
300 | bottom: 16.0,
301 | left: 32.0,
302 | right: 32.0,
303 | ),
304 | child: Text(
305 | 'Where do you ${_isStudent ? 'study' : 'work'}?',
306 | textAlign: TextAlign.center,
307 | style: Theme.of(context).textTheme.title,
308 | ),
309 | ),
310 | Form(
311 | key: _studentProfessionalFormKey,
312 | child: ListTile(
313 | title: TextFormField(
314 | focusNode: focusNode,
315 | controller: studentProfessionalController,
316 | maxLength: GlobalConstants.entryMaxLength,
317 | validator: (value) =>
318 | _validateStudentProfessionalEntry(value),
319 | decoration: InputDecoration(
320 | border: OutlineInputBorder(
321 | borderRadius: BorderRadius.circular(10.0)),
322 | hintText:
323 | 'Enter ${_isStudent ? 'institute' : 'workplace'}',
324 | labelText: '${_isStudent ? 'Institute' : 'Workplace'}'),
325 | ),
326 | ),
327 | ),
328 | Divider(),
329 | Row(
330 | children: [
331 | Expanded(
332 | child: FlatButton(
333 | child: Row(
334 | mainAxisAlignment: MainAxisAlignment.start,
335 | children: [
336 | Icon(
337 | Icons.arrow_back,
338 | size: 24.0,
339 | ),
340 | Text('BACK'),
341 | ],
342 | ),
343 | textColor: Theme.of(context).primaryColor,
344 | onPressed: () {
345 | controller.animateToPage(1,
346 | duration: Duration(milliseconds: 500),
347 | curve: Curves.fastOutSlowIn);
348 | },
349 | ),
350 | ),
351 | Expanded(
352 | child: FlatButton(
353 | child: Row(
354 | mainAxisAlignment: MainAxisAlignment.end,
355 | children: [
356 | Text(_isStudent ? 'DONE' : 'NEXT'),
357 | Icon(
358 | _isStudent ? Icons.check_circle : Icons.arrow_forward,
359 | size: 24.0,
360 | ),
361 | ],
362 | ),
363 | textColor: Theme.of(context).primaryColor,
364 | onPressed: () async {
365 | focusNode.unfocus();
366 | if (_studentProfessionalFormKey.currentState.validate()) {
367 | if (_isStudent) {
368 | await _submitDataToFirestore();
369 | Alert(
370 | context: context,
371 | type: AlertType.success,
372 | title: "Success!",
373 | desc:
374 | "Your are registered successfully!\nYou will receive a confirmation message soon!",
375 | buttons: [
376 | DialogButton(
377 | child: Text("COOL!",
378 | style: Theme.of(context)
379 | .textTheme
380 | .title
381 | .copyWith(
382 | color: Colors.white,
383 | )),
384 | onPressed: () {
385 | Navigator.of(context).pop();
386 | Navigator.of(context).pop();
387 | },
388 | )
389 | ],
390 | ).show();
391 | } else {
392 | controller.animateToPage(3,
393 | duration: Duration(milliseconds: 500),
394 | curve: Curves.fastOutSlowIn);
395 | }
396 | }
397 | },
398 | ),
399 | )
400 | ],
401 | )
402 | ],
403 | ),
404 | ),
405 | );
406 | }
407 |
408 | Center _buildDesignationEntryView() {
409 | return Center(
410 | child: SingleChildScrollView(
411 | child: Column(
412 | mainAxisSize: MainAxisSize.min,
413 | mainAxisAlignment: MainAxisAlignment.center,
414 | children: [
415 | Icon(
416 | Icons.account_box,
417 | size: 100.0,
418 | color: Theme.of(context).primaryColor,
419 | ),
420 | Padding(
421 | padding: const EdgeInsets.only(
422 | top: 16.0,
423 | bottom: 16.0,
424 | left: 32.0,
425 | right: 32.0,
426 | ),
427 | child: Text(
428 | 'Your designation at ${studentProfessionalController.text}',
429 | textAlign: TextAlign.center,
430 | style: Theme.of(context).textTheme.title,
431 | ),
432 | ),
433 | Form(
434 | key: _designationFormKey,
435 | child: ListTile(
436 | title: TextFormField(
437 | focusNode: focusNode,
438 | controller: designationController,
439 | maxLength: GlobalConstants.entryMaxLength,
440 | validator: (value) => _validateDesignation(value),
441 | decoration: InputDecoration(
442 | border: OutlineInputBorder(
443 | borderRadius: BorderRadius.circular(10.0)),
444 | hintText: 'Enter designation',
445 | labelText: 'Designation',
446 | ),
447 | ),
448 | ),
449 | ),
450 | Divider(),
451 | Row(
452 | children: [
453 | Expanded(
454 | child: FlatButton(
455 | child: Row(
456 | mainAxisAlignment: MainAxisAlignment.start,
457 | children: [
458 | Icon(
459 | Icons.arrow_back,
460 | size: 24.0,
461 | ),
462 | Text('BACK'),
463 | ],
464 | ),
465 | textColor: Theme.of(context).primaryColor,
466 | onPressed: () {
467 | controller.animateToPage(1,
468 | duration: Duration(milliseconds: 500),
469 | curve: Curves.fastOutSlowIn);
470 | },
471 | ),
472 | ),
473 | Expanded(
474 | child: FlatButton(
475 | child: Row(
476 | mainAxisAlignment: MainAxisAlignment.end,
477 | children: [
478 | Text('DONE'),
479 | Icon(
480 | Icons.check_circle,
481 | size: 24.0,
482 | ),
483 | ],
484 | ),
485 | textColor: Theme.of(context).primaryColor,
486 | onPressed: () async {
487 | focusNode.unfocus();
488 | if (_designationFormKey.currentState.validate()) {
489 | await _submitDataToFirestore();
490 | Alert(
491 | context: context,
492 | type: AlertType.success,
493 | title: "Success!",
494 | desc:
495 | "Your are registered successfully!\nYou will receive a confirmation message soon!",
496 | buttons: [
497 | DialogButton(
498 | child: Text("COOL!",
499 | style: Theme.of(context)
500 | .textTheme
501 | .title
502 | .copyWith(
503 | color: Colors.white,
504 | )),
505 | onPressed: () {
506 | Navigator.of(context).pop();
507 | Navigator.of(context).pop();
508 | },
509 | )
510 | ],
511 | ).show();
512 | }
513 | },
514 | ),
515 | )
516 | ],
517 | )
518 | ],
519 | ),
520 | ),
521 | );
522 | }
523 |
524 | String _validatePhoneNumber(String number) {
525 | if (number.isEmpty) return 'Phone number required';
526 | if (number.length < GlobalConstants.phoneNumberMaxLength ||
527 | !RegexHelpers.phoneNumberRegex.hasMatch(number))
528 | return 'You wouldn\'t want to miss any important update! \nPlease enter a valid mobile number';
529 | }
530 |
531 | String _validateDesignation(String number) {
532 | if (number.isEmpty) return 'Designation required';
533 | }
534 |
535 | String _validateStudentProfessionalEntry(String number) {
536 | if (number.isEmpty)
537 | return '${_isStudent ? 'Institute' : 'Workplace'} required';
538 | return null;
539 | }
540 |
541 | Future _submitDataToFirestore() async {
542 | setState(() => _isLoading = true);
543 | try {
544 | FirebaseFirestore.instance.runTransaction((transaction) async {
545 | await transaction.update(userCache.user.reference, {
546 | 'registration': Registration(
547 | occupation: _isStudent ? 'Student' : 'Professional',
548 | workOrInstitute: studentProfessionalController.text,
549 | designation: designationController.text,
550 | ).toJson(),
551 | 'mobileNumber': mobileNumberController.text,
552 | 'isRegistered': true
553 | });
554 | });
555 |
556 | await userCache.getUser(userCache.user.id, useCached: false);
557 | } catch (ex) {
558 | print(ex);
559 | Alert(
560 | context: context,
561 | type: AlertType.error,
562 | title: "Oops!",
563 | desc: "An error has occurred",
564 | buttons: [
565 | DialogButton(
566 | child: Text("Dismiss",
567 | style: Theme.of(context).textTheme.title.copyWith(
568 | color: Colors.white,
569 | )),
570 | color: Colors.red,
571 | onPressed: () {
572 | Navigator.of(context).pop();
573 | Navigator.of(context).pop();
574 | },
575 | )
576 | ],
577 | ).show();
578 | } finally {
579 | setState(() => _isLoading = false);
580 | }
581 | }
582 | }
583 |
584 | class Registration {
585 | final String occupation;
586 | final String workOrInstitute;
587 | final String designation;
588 | final DocumentReference reference;
589 |
590 | Registration({
591 | this.occupation,
592 | this.designation = 'not applicable',
593 | this.workOrInstitute,
594 | this.reference,
595 | });
596 |
597 | Registration.fromMap(Map map, {this.reference})
598 | : occupation = map['occupation'],
599 | designation = map['designation'],
600 | workOrInstitute = map['workOrInstitute'];
601 |
602 | Map toJson() => {
603 | "occupation": this.occupation,
604 | "workOrInstitute": this.workOrInstitute,
605 | "designation": this.designation,
606 | };
607 |
608 | Registration.fromSnapshot(DocumentSnapshot snapshot)
609 | : this.fromMap(snapshot.data(), reference: snapshot.reference);
610 | }
611 |
--------------------------------------------------------------------------------
/lib/schedule/model.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:flutter_pk/global.dart';
3 | import 'package:flutter_pk/util.dart';
4 |
5 | class ScheduleApi {
6 | Future> getSessionList() async {
7 | var date = await FirebaseFirestore.instance
8 | .collection(FireStoreKeys.dateCollection)
9 | .snapshots()
10 | .first;
11 |
12 | var sessionCollection = date.docs.first.reference
13 | .collection(FireStoreKeys.sessionCollection);
14 |
15 | var sessionList = await sessionCollection.get();
16 |
17 | return sessionList.docs
18 | .map((item) => Session.fromSnapshot(item))
19 | .toList();
20 | }
21 | }
22 |
23 | class Speaker {
24 | final String id;
25 | final String name;
26 | final String photoUrl;
27 | final String description;
28 | final DocumentReference reference;
29 |
30 | Speaker({
31 | this.name,
32 | this.id,
33 | this.description,
34 | this.reference,
35 | this.photoUrl,
36 | });
37 |
38 | Speaker.fromMap(Map map, {this.reference})
39 | : id = map['id'],
40 | description = map['description'],
41 | name = map['name'],
42 | photoUrl = map['photoUrl'];
43 |
44 | Map toJson() => {
45 | "id": id,
46 | "name": name,
47 | "description": description,
48 | "photoUrl": photoUrl,
49 | };
50 |
51 | Speaker.fromSnapshot(DocumentSnapshot snapshot)
52 | : this.fromMap(snapshot.data(), reference: snapshot.reference);
53 | }
54 |
55 | class Session {
56 | final String id;
57 | final String title;
58 | final DateTime startDateTime;
59 | final DateTime endDateTime;
60 | final String color;
61 | final String textColor;
62 | final String description;
63 | final String speakerId;
64 | final List speakers;
65 | final DocumentReference reference;
66 |
67 | Session(
68 | {this.id,
69 | this.title,
70 | this.endDateTime,
71 | this.startDateTime,
72 | this.color,
73 | this.textColor,
74 | this.description,
75 | this.speakerId,
76 | this.reference,
77 | this.speakers});
78 |
79 | Session.fromMap(Map map, {this.reference})
80 | : id = map['id'],
81 | title = map['title'],
82 | endDateTime = toDateTime(map['endDateTime']),
83 | startDateTime = toDateTime(map['startDateTime']),
84 | color = map['color'],
85 | textColor = map['textColor'],
86 | speakerId = map['speakerId'],
87 | speakers = map['speakers'],
88 | description = map['description'];
89 |
90 | Session.fromSnapshot(DocumentSnapshot snapshot)
91 | : this.fromMap(snapshot.data(), reference: snapshot.reference);
92 | }
93 |
--------------------------------------------------------------------------------
/lib/schedule/schedule_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_pk/helpers/formatters.dart';
3 | import 'package:flutter_pk/schedule/model.dart';
4 | import 'package:flutter_pk/schedule/session_detail.dart';
5 | import 'package:flutter_pk/theme.dart';
6 | import 'package:flutter_pk/widgets/custom_app_bar.dart';
7 | import 'package:progress_indicators/progress_indicators.dart';
8 |
9 | class SchedulePage extends StatefulWidget {
10 | @override
11 | SchedulePageState createState() {
12 | return new SchedulePageState();
13 | }
14 | }
15 |
16 | class SchedulePageState extends State
17 | with SingleTickerProviderStateMixin {
18 | ScheduleApi api = ScheduleApi();
19 |
20 | @override
21 | void initState() {
22 | // TODO: implement initState
23 | super.initState();
24 | _fetchSessions();
25 | }
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | return Scaffold(
30 | body: SafeArea(
31 | child: Column(
32 | children: [
33 | CustomAppBar(
34 | title: 'Schedule',
35 | ),
36 | _buildList()
37 | ],
38 | ),
39 | ),
40 | );
41 | }
42 |
43 | Widget _buildList() {
44 | return Expanded(
45 | child: FutureBuilder>(
46 | future: _fetchSessions(),
47 | builder: (context, snapshot) {
48 | if (!snapshot.hasData) {
49 | return Center(
50 | child: HeartbeatProgressIndicator(
51 | child: SizedBox(
52 | height: 40.0,
53 | width: 40.0,
54 | child: Image(image: AssetImage('assets/loader.png')),
55 | ),
56 | ),
57 | );
58 | } else {
59 | var sessions = snapshot.data;
60 | return ListView.builder(
61 | itemCount: sessions.length,
62 | itemBuilder: (BuildContext context, int index) {
63 | return _buildListItem(context, sessions[index]);
64 | },
65 | padding: const EdgeInsets.only(top: 20.0),
66 | );
67 | }
68 | },
69 | ),
70 | );
71 | }
72 |
73 | Widget _buildListItem(BuildContext context, Session session) {
74 | var hour = session.startDateTime?.hour;
75 | var minute = session.startDateTime?.minute;
76 |
77 | if (hour == null || minute == null)
78 | return Center(
79 | child: Text(
80 | 'Nothing found!',
81 | style: Theme.of(context).textTheme.title.copyWith(
82 | color: Colors.black26,
83 | fontWeight: FontWeight.bold,
84 | ),
85 | ),
86 | );
87 |
88 | return Column(
89 | children: [
90 | Row(
91 | children: [
92 | Padding(
93 | padding: const EdgeInsets.only(left: 16.0, right: 16.0),
94 | child: Column(
95 | children: [
96 | Text(
97 | '${_formatTimeDigit(hour)}:${_formatTimeDigit(minute)}',
98 | style: TextStyle(
99 | color: Theme.of(context).primaryColor,
100 | fontWeight: FontWeight.bold),
101 | ),
102 | Text(
103 | 'HRS',
104 | style: TextStyle(
105 | color: Theme.of(context).primaryColor,
106 | fontWeight: FontWeight.bold),
107 | )
108 | ],
109 | ),
110 | ),
111 | Expanded(
112 | child: Container(
113 | decoration: BoxDecoration(
114 | color: ColorDictionary.stringToColor[session?.color],
115 | borderRadius: BorderRadius.only(
116 | topLeft: Radius.circular(10.0),
117 | bottomLeft: Radius.circular(10.0),
118 | ),
119 | ),
120 | child: ListTile(
121 | title: Text(
122 | session.title,
123 | style: TextStyle(
124 | color: ColorDictionary
125 | .stringToColor[session?.textColor]),
126 | ),
127 | subtitle: Text(
128 | '${formatDate(
129 | session?.startDateTime,
130 | DateFormats.shortUiDateTimeFormat,
131 | )} - ${formatDate(
132 | session?.endDateTime,
133 | DateFormats.shortUiTimeFormat,
134 | )}',
135 | style: TextStyle(
136 | color:
137 | ColorDictionary.stringToColor[session?.textColor],
138 | ),
139 | ),
140 | onTap: () => _handleListTileOnTap(context, session)),
141 | ),
142 | ),
143 | ],
144 | ),
145 | Padding(
146 | padding: const EdgeInsets.only(top: 16.0),
147 | ),
148 | ],
149 | );
150 | }
151 |
152 | String _formatTimeDigit(int timeValue) =>
153 | timeValue < 10 ? '0' + timeValue.toString() : timeValue.toString();
154 |
155 | Future _handleListTileOnTap(BuildContext context, Session session) async {
156 | var isDescriptionAvailable =
157 | session.description != null && session.description.isNotEmpty;
158 | if (isDescriptionAvailable)
159 | await Navigator.of(context).push(
160 | MaterialPageRoute(
161 | builder: (context) => SessionDetailPage(
162 | session: session,
163 | ),
164 | ),
165 | );
166 | }
167 |
168 | Future> _fetchSessions() async {
169 | try {
170 | var response = await api.getSessionList();
171 | return response;
172 | } catch (ex) {
173 | print(ex);
174 | return null;
175 | }
176 | }
177 | }
178 |
--------------------------------------------------------------------------------
/lib/schedule/session_detail.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:cloud_firestore/cloud_firestore.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_pk/feedback/feedback.dart';
6 | import 'package:flutter_pk/global.dart';
7 | import 'package:flutter_pk/schedule/model.dart';
8 | import 'package:cached_network_image/cached_network_image.dart';
9 | import 'package:flutter_pk/theme.dart';
10 | import 'package:rflutter_alert/rflutter_alert.dart';
11 |
12 | class SessionDetailPage extends StatelessWidget {
13 | final Session session;
14 | SessionDetailPage({@required this.session});
15 |
16 | @override
17 | Widget build(BuildContext context) {
18 | var textColor = ColorDictionary.stringToColor[session.textColor];
19 |
20 | return Scaffold(
21 | appBar: AppBar(
22 | brightness: Brightness.dark,
23 | iconTheme: IconThemeData(color: textColor),
24 | title: Text(
25 | session.title,
26 | style: TextStyle(color: textColor),
27 | ),
28 | backgroundColor: ColorDictionary.stringToColor[session.color],
29 | ),
30 | floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
31 | floatingActionButton: _buildFeedbackButton(context),
32 | body: _buildBody(showSpeakerInfo: session.speakers != null && session.speakers.length > 0),
33 | );
34 | }
35 |
36 | FloatingActionButton _buildFeedbackButton(BuildContext context) {
37 | return FloatingActionButton.extended(
38 | onPressed: () {
39 | if (DateTime.now().isAfter(
40 | eventDateTimeCache.eventDateTime.add(
41 | Duration(days: 1),
42 | ),
43 | )) {
44 | _navigateToFeedback(context);
45 | } else {
46 | Alert(
47 | context: context,
48 | type: AlertType.info,
49 | title: "Information!",
50 | desc:
51 | "You will be able to provide feedback once the event day ends!",
52 | buttons: [
53 | DialogButton(
54 | child: Text("Cool!",
55 | style: Theme.of(context).textTheme.title.copyWith(
56 | color: Colors.white,
57 | )),
58 | color: Colors.green,
59 | onPressed: () {
60 | Navigator.of(context).pop();
61 | },
62 | )
63 | ],
64 | ).show();
65 | }
66 | },
67 | icon: Icon(
68 | Icons.rate_review,
69 | color: ColorDictionary.stringToColor[session.textColor],
70 | ),
71 | label: Text(
72 | 'Feedback',
73 | style: TextStyle(
74 | color: ColorDictionary.stringToColor[session.textColor]),
75 | ),
76 | backgroundColor: ColorDictionary.stringToColor[session.color],
77 | );
78 | }
79 |
80 | Widget _buildBody({@required bool showSpeakerInfo}) {
81 | var bodyWidgets = [];
82 |
83 | if (showSpeakerInfo) {
84 | bodyWidgets.addAll(
85 | [
86 | Padding(
87 | padding: const EdgeInsets.only(top: 8.0),
88 | child: Center(
89 | child: Text(
90 | 'About ${session.speakers.length > 1 ? 'speakers' : 'speaker'}'),
91 | ),
92 | ),
93 | session.speakers.length > 1
94 | ? _buildMultiSpeakerDetail()
95 | : _buildSingleSpeakerDetail(),
96 | Divider(),
97 | ],
98 | );
99 | }
100 |
101 | bodyWidgets.addAll(
102 | [
103 | Padding(
104 | padding: const EdgeInsets.all(16.0),
105 | child: Container(
106 | decoration: BoxDecoration(
107 | color: ColorDictionary.stringToColor[session.color],
108 | borderRadius: BorderRadius.circular(10.0)),
109 | child: ListTile(
110 | title: Padding(
111 | padding: const EdgeInsets.only(top: 8.0),
112 | child: Center(
113 | child: Text(
114 | session.title,
115 | style: TextStyle(
116 | fontWeight: FontWeight.bold,
117 | color: ColorDictionary.stringToColor[session.textColor],
118 | ),
119 | ),
120 | ),
121 | ),
122 | subtitle: Padding(
123 | padding: const EdgeInsets.only(top: 16.0, bottom: 8.0),
124 | child: Text(
125 | session.description,
126 | style: TextStyle(
127 | color: ColorDictionary.stringToColor[session.textColor]),
128 | ),
129 | ),
130 | ),
131 | ),
132 | ),
133 | SizedBox(
134 | height: 60.0,
135 | ),
136 | ],
137 | );
138 |
139 | return SingleChildScrollView(
140 | child: Padding(
141 | padding: const EdgeInsets.only(top: 8.0),
142 | child: Column(
143 | children: [
144 | Center(
145 | child: Column(
146 | mainAxisAlignment: MainAxisAlignment.center,
147 | children: bodyWidgets,
148 | ),
149 | ),
150 | ],
151 | ),
152 | ),
153 | );
154 | }
155 |
156 | void _navigateToFeedback(BuildContext context) {
157 | Navigator.of(context).push(
158 | MaterialPageRoute(
159 | builder: (context) => FullScreenFeedbackDialog(
160 | session: session,
161 | ),
162 | fullscreenDialog: true),
163 | );
164 | }
165 |
166 | FutureBuilder> _buildMultiSpeakerDetail() {
167 | return FutureBuilder>(
168 | future: _getMultiSpeakerData(),
169 | builder: (context, snapshot) {
170 | if (snapshot.hasData) {
171 | var speakerOne = snapshot.data.first;
172 | var speakerTwo = snapshot.data[1];
173 | return Row(
174 | crossAxisAlignment: CrossAxisAlignment.start,
175 | children: [
176 | Expanded(child: _buildSpeakerView(speakerOne)),
177 | Expanded(child: _buildSpeakerView(speakerTwo)),
178 | ],
179 | );
180 | } else {
181 | return Center(
182 | child: Text(
183 | 'Fetching speaker details',
184 | style: Theme.of(context)
185 | .textTheme
186 | .title
187 | .copyWith(color: Colors.grey),
188 | ),
189 | );
190 | }
191 | });
192 | }
193 |
194 | FutureBuilder _buildSingleSpeakerDetail() {
195 | return FutureBuilder(
196 | future: _getData(),
197 | builder: (context, snapshot) {
198 | if (snapshot.hasData) {
199 | return _buildSpeakerView(snapshot.data);
200 | } else {
201 | return Center(
202 | child: Text(
203 | 'Fetching speaker details',
204 | style: Theme.of(context)
205 | .textTheme
206 | .title
207 | .copyWith(color: Colors.grey),
208 | ),
209 | );
210 | }
211 | });
212 | }
213 |
214 | Column _buildSpeakerView(Speaker speaker) {
215 | return Column(
216 | children: [
217 | Padding(
218 | padding: const EdgeInsets.only(top: 16.0),
219 | child: Center(
220 | child: Stack(
221 | children: [
222 | Container(
223 | height: 70.0,
224 | width: 70.0,
225 | decoration: new BoxDecoration(
226 | shape: BoxShape.circle,
227 | image: DecorationImage(
228 | image: AssetImage(
229 | 'assets/ic_person.png',
230 | ),
231 | ),
232 | ),
233 | ),
234 | Container(
235 | height: 70.0,
236 | width: 70.0,
237 | decoration: new BoxDecoration(
238 | shape: BoxShape.circle,
239 | image: DecorationImage(
240 | image: CachedNetworkImageProvider(
241 | speaker.photoUrl,
242 | ),
243 | ),
244 | ),
245 | ),
246 | ],
247 | ),
248 | ),
249 | ),
250 | ListTile(
251 | title: Padding(
252 | padding: const EdgeInsets.all(0.0),
253 | child: Column(
254 | children: [
255 | Text(
256 | speaker.name,
257 | style: TextStyle(
258 | fontWeight: FontWeight.bold,
259 | ),
260 | ),
261 | Padding(
262 | padding: const EdgeInsets.only(top: 16.0),
263 | child: Text(
264 | speaker.description,
265 | ),
266 | ),
267 | ],
268 | ),
269 | ),
270 | ),
271 | ],
272 | );
273 | }
274 |
275 | Future _getData() async {
276 | CollectionReference reference =
277 | await FirebaseFirestore.instance.collection(FireStoreKeys.speakerCollection);
278 | var speaker =
279 | Speaker.fromSnapshot(await reference.document(session.speakerId).get());
280 | return speaker;
281 | }
282 |
283 | Future> _getMultiSpeakerData() async {
284 | CollectionReference reference =
285 | await FirebaseFirestore.instance.collection(FireStoreKeys.speakerCollection);
286 | var speakerOne = Speaker.fromSnapshot(
287 | await reference.document(session.speakers[0]).get());
288 | var speakerTwo = Speaker.fromSnapshot(
289 | await reference.document(session.speakers[1]).get());
290 | List list = List();
291 | list.addAll([
292 | speakerOne,
293 | speakerTwo,
294 | ]);
295 | return list;
296 | }
297 | }
298 |
--------------------------------------------------------------------------------
/lib/theme.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | abstract class ColorDictionary {
4 | static const Map stringToColor = {
5 | 'indigo': Colors.indigo,
6 | 'green': Colors.green,
7 | 'amber': Colors.amber,
8 | 'blue': Colors.blue,
9 | 'white': Colors.white,
10 | 'black': Colors.black,
11 | 'blueGrey': Colors.blueGrey,
12 | 'lightBlue': Colors.lightBlue,
13 | 'brown': Colors.brown,
14 | 'teal': Colors.teal,
15 | 'indigoAccent': Colors.indigoAccent,
16 | 'grey': Colors.grey
17 | };
18 | }
19 |
20 | const Color kBlue = Colors.blue;
21 | final theme = _buildTheme();
22 |
23 | ThemeData _buildTheme() {
24 | var base = ThemeData.light();
25 | print('font size of theme: ${base.primaryTextTheme.title.fontSize}');
26 |
27 | return base.copyWith(
28 | primaryColor: kBlue,
29 | accentColor: kBlue,
30 | canvasColor: Colors.white,
31 | scaffoldBackgroundColor: Colors.white,
32 | appBarTheme: AppBarTheme(
33 | brightness: Brightness.light,
34 | iconTheme: base.iconTheme.copyWith(color: Colors.black),
35 | color: Colors.white,
36 | textTheme: base.primaryTextTheme.copyWith(
37 | title: TextStyle(
38 | fontWeight: FontWeight.w500,
39 | fontSize: 20,
40 | )
41 | ).apply(bodyColor: Colors.black),
42 | ),
43 | buttonTheme: base.buttonTheme.copyWith(
44 | buttonColor: kBlue,
45 | textTheme: ButtonTextTheme.primary,
46 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
47 | ),
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/lib/util.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 |
3 | DateTime toDateTime(Timestamp timestamp) => timestamp.toDate();
--------------------------------------------------------------------------------
/lib/venue_detail.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_pk/global.dart';
4 | import 'package:flutter_pk/venue_model.dart';
5 | import 'package:google_maps_flutter/google_maps_flutter.dart';
6 | import 'package:progress_indicators/progress_indicators.dart';
7 |
8 | class VenueDetailPage extends StatefulWidget {
9 | @override
10 | VenueDetailPageState createState() {
11 | return new VenueDetailPageState();
12 | }
13 | }
14 |
15 | class VenueDetailPageState extends State {
16 | GoogleMapController mapController;
17 | bool _isLoading = false;
18 | Venue _venue = new Venue();
19 | Map markers = {};
20 |
21 | void _onMapCreated(GoogleMapController controller) {
22 | mapController = controller;
23 | _addMarker(_venue);
24 | }
25 |
26 | @override
27 | void initState() {
28 | // TODO: implement initState
29 | super.initState();
30 | _getData();
31 | }
32 |
33 | @override
34 | Widget build(BuildContext context) {
35 | // TODO: implement build
36 | return Scaffold(
37 | body: Column(
38 | children: [_buildBody()],
39 | ),
40 | );
41 | }
42 |
43 | Widget _buildBody() {
44 | return Expanded(
45 | child: _isLoading
46 | ? Center(
47 | child: HeartbeatProgressIndicator(
48 | child: SizedBox(
49 | height: 40.0,
50 | width: 40.0,
51 | child: Image(
52 | image: AssetImage('assets/map.png'),
53 | color: Theme.of(context).primaryColor,
54 | ),
55 | )),
56 | )
57 | : Stack(
58 | children: [
59 | GoogleMap(
60 | onMapCreated: _onMapCreated,
61 | mapType: MapType.normal,
62 | zoomGesturesEnabled: true,
63 | compassEnabled: true,
64 | rotateGesturesEnabled: true,
65 | scrollGesturesEnabled: true,
66 | markers: Set.of(markers.values),
67 | initialCameraPosition: CameraPosition(
68 | target: LatLng(
69 | _venue.location.latitude,
70 | _venue.location.longitude,
71 | ),
72 | zoom: 15.0),
73 | ),
74 | SafeArea(
75 | child: Padding(
76 | padding: const EdgeInsets.all(8.0),
77 | child: Row(
78 | children: [
79 | Expanded(
80 | child: Card(
81 | elevation: 4.0,
82 | child: Column(
83 | mainAxisSize: MainAxisSize.min,
84 | children: [
85 | Padding(
86 | padding: const EdgeInsets.only(
87 | left: 64.0, right: 64.0, top: 16.0),
88 | child: Image(
89 | image: NetworkImage(
90 | _venue.imageUrl,
91 | scale: 0.5,
92 | ),
93 | ),
94 | ),
95 | Padding(
96 | padding: const EdgeInsets.all(8.0),
97 | child: Text(
98 | _venue.address,
99 | textAlign: TextAlign.center,
100 | ),
101 | ),
102 | ],
103 | ),
104 | ),
105 | ),
106 | ],
107 | ),
108 | ),
109 | )
110 | ],
111 | ),
112 | );
113 | }
114 |
115 | _getData() {
116 | setState(() {
117 | _isLoading = true;
118 | });
119 | EventDetails _eventDetails = new EventDetails();
120 | var eventDetails = FirebaseFirestore.instance
121 | .collection(FireStoreKeys.dateCollection)
122 | .snapshots()
123 | .first;
124 | eventDetails.then((onValue) {
125 | locationCache.setLocation(
126 | onValue.docs.first.data()['venue']['location']['longitude'].toString(),
127 | onValue.docs.first.data()['venue']['location']['latitude'].toString(),
128 | );
129 | _eventDetails = EventDetails(
130 | reference: onValue.docs.first.reference,
131 | venue: Venue(
132 | address: onValue.docs.first.data()['venue']['address'],
133 | title: onValue.docs.first.data()['venue']['title'],
134 | city: onValue.docs.first.data()['venue']['city'],
135 | imageUrl: onValue.docs.first.data()['venue']['imageUrl'],
136 | location: Location(
137 | latitude: onValue.docs.first.data()['venue']['location']
138 | ['latitude'],
139 | longitude: onValue.docs.first.data()['venue']['location']
140 | ['longitude'],
141 | )));
142 | setState(() {
143 | _venue = _eventDetails.venue;
144 | _isLoading = false;
145 | });
146 | });
147 | }
148 |
149 | void _addMarker(Venue venue) {
150 | final int markerCount = markers.length;
151 |
152 | if (markerCount == 12) {
153 | return;
154 | }
155 |
156 | final MarkerId markerId = MarkerId(venue.city);
157 |
158 | final Marker marker = Marker(
159 | markerId: markerId,
160 | position: LatLng(venue.location.latitude, venue.location.longitude),
161 | infoWindow: InfoWindow(title: venue.title, snippet: venue.city),
162 | icon: BitmapDescriptor.defaultMarkerWithHue(
163 | BitmapDescriptor.hueAzure,
164 | ),
165 | );
166 |
167 | setState(() {
168 | markers[markerId] = marker;
169 | });
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/lib/venue_model.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:flutter_pk/helpers/formatters.dart';
3 |
4 | class EventDetails {
5 | final String date;
6 | final String eventTitle;
7 | final Venue venue;
8 | final DocumentReference reference;
9 |
10 | EventDetails({this.date, this.eventTitle, this.venue, this.reference});
11 |
12 | EventDetails.fromMap(Map map, {this.reference})
13 | : eventTitle = map['eventTitle'],
14 | date = formatDate(
15 | map['date'],
16 | DateFormats.shortUiDateFormat,
17 | ),
18 | venue = Venue.fromMap(map['venue']);
19 | EventDetails.fromSnapshot(DocumentSnapshot snapshot)
20 | : this.fromMap(snapshot.data(), reference: snapshot.reference);
21 | }
22 |
23 | class Venue {
24 | final String title;
25 | final String address;
26 | final String city;
27 | final String imageUrl;
28 | final Location location;
29 | final DocumentReference reference;
30 |
31 | Venue({
32 | this.address,
33 | this.title,
34 | this.imageUrl,
35 | this.location,
36 | this.city,
37 | this.reference,
38 | });
39 |
40 | Venue.fromMap(Map map, {this.reference})
41 | : title = map['title'],
42 | address = map['address'],
43 | city = map['city'],
44 | imageUrl = map['imageUrl'],
45 | location = Location.fromMap(map['location']);
46 |
47 | Venue.fromSnapshot(DocumentSnapshot snapshot)
48 | : this.fromMap(snapshot.data(), reference: snapshot.reference);
49 | }
50 |
51 | class Location {
52 | final double latitude;
53 | final double longitude;
54 | final DocumentReference reference;
55 |
56 | Location({
57 | this.latitude,
58 | this.longitude,
59 | this.reference,
60 | });
61 |
62 | Location.fromMap(Map map, {this.reference})
63 | : latitude = map['latitude'],
64 | longitude = map['longitude'];
65 |
66 | Location.fromSnapshot(DocumentSnapshot snapshot)
67 | : this.fromMap(snapshot.data(), reference: snapshot.reference);
68 | }
--------------------------------------------------------------------------------
/lib/widgets/capsule_text.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class CapsuleText extends StatelessWidget {
4 | final Color color;
5 | final String title;
6 | final Color textColor;
7 |
8 | CapsuleText({this.color, this.title, this.textColor = Colors.white});
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | return Card(
13 | elevation: 0.0,
14 | shape: StadiumBorder(),
15 | color: color,
16 | child: Padding(
17 | padding: const EdgeInsets.symmetric(
18 | horizontal: 8.0,
19 | vertical: 2.0,
20 | ),
21 | child: Text(
22 | title,
23 | style: Theme.of(context).textTheme.caption.copyWith(
24 | color: textColor,
25 | fontSize: 14.0
26 | ),
27 | ),
28 | ),
29 | );
30 | }
31 | }
--------------------------------------------------------------------------------
/lib/widgets/custom_app_bar.dart:
--------------------------------------------------------------------------------
1 | import 'package:cloud_firestore/cloud_firestore.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_pk/global.dart';
4 | import 'package:flutter_pk/helpers/formatters.dart';
5 | import 'package:flutter_pk/profile/profile_dialog.dart';
6 | import 'package:flutter_pk/util.dart';
7 |
8 | class CustomAppBar extends StatefulWidget {
9 | final String title;
10 | CustomAppBar({@required this.title});
11 | @override
12 | CustomAppBarState createState() {
13 | return new CustomAppBarState();
14 | }
15 | }
16 |
17 | class CustomAppBarState extends State {
18 | String eventDate = '';
19 | String eventTitle = '';
20 | @override
21 | void initState() {
22 | super.initState();
23 | var eventDetails = FirebaseFirestore.instance
24 | .collection(FireStoreKeys.dateCollection)
25 | .snapshots()
26 | .first;
27 | eventDetails.then((onValue) {
28 | setState(() {
29 | eventDate = formatDate(
30 | toDateTime(onValue.docs.first.data()['date']),
31 | DateFormats.shortUiDateFormat,
32 | );
33 | eventDateTimeCache
34 | .setDateTime(toDateTime(onValue.docs.first.data()['date']));
35 | eventTitle = onValue.docs.first.data()['eventTitle'];
36 | });
37 | });
38 | }
39 |
40 | @override
41 | Widget build(BuildContext context) {
42 | return Padding(
43 | padding: const EdgeInsets.only(left: 8, top: 40, right: 8, bottom: 8),
44 | child: Row(
45 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
46 | children: [
47 | GestureDetector(
48 | onTap: () async {
49 | await Navigator.of(context).push(
50 | MaterialPageRoute(
51 | builder: (context) => FullScreenProfileDialog(),
52 | fullscreenDialog: true,
53 | ),
54 | );
55 | },
56 | child: Padding(
57 | padding: const EdgeInsets.only(left: 8.0),
58 | child: CircleAvatar(
59 | backgroundImage: NetworkImage(userCache.user.photoUrl)),
60 | ),
61 | ),
62 | Expanded(
63 | child: Column(
64 | mainAxisAlignment: MainAxisAlignment.center,
65 | crossAxisAlignment: CrossAxisAlignment.center,
66 | children: [
67 | Text(
68 | eventTitle,
69 | style: Theme.of(context).textTheme.title,
70 | textAlign: TextAlign.center,
71 | overflow: TextOverflow.clip,
72 | ),
73 | Text(eventDate)
74 | ],
75 | ),
76 | ),
77 | SizedBox(width: 48),
78 | ],
79 | ),
80 | );
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/lib/widgets/dots_indicator.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class DotsIndicator extends AnimatedWidget {
6 | DotsIndicator({
7 | this.controller,
8 | this.itemCount,
9 | this.onPageSelected,
10 | this.activeColor,
11 | this.inactiveColor: Colors.white,
12 | }) : super(listenable: controller);
13 |
14 | /// The PageController that this DotsIndicator is representing.
15 | final PageController controller;
16 |
17 | /// The number of items managed by the PageController
18 | final int itemCount;
19 |
20 | /// Called when a dot is tapped
21 | final ValueChanged onPageSelected;
22 |
23 | /// The color of the dots.
24 | ///
25 | /// Defaults to `Colors.white`.
26 | final Color inactiveColor;
27 |
28 | final Color activeColor;
29 |
30 | // The base size of the dots
31 | static const double _kDotSize = 8.0;
32 |
33 | // The increase in the size of the selected dot
34 | static const double _kMaxZoom = 1.5;
35 |
36 | // The distance between the center of each dot
37 | static const double _kDotSpacing = 18.0;
38 |
39 | Widget _buildDot(int index, BuildContext context) {
40 | double selectedness = Curves.easeOut.transform(
41 | max(
42 | 0.0,
43 | 1.0 - ((controller.page ?? controller.initialPage) - index).abs(),
44 | ),
45 | );
46 | double zoom = 1.0 + (_kMaxZoom - 1.0) * selectedness;
47 | return new Container(
48 | width: _kDotSpacing,
49 | child: new Center(
50 | child: new Material(
51 | color: index == (controller.page == null ? 0 : controller.page)
52 | ? activeColor
53 | : inactiveColor,
54 | type: MaterialType.circle,
55 | child: new Container(
56 | width: _kDotSize * zoom,
57 | height: _kDotSize * zoom,
58 | ),
59 | ),
60 | ),
61 | );
62 | }
63 |
64 | Widget build(BuildContext context) {
65 | return SizedBox(
66 | height: 20.0,
67 | child: Row(
68 | mainAxisAlignment: MainAxisAlignment.spaceAround,
69 | children: [
70 | Expanded(
71 | child: Center(
72 | child: ListView.builder(
73 | itemBuilder: (context, int index) {
74 | return _buildDot(index, context);
75 | },
76 | itemCount: itemCount,
77 | scrollDirection: Axis.horizontal,
78 | shrinkWrap: true,
79 | ),
80 | ),
81 | ),
82 | ],
83 | ),
84 | );
85 | }
86 | }
--------------------------------------------------------------------------------
/lib/widgets/full_screen_loader.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:progress_indicators/progress_indicators.dart';
3 |
4 | class FullScreenLoader extends StatelessWidget {
5 | @override
6 | Widget build(BuildContext context) {
7 | // TODO: implement build
8 | return Container(
9 | height: MediaQuery.of(context).size.height,
10 | width: MediaQuery.of(context).size.width,
11 | decoration: BoxDecoration(
12 | color: Colors.black54,
13 | backgroundBlendMode: BlendMode.darken,
14 | ),
15 | child: Center(
16 | child: HeartbeatProgressIndicator(
17 | child: SizedBox(
18 | height: 40.0,
19 | width: 40.0,
20 | child: Image(image: AssetImage('assets/loader.png')),
21 | )),
22 | ),
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/widgets/sprung_box.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:sprung/sprung.dart';
3 |
4 | typedef void BoolCallback(bool val);
5 |
6 | class SprungBox extends StatefulWidget {
7 | final Duration duration;
8 | final BoolCallback callback;
9 |
10 | SprungBox({
11 | this.callback,
12 | duration,
13 | }) : this.duration = duration ?? Duration(milliseconds: 3500);
14 |
15 | @override
16 | _SprungBoxState createState() => _SprungBoxState();
17 | }
18 |
19 | class _SprungBoxState extends State
20 | with SingleTickerProviderStateMixin {
21 | bool _isOffset = false;
22 | bool showFlag = false;
23 |
24 | @override
25 | void initState() {
26 | super.initState();
27 | _toggleOffset();
28 | }
29 |
30 | void _toggleOffset() async {
31 | await Future.delayed(
32 | new Duration(milliseconds: 500),
33 | () => setState(() {
34 | this._isOffset = !this._isOffset;
35 | }),
36 | );
37 | await Future.delayed(
38 | new Duration(milliseconds: 1500),
39 | () => widget.callback(true),
40 | );
41 | }
42 |
43 | @override
44 | Widget build(BuildContext context) {
45 | return LayoutBuilder(
46 | builder: (context, constraints) {
47 | final height = constraints.maxWidth * 2;
48 | final left = !this._isOffset ? height + 100.0 : 40.0;
49 |
50 | final width = MediaQuery.of(context).size.width * 2;
51 |
52 | return Padding(
53 | padding: const EdgeInsets.only(right: 48.0),
54 | child: AnimatedContainer(
55 | duration: this.widget.duration,
56 | curve: Sprung(),
57 | margin: EdgeInsets.only(
58 | left: left,
59 | ),
60 | height: 250.0,
61 | width: width,
62 | color: Colors.transparent,
63 | child: SizedBox(
64 | height: 250.0,
65 | width: 250.0,
66 | child: Image(
67 | image: AssetImage('assets/flutterKarachi.png'),
68 | ),
69 | ),
70 | ),
71 | );
72 | },
73 | );
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_pk
2 | description: A new Flutter project.
3 |
4 | # The following defines the version and build number for your application.
5 | # A version number is three numbers separated by dots, like 1.2.43
6 | # followed by an optional build number separated by a +.
7 | # Both the version and the builder number may be overridden in flutter
8 | # build by specifying --build-name and --build-number, respectively.
9 | # Read more about versioning at semver.org.
10 | version: 1.0.0+5
11 |
12 | environment:
13 | sdk: ">=2.1.0 <3.0.0"
14 |
15 | dependencies:
16 | flutter:
17 | sdk: flutter
18 | flutter_swiper: ^1.1.6
19 | firebase_auth: ^0.18.0+1
20 | firebase_core: ^0.5.0
21 | cloud_firestore: ^0.14.0+2
22 | sprung: ^2.0.0+12
23 | intl: ^0.16.1
24 | rounded_modal: ^1.0.1
25 | progress_indicators: ^0.1.5
26 | google_sign_in: ^4.5.3
27 | cached_network_image: ^2.2.0+1
28 | rflutter_alert: ^1.0.3
29 | shared_preferences: ^0.5.10
30 | smooth_star_rating: 1.0.1
31 | barcode_scan: ^3.0.1
32 | google_maps_flutter: ^0.5.30
33 | url_launcher: ^5.5.0
34 |
35 | # The following adds the Cupertino Icons font to your application.
36 | # Use with the CupertinoIcons class for iOS style icons.
37 | cupertino_icons: ^0.1.3
38 |
39 | dev_dependencies:
40 | flutter_test:
41 | sdk: flutter
42 | flutter_launcher_icons: ^0.7.5
43 |
44 | flutter_icons:
45 | android: "launcher_icon"
46 | ios: true
47 | image_path: "assets/icon/icon.png"
48 |
49 |
50 | # For information on the generic Dart part of this file, see the
51 | # following page: https://www.dartlang.org/tools/pub/pubspec
52 |
53 | # The following section is specific to Flutter.
54 | flutter:
55 |
56 | # The following line ensures that the Material Icons font is
57 | # included with your application, so that you can use the icons in
58 | # the material Icons class.
59 | uses-material-design: true
60 | assets:
61 | - assets/
62 |
63 | # To add assets to your application, add an assets section, like this:
64 | # assets:
65 | # - images/a_dot_burr.jpeg
66 | # - images/a_dot_ham.jpeg
67 |
68 | # An image asset can refer to one or more resolution-specific "variants", see
69 | # https://flutter.io/assets-and-images/#resolution-aware.
70 |
71 | # For details regarding adding assets from package dependencies, see
72 | # https://flutter.io/assets-and-images/#from-packages
73 |
74 | # To add custom fonts to your application, add a fonts section here,
75 | # in this "flutter" section. Each entry in this list should have a
76 | # "family" key with the font family name, and a "fonts" key with a
77 | # list giving the asset and other descriptors for the font. For
78 | # example:
79 | # fonts:
80 | # - family: Schyler
81 | # fonts:
82 | # - asset: fonts/Schyler-Regular.ttf
83 | # - asset: fonts/Schyler-Italic.ttf
84 | # style: italic
85 | # - family: Trajan Pro
86 | # fonts:
87 | # - asset: fonts/TrajanPro.ttf
88 | # - asset: fonts/TrajanPro_Bold.ttf
89 | # weight: 700
90 | #
91 | # For details regarding fonts from package dependencies,
92 | # see https://flutter.io/custom-fonts/#from-packages
93 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:flutter_pk/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------