├── .firebaserc ├── .flutter-plugins-dependencies ├── .gitignore ├── .gradle └── 4.4.1 │ ├── fileChanges │ └── last-build.bin │ └── fileHashes │ └── fileHashes.lock ├── .metadata ├── README.md ├── android ├── app │ ├── build.gradle │ ├── google-services.json │ ├── key.properties │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── example │ │ │ │ └── fluttershare │ │ │ │ └── MainActivity.java │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-ldpi │ │ │ └── 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 │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── fonts │ └── Signatra.ttf └── images │ ├── activity_feed.svg │ ├── google_signin_button.png │ ├── no_content.svg │ ├── search.svg │ └── upload.svg ├── firebase.json ├── flutter_01.png ├── functions ├── .gitignore ├── index.js ├── package-lock.json └── package.json ├── ios ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Release.xcconfig │ └── flutter_export_environment.sh ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── Runner │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── 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 │ └── main.m ├── lib ├── main.dart ├── models │ └── user.dart ├── pages │ ├── activity_feed.dart │ ├── comments.dart │ ├── create_account.dart │ ├── edit_profile.dart │ ├── home.dart │ ├── post_screen.dart │ ├── profile.dart │ ├── search.dart │ ├── timeline.dart │ └── upload.dart └── widgets │ ├── custom_image.dart │ ├── header.dart │ ├── post.dart │ ├── post_tile.dart │ └── progress.dart ├── pubspec.lock ├── pubspec.yaml └── test └── widget_test.dart /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "socialize-4b183" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.flutter-plugins-dependencies: -------------------------------------------------------------------------------- 1 | {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"cloud_firestore","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-0.9.13+1/","dependencies":["firebase_core"]},{"name":"firebase_auth","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_auth-0.8.4+5/","dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-0.3.4/","dependencies":[]},{"name":"firebase_messaging","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-4.0.0+4/","dependencies":[]},{"name":"firebase_storage","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_storage-2.1.1+2/","dependencies":["firebase_core"]},{"name":"geolocator","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/geolocator-5.0.1/","dependencies":["location_permissions"]},{"name":"google_sign_in","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/google_sign_in-4.5.1/","dependencies":[]},{"name":"image_picker","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker-0.6.7+2/","dependencies":[]},{"name":"location_permissions","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/location_permissions-2.0.5/","dependencies":[]},{"name":"path_provider","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-0.5.0+1/","dependencies":[]},{"name":"sqflite","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.3.1/","dependencies":[]}],"android":[{"name":"cloud_firestore","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-0.9.13+1/","dependencies":["firebase_core"]},{"name":"firebase_auth","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_auth-0.8.4+5/","dependencies":["firebase_core"]},{"name":"firebase_core","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-0.3.4/","dependencies":[]},{"name":"firebase_messaging","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_messaging-4.0.0+4/","dependencies":[]},{"name":"firebase_storage","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_storage-2.1.1+2/","dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/flutter_plugin_android_lifecycle-1.0.8/","dependencies":[]},{"name":"geolocator","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/geolocator-5.0.1/","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/google_api_availability-2.0.4/","dependencies":[]},{"name":"google_sign_in","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/google_sign_in-4.5.1/","dependencies":[]},{"name":"image_picker","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/image_picker-0.6.7+2/","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"location_permissions","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/location_permissions-2.0.5/","dependencies":[]},{"name":"path_provider","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/path_provider-0.5.0+1/","dependencies":[]},{"name":"sqflite","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.3.1/","dependencies":[]}],"macos":[{"name":"sqflite","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/sqflite-1.3.1/","dependencies":[]}],"linux":[],"windows":[],"web":[{"name":"google_sign_in_web","path":"/home/muhammad/tools/flutter/.pub-cache/hosted/pub.dartlang.org/google_sign_in_web-0.9.1+1/","dependencies":[]}]},"dependencyGraph":[{"name":"cloud_firestore","dependencies":["firebase_core"]},{"name":"firebase_auth","dependencies":["firebase_core"]},{"name":"firebase_core","dependencies":[]},{"name":"firebase_messaging","dependencies":[]},{"name":"firebase_storage","dependencies":["firebase_core"]},{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"geolocator","dependencies":["google_api_availability","location_permissions"]},{"name":"google_api_availability","dependencies":[]},{"name":"google_sign_in","dependencies":["google_sign_in_web"]},{"name":"google_sign_in_web","dependencies":[]},{"name":"image_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"location_permissions","dependencies":[]},{"name":"path_provider","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2020-06-20 15:36:54.286083","version":"1.17.3"} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .packages 28 | .pub-cache/ 29 | .pub/ 30 | /build/ 31 | 32 | # Android related 33 | **/android/**/gradle-wrapper.jar 34 | **/android/.gradle 35 | **/android/captures/ 36 | **/android/gradlew 37 | **/android/gradlew.bat 38 | **/android/local.properties 39 | **/android/**/GeneratedPluginRegistrant.java 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 | 67 | # Exceptions to above rules. 68 | !**/ios/**/default.mode1v3 69 | !**/ios/**/default.mode2v3 70 | !**/ios/**/default.pbxuser 71 | !**/ios/**/default.perspectivev3 72 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 73 | -------------------------------------------------------------------------------- /.gradle/4.4.1/fileChanges/last-build.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gradle/4.4.1/fileHashes/fileHashes.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/.gradle/4.4.1/fileHashes/fileHashes.lock -------------------------------------------------------------------------------- /.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: bb6c3f813146b72ea0f97098c913b45e93b694c4 8 | channel: master 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Socialize 2 | ## Social network app using Flutter and Firebase 3 | ### this app is pretty much like Instgram application which I build to learn more about flutter and get my self involoved into flutter and dart 4 | ## please check first apk ver. 5 | https://drive.google.com/file/d/1D7tJ4Oq9-Te0S9rViCvoOLTA-r9GM36L/view?usp=sharing 6 | ## please check demo video 7 | https://youtu.be/q8nx_BtTo74 8 | 9 | -------------------------------------------------------------------------------- /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 | apply plugin: 'com.android.application' 15 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 16 | def keystoreProperties = new Properties() 17 | def keystorePropertiesFile = rootProject.file('key.properties') 18 | if (keystorePropertiesFile.exists()) { 19 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 20 | } 21 | android { 22 | compileSdkVersion 28 23 | 24 | lintOptions { 25 | disable 'InvalidPackage' 26 | } 27 | 28 | defaultConfig { 29 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 30 | applicationId "com.muhammadkamal.socialize" 31 | minSdkVersion 16 32 | targetSdkVersion 28 33 | versionCode 1 34 | versionName "1.2.2" 35 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 36 | multiDexEnabled true 37 | } 38 | signingConfigs { 39 | release { 40 | keyAlias keystoreProperties['keyAlias'] 41 | keyPassword keystoreProperties['keyPassword'] 42 | storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null 43 | storePassword keystoreProperties['storePassword'] 44 | } 45 | } 46 | buildTypes { 47 | release { 48 | // TODO: Add your own signing config for the release build. 49 | // Signing with the debug keys for now, 50 | // so `flutter run --release` works. 51 | signingConfig signingConfigs.debug 52 | } 53 | } 54 | 55 | } 56 | 57 | flutter { 58 | source '../..' 59 | } 60 | 61 | dependencies { 62 | testImplementation 'junit:junit:4.12' 63 | androidTestImplementation 'androidx.test:runner:1.1.0-alpha4' 64 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4' 65 | implementation 'com.google.firebase:firebase-core:16.0.1' 66 | 67 | } 68 | apply plugin: 'com.google.gms.google-services' -------------------------------------------------------------------------------- /android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "787100240864", 4 | "firebase_url": "https://socialize-4b183.firebaseio.com", 5 | "project_id": "socialize-4b183", 6 | "storage_bucket": "socialize-4b183.appspot.com" 7 | }, 8 | "client": [ 9 | { 10 | "client_info": { 11 | "mobilesdk_app_id": "1:787100240864:android:2d171f90bc4c33624d3985", 12 | "android_client_info": { 13 | "package_name": "com.muhammadkamal.socialize" 14 | } 15 | }, 16 | "oauth_client": [ 17 | { 18 | "client_id": "787100240864-cdpbrm3sggcrk4htuoa2b8fn9idmsu8u.apps.googleusercontent.com", 19 | "client_type": 1, 20 | "android_info": { 21 | "package_name": "com.muhammadkamal.socialize", 22 | "certificate_hash": "192159f468df95572a89e36ce8177ea276239f00" 23 | } 24 | }, 25 | { 26 | "client_id": "787100240864-a6j2cevdaipu5qmhv5lrvlegtaq9jn6j.apps.googleusercontent.com", 27 | "client_type": 3 28 | } 29 | ], 30 | "api_key": [ 31 | { 32 | "current_key": "AIzaSyA_Yblr225uD7Kztnu_RNVqHKseg0Ogkxc" 33 | } 34 | ], 35 | "services": { 36 | "appinvite_service": { 37 | "other_platform_oauth_client": [ 38 | { 39 | "client_id": "787100240864-a6j2cevdaipu5qmhv5lrvlegtaq9jn6j.apps.googleusercontent.com", 40 | "client_type": 3 41 | } 42 | ] 43 | } 44 | } 45 | } 46 | ], 47 | "configuration_version": "1" 48 | } -------------------------------------------------------------------------------- /android/app/key.properties: -------------------------------------------------------------------------------- 1 | storePassword= 2 | keyPassword= 3 | keyAlias=key 4 | storeFile= 5 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 13 | 20 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 36 | 37 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/example/fluttershare/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.fluttershare; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/android/app/src/main/res/mipmap-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.3.2' 9 | classpath 'com.google.gms:google-services:4.0.1' 10 | 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | maven { 19 | url "https://maven.google.com" // Google's Maven repository 20 | } 21 | } 22 | } 23 | 24 | rootProject.buildDir = '../build' 25 | subprojects { 26 | project.buildDir = "${rootProject.buildDir}/${project.name}" 27 | } 28 | subprojects { 29 | project.evaluationDependsOn(':app') 30 | } 31 | 32 | task clean(type: Delete) { 33 | delete rootProject.buildDir 34 | } -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | android.enableJetifier=true 2 | android.useAndroidX=true 3 | org.gradle.jvmargs=-Xmx1536M 4 | android.enableR8=true 5 | android.bundle.enableUncompressedNativeLibs=false -------------------------------------------------------------------------------- /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-4.10.2-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/fonts/Signatra.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/assets/fonts/Signatra.ttf -------------------------------------------------------------------------------- /assets/images/activity_feed.svg: -------------------------------------------------------------------------------- 1 | notify -------------------------------------------------------------------------------- /assets/images/google_signin_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/assets/images/google_signin_button.png -------------------------------------------------------------------------------- /assets/images/no_content.svg: -------------------------------------------------------------------------------- 1 | cancel -------------------------------------------------------------------------------- /assets/images/upload.svg: -------------------------------------------------------------------------------- 1 | camera -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /flutter_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/flutter_01.png -------------------------------------------------------------------------------- /functions/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /functions/index.js: -------------------------------------------------------------------------------- 1 | const functions = require('firebase-functions'); 2 | const admin = require("firebase-admin"); 3 | admin.initializeApp(); 4 | 5 | // // Create and Deploy Your First Cloud Functions 6 | // // https://firebase.google.com/docs/functions/write-firebase-functions 7 | // 8 | // exports.helloWorld = functions.https.onRequest((request, response) => { 9 | // response.send("Hello from Firebase!"); 10 | // }); 11 | exports.onCreateFollower = functions.firestore 12 | .document("/followers/{userId}/userFollowers/{followerId}") 13 | .onCreate(async (snapshot, context) => { 14 | console.log("follower created", snapshot.id); 15 | const userId = context.params.userId; 16 | const followerId = context.params.followerId; 17 | // 1) create follower users posts 18 | const followerUserPostsRef = admin.firestore().collection("posts").doc(userId).collection("usersPosts"); 19 | // 2) create following users's timeline 20 | const timelinePostRef = admin.firestore().collection("timeline").doc(followerId).collection("timelinePosts"); 21 | // 3) get followed users post 22 | const querySnapshot = await followerUserPostsRef.get(); 23 | // 4) add each user post to following timeline 24 | querySnapshot.forEach(doc => { 25 | if (doc.exists) { 26 | const postId = doc.id; 27 | const postData = doc.data(); 28 | timelinePostRef.doc(postId).set(postData); 29 | } 30 | 31 | }); 32 | 33 | }); 34 | 35 | exports.onDeleteFollower = functions.firestore 36 | .document("/followers/{userId}/userFollowers/{followerId}") 37 | .onDelete(async (snapshot, context) => { 38 | console.log("follower deleted", snapshot.id); 39 | const userId = context.params.userId; 40 | const followerId = context.params.followerId; 41 | 42 | 43 | const timelinePostRef = admin.firestore().collection("timeline").doc(followerId).collection("timelinePosts") 44 | .where("ownerId", "==", userId); 45 | 46 | const querySnapshot = await timelinePostRef.get(); 47 | // 4) add each user post to following timeline 48 | querySnapshot.forEach(doc => { 49 | if (doc.exists) { 50 | doc.ref.delete(); 51 | } 52 | }) 53 | 54 | }); 55 | 56 | exports.onCreatePost = functions.firestore.document("/posts/{userId}/usersPosts/{postId}") 57 | .onCreate(async (snapshot, context) => { 58 | const postCreated = snapshot.data(); 59 | const userId = context.params.userId; 60 | const postId = context.params.postId; 61 | // get all followers of the post craetor 62 | const userFollowersRef = admin.firestore().collection("followers").doc(userId) 63 | .collection("userFollowers"); 64 | const querySnapshot = await userFollowersRef.get(); 65 | // add new post to each follower timeline 66 | querySnapshot.forEach(doc => { 67 | const followerId = doc.id; 68 | admin.firestore().collection("timeline").doc(followerId).collection("timelinePosts") 69 | .doc(postId).set(postCreated); 70 | }); 71 | }); 72 | 73 | exports.onUpdatePost = functions.firestore.document("/posts/{userId}/usersPosts/{postId}") 74 | .onUpdate(async (change, context) => { 75 | const postUpdate = change.after.data(); 76 | const userId = context.params.userId; 77 | const postId = context.params.postId; 78 | // get all followers of the post craetor 79 | const userFollowersRef = admin.firestore().collection("followers").doc(userId) 80 | .collection("userFollowers"); 81 | const querySnapshot = await userFollowersRef.get(); 82 | // update post to each follower timeline 83 | querySnapshot.forEach(doc => { 84 | const followerId = doc.id; 85 | admin.firestore().collection("timeline").doc(followerId).collection("timelinePosts") 86 | .doc(postId).get().then(doc => { 87 | if (doc.exists) 88 | doc.ref.update(postUpdate); 89 | }); 90 | }); 91 | }); 92 | 93 | 94 | exports.onDeletePost = functions.firestore.document("/posts/{userId}/usersPosts/{postId}") 95 | .onDelete(async (snapshot, context) => { 96 | const postDelete = snapshot.data(); 97 | const userId = context.params.userId; 98 | const postId = context.params.postId; 99 | // get all followers of the post craetor 100 | const userFollowersRef = admin.firestore().collection("followers").doc(userId) 101 | .collection("userFollowers"); 102 | const querySnapshot = await userFollowersRef.get(); 103 | // update post to each follower timeline 104 | querySnapshot.forEach(doc => { 105 | const followerId = doc.id; 106 | admin.firestore().collection("timeline").doc(followerId).collection("timelinePosts") 107 | .doc(postId).get().then(doc => { 108 | if (doc.exists) 109 | doc.ref.delete(postDelete); 110 | }); 111 | }); 112 | }); 113 | exports.onCreateActivityFeedItem = functions.firestore 114 | .document("/feed/{userId}/feedItems/{activityFeedItem}") 115 | .onCreate(async (snapshot, context) => { 116 | console.log("Activity Feed Item Created", snapshot.data()); 117 | 118 | // 1) Get user connected to the feed 119 | const userId = context.params.userId; 120 | 121 | const userRef = admin.firestore().doc("users/${userId}"); 122 | const doc = await userRef.get(); 123 | 124 | // 2) Once we have user, check if they have a notification token; send notification, if they have a token 125 | const androidNotificationToken = doc.data().androidNotificationToken; 126 | const createdActivityFeedItem = snapshot.data(); 127 | if (androidNotificationToken) { 128 | sendNotification(androidNotificationToken, createdActivityFeedItem); 129 | } else { 130 | console.log("No token for user, cannot send notification"); 131 | } 132 | 133 | function sendNotification(androidNotificationToken, activityFeedItem) { 134 | let body; 135 | 136 | // 3) switch body value based off of notification type 137 | switch (activityFeedItem.type) { 138 | case "comment": 139 | body = `${activityFeedItem.username} replied: ${ 140 | activityFeedItem.commentData 141 | }`; 142 | break; 143 | case "like": 144 | body = `${activityFeedItem.username} liked your post`; 145 | break; 146 | case "follow": 147 | body = `${activityFeedItem.username} started following you`; 148 | break; 149 | default: 150 | break; 151 | } 152 | 153 | // 4) Create message for push notification 154 | const message = { 155 | notification: { body }, 156 | token: androidNotificationToken, 157 | data: { recipient: userId } 158 | }; 159 | 160 | // 5) Send message with admin.messaging() 161 | admin 162 | .messaging() 163 | .send(message) 164 | .then(response => { 165 | // Response is a message ID string 166 | console.log("Successfully sent message", response); 167 | }) 168 | .catch(error => { 169 | console.log("Error sending message", error); 170 | }); 171 | } 172 | }); 173 | -------------------------------------------------------------------------------- /functions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "functions", 3 | "description": "Cloud Functions for Firebase", 4 | "scripts": { 5 | "serve": "firebase emulators:start --only functions", 6 | "shell": "firebase functions:shell", 7 | "start": "npm run shell", 8 | "deploy": "firebase deploy --only functions", 9 | "logs": "firebase functions:log" 10 | }, 11 | "engines": { 12 | "node": "8" 13 | }, 14 | "dependencies": { 15 | "firebase-admin": "^8.10.0", 16 | "firebase-functions": "^3.6.0" 17 | }, 18 | "devDependencies": { 19 | "firebase-functions-test": "^0.2.0" 20 | }, 21 | "private": true 22 | } 23 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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/Flutter/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=/home/muhammad/tools/flutter" 4 | export "FLUTTER_APPLICATION_PATH=/media/muhammad/Here_we_are/Muhammad/courses/flutter/socialize" 5 | export "FLUTTER_TARGET=lib/main.dart" 6 | export "FLUTTER_BUILD_DIR=build" 7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios" 8 | export "OTHER_LDFLAGS=$(inherited) -framework Flutter" 9 | export "FLUTTER_FRAMEWORK_DIR=/home/muhammad/tools/flutter/bin/cache/artifacts/engine/ios" 10 | export "FLUTTER_BUILD_NAME=1.0.0" 11 | export "FLUTTER_BUILD_NUMBER=1" 12 | -------------------------------------------------------------------------------- /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 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock 37 | # referring to absolute paths on developers' machines. 38 | system('rm -rf .symlinks') 39 | system('mkdir -p .symlinks/plugins') 40 | 41 | # Flutter Pods 42 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig') 43 | if generated_xcode_build_settings.empty? 44 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first." 45 | end 46 | generated_xcode_build_settings.map { |p| 47 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR' 48 | symlink = File.join('.symlinks', 'flutter') 49 | File.symlink(File.dirname(p[:path]), symlink) 50 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path])) 51 | end 52 | } 53 | 54 | # Plugin Pods 55 | plugin_pods = parse_KV_file('../.flutter-plugins') 56 | plugin_pods.map { |p| 57 | symlink = File.join('.symlinks', 'plugins', p[:name]) 58 | File.symlink(p[:path], symlink) 59 | pod p[:name], :path => File.join(symlink, 'ios') 60 | } 61 | end 62 | 63 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. 64 | install! 'cocoapods', :disable_input_output_paths => true 65 | 66 | post_install do |installer| 67 | installer.pods_project.targets.each do |target| 68 | target.build_configurations.each do |config| 69 | config.build_settings['ENABLE_BITCODE'] = 'NO' 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - BoringSSL-GRPC (0.0.2): 3 | - BoringSSL-GRPC/Implementation (= 0.0.2) 4 | - BoringSSL-GRPC/Interface (= 0.0.2) 5 | - BoringSSL-GRPC/Implementation (0.0.2): 6 | - BoringSSL-GRPC/Interface (= 0.0.2) 7 | - BoringSSL-GRPC/Interface (0.0.2) 8 | - cloud_firestore (0.0.1): 9 | - Firebase/Auth 10 | - Firebase/Core 11 | - Firebase/Database 12 | - Firebase/Firestore 13 | - Flutter 14 | - Firebase/Auth (5.20.2): 15 | - Firebase/CoreOnly 16 | - FirebaseAuth (= 5.4.2) 17 | - Firebase/Core (5.20.2): 18 | - Firebase/CoreOnly 19 | - FirebaseAnalytics (= 5.8.1) 20 | - Firebase/CoreOnly (5.20.2): 21 | - FirebaseCore (= 5.4.1) 22 | - Firebase/Database (5.20.2): 23 | - Firebase/CoreOnly 24 | - FirebaseDatabase (= 5.1.1) 25 | - Firebase/Firestore (5.20.2): 26 | - Firebase/CoreOnly 27 | - FirebaseFirestore (= 1.2.1) 28 | - Firebase/Messaging (5.20.2): 29 | - Firebase/CoreOnly 30 | - FirebaseMessaging (= 3.5.0) 31 | - Firebase/Storage (5.20.2): 32 | - Firebase/CoreOnly 33 | - FirebaseStorage (= 3.1.1) 34 | - firebase_auth (0.0.1): 35 | - Firebase/Auth (~> 5.19) 36 | - Firebase/Core 37 | - Flutter 38 | - firebase_core (0.0.1): 39 | - Firebase/Core 40 | - Flutter 41 | - firebase_messaging (0.0.1): 42 | - Firebase/Core 43 | - Firebase/Messaging 44 | - Flutter 45 | - firebase_storage (0.0.1): 46 | - Firebase/Storage 47 | - Flutter 48 | - FirebaseAnalytics (5.8.1): 49 | - FirebaseCore (~> 5.4) 50 | - FirebaseInstanceID (~> 3.8) 51 | - GoogleAppMeasurement (= 5.8.1) 52 | - GoogleUtilities/AppDelegateSwizzler (~> 5.2) 53 | - GoogleUtilities/MethodSwizzler (~> 5.2) 54 | - GoogleUtilities/Network (~> 5.2) 55 | - "GoogleUtilities/NSData+zlib (~> 5.2)" 56 | - nanopb (~> 0.3) 57 | - FirebaseAnalyticsInterop (1.2.0) 58 | - FirebaseAuth (5.4.2): 59 | - FirebaseAuthInterop (~> 1.0) 60 | - FirebaseCore (~> 5.2) 61 | - GoogleUtilities/Environment (~> 5.2) 62 | - GTMSessionFetcher/Core (~> 1.1) 63 | - FirebaseAuthInterop (1.0.0) 64 | - FirebaseCore (5.4.1): 65 | - GoogleUtilities/Environment (~> 5.2) 66 | - GoogleUtilities/Logger (~> 5.2) 67 | - FirebaseDatabase (5.1.1): 68 | - FirebaseAuthInterop (~> 1.0) 69 | - FirebaseCore (~> 5.2) 70 | - leveldb-library (~> 1.18) 71 | - FirebaseFirestore (1.2.1): 72 | - FirebaseAuthInterop (~> 1.0) 73 | - FirebaseCore (~> 5.2) 74 | - FirebaseFirestore/abseil-cpp (= 1.2.1) 75 | - "gRPC-C++ (= 0.0.6)" 76 | - leveldb-library (~> 1.20) 77 | - nanopb (~> 0.3.901) 78 | - Protobuf (~> 3.1) 79 | - FirebaseFirestore/abseil-cpp (1.2.1): 80 | - FirebaseAuthInterop (~> 1.0) 81 | - FirebaseCore (~> 5.2) 82 | - "gRPC-C++ (= 0.0.6)" 83 | - leveldb-library (~> 1.20) 84 | - nanopb (~> 0.3.901) 85 | - Protobuf (~> 3.1) 86 | - FirebaseInstanceID (3.8.1): 87 | - FirebaseCore (~> 5.2) 88 | - GoogleUtilities/Environment (~> 5.2) 89 | - GoogleUtilities/UserDefaults (~> 5.2) 90 | - FirebaseMessaging (3.5.0): 91 | - FirebaseAnalyticsInterop (~> 1.1) 92 | - FirebaseCore (~> 5.2) 93 | - FirebaseInstanceID (~> 3.6) 94 | - GoogleUtilities/Environment (~> 5.3) 95 | - GoogleUtilities/Reachability (~> 5.3) 96 | - GoogleUtilities/UserDefaults (~> 5.3) 97 | - Protobuf (~> 3.1) 98 | - FirebaseStorage (3.1.1): 99 | - FirebaseAuthInterop (~> 1.0) 100 | - FirebaseCore (~> 5.2) 101 | - GTMSessionFetcher/Core (~> 1.1) 102 | - Flutter (1.0.0) 103 | - FMDB (2.7.5): 104 | - FMDB/standard (= 2.7.5) 105 | - FMDB/standard (2.7.5) 106 | - geolocator (5.0.1): 107 | - Flutter 108 | - google_api_availability (2.0.1): 109 | - Flutter 110 | - google_sign_in (0.0.1): 111 | - Flutter 112 | - GoogleSignIn (~> 4.0) 113 | - GoogleAppMeasurement (5.8.1): 114 | - GoogleUtilities/AppDelegateSwizzler (~> 5.2) 115 | - GoogleUtilities/MethodSwizzler (~> 5.2) 116 | - GoogleUtilities/Network (~> 5.2) 117 | - "GoogleUtilities/NSData+zlib (~> 5.2)" 118 | - nanopb (~> 0.3) 119 | - GoogleSignIn (4.4.0): 120 | - "GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)" 121 | - "GoogleToolboxForMac/NSString+URLArguments (~> 2.1)" 122 | - GTMSessionFetcher/Core (~> 1.1) 123 | - GoogleToolboxForMac/DebugUtils (2.2.1): 124 | - GoogleToolboxForMac/Defines (= 2.2.1) 125 | - GoogleToolboxForMac/Defines (2.2.1) 126 | - "GoogleToolboxForMac/NSDictionary+URLArguments (2.2.1)": 127 | - GoogleToolboxForMac/DebugUtils (= 2.2.1) 128 | - GoogleToolboxForMac/Defines (= 2.2.1) 129 | - "GoogleToolboxForMac/NSString+URLArguments (= 2.2.1)" 130 | - "GoogleToolboxForMac/NSString+URLArguments (2.2.1)" 131 | - GoogleUtilities/AppDelegateSwizzler (5.8.0): 132 | - GoogleUtilities/Environment 133 | - GoogleUtilities/Logger 134 | - GoogleUtilities/Network 135 | - GoogleUtilities/Environment (5.8.0) 136 | - GoogleUtilities/Logger (5.8.0): 137 | - GoogleUtilities/Environment 138 | - GoogleUtilities/MethodSwizzler (5.8.0): 139 | - GoogleUtilities/Logger 140 | - GoogleUtilities/Network (5.8.0): 141 | - GoogleUtilities/Logger 142 | - "GoogleUtilities/NSData+zlib" 143 | - GoogleUtilities/Reachability 144 | - "GoogleUtilities/NSData+zlib (5.8.0)" 145 | - GoogleUtilities/Reachability (5.8.0): 146 | - GoogleUtilities/Logger 147 | - GoogleUtilities/UserDefaults (5.8.0): 148 | - GoogleUtilities/Logger 149 | - "gRPC-C++ (0.0.6)": 150 | - "gRPC-C++/Implementation (= 0.0.6)" 151 | - "gRPC-C++/Interface (= 0.0.6)" 152 | - "gRPC-C++/Implementation (0.0.6)": 153 | - "gRPC-C++/Interface (= 0.0.6)" 154 | - gRPC-Core (= 1.17.0) 155 | - nanopb (~> 0.3) 156 | - "gRPC-C++/Interface (0.0.6)" 157 | - gRPC-Core (1.17.0): 158 | - gRPC-Core/Implementation (= 1.17.0) 159 | - gRPC-Core/Interface (= 1.17.0) 160 | - gRPC-Core/Implementation (1.17.0): 161 | - BoringSSL-GRPC (= 0.0.2) 162 | - gRPC-Core/Interface (= 1.17.0) 163 | - nanopb (~> 0.3) 164 | - gRPC-Core/Interface (1.17.0) 165 | - GTMSessionFetcher/Core (1.2.2) 166 | - image_picker (0.0.1): 167 | - Flutter 168 | - leveldb-library (1.20) 169 | - location_permissions (2.0.2): 170 | - Flutter 171 | - nanopb (0.3.901): 172 | - nanopb/decode (= 0.3.901) 173 | - nanopb/encode (= 0.3.901) 174 | - nanopb/decode (0.3.901) 175 | - nanopb/encode (0.3.901) 176 | - path_provider (0.0.1): 177 | - Flutter 178 | - Protobuf (3.8.0) 179 | - sqflite (0.0.1): 180 | - Flutter 181 | - FMDB (~> 2.7.2) 182 | 183 | DEPENDENCIES: 184 | - cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`) 185 | - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) 186 | - firebase_core (from `.symlinks/plugins/firebase_core/ios`) 187 | - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) 188 | - firebase_storage (from `.symlinks/plugins/firebase_storage/ios`) 189 | - Flutter (from `.symlinks/flutter/ios`) 190 | - geolocator (from `.symlinks/plugins/geolocator/ios`) 191 | - google_api_availability (from `.symlinks/plugins/google_api_availability/ios`) 192 | - google_sign_in (from `.symlinks/plugins/google_sign_in/ios`) 193 | - image_picker (from `.symlinks/plugins/image_picker/ios`) 194 | - location_permissions (from `.symlinks/plugins/location_permissions/ios`) 195 | - path_provider (from `.symlinks/plugins/path_provider/ios`) 196 | - sqflite (from `.symlinks/plugins/sqflite/ios`) 197 | 198 | SPEC REPOS: 199 | https://github.com/cocoapods/specs.git: 200 | - BoringSSL-GRPC 201 | - Firebase 202 | - FirebaseAnalytics 203 | - FirebaseAnalyticsInterop 204 | - FirebaseAuth 205 | - FirebaseAuthInterop 206 | - FirebaseCore 207 | - FirebaseDatabase 208 | - FirebaseFirestore 209 | - FirebaseInstanceID 210 | - FirebaseMessaging 211 | - FirebaseStorage 212 | - FMDB 213 | - GoogleAppMeasurement 214 | - GoogleSignIn 215 | - GoogleToolboxForMac 216 | - GoogleUtilities 217 | - "gRPC-C++" 218 | - gRPC-Core 219 | - GTMSessionFetcher 220 | - leveldb-library 221 | - nanopb 222 | - Protobuf 223 | 224 | EXTERNAL SOURCES: 225 | cloud_firestore: 226 | :path: ".symlinks/plugins/cloud_firestore/ios" 227 | firebase_auth: 228 | :path: ".symlinks/plugins/firebase_auth/ios" 229 | firebase_core: 230 | :path: ".symlinks/plugins/firebase_core/ios" 231 | firebase_messaging: 232 | :path: ".symlinks/plugins/firebase_messaging/ios" 233 | firebase_storage: 234 | :path: ".symlinks/plugins/firebase_storage/ios" 235 | Flutter: 236 | :path: ".symlinks/flutter/ios" 237 | geolocator: 238 | :path: ".symlinks/plugins/geolocator/ios" 239 | google_api_availability: 240 | :path: ".symlinks/plugins/google_api_availability/ios" 241 | google_sign_in: 242 | :path: ".symlinks/plugins/google_sign_in/ios" 243 | image_picker: 244 | :path: ".symlinks/plugins/image_picker/ios" 245 | location_permissions: 246 | :path: ".symlinks/plugins/location_permissions/ios" 247 | path_provider: 248 | :path: ".symlinks/plugins/path_provider/ios" 249 | sqflite: 250 | :path: ".symlinks/plugins/sqflite/ios" 251 | 252 | SPEC CHECKSUMS: 253 | BoringSSL-GRPC: 2a230d9cd93e7ce39916044f645cebb31f37dde6 254 | cloud_firestore: cd6e849ecb8ab43e5a7a5f1f169304ca65436c03 255 | Firebase: 0c8cf33f266410c61ab3e2265cfa412200351d9c 256 | firebase_auth: e32ab45c234bdf847b7777f5b097ce4f7d26879f 257 | firebase_core: ce5006bb48508ee4e71e0f429a3f519bb8ee2961 258 | firebase_messaging: b25b2fa94e685146bcf9d706ed87b4e95cd2a17d 259 | firebase_storage: 2543f377090a6e219caab9224dead5bbcb30ef33 260 | FirebaseAnalytics: ece1aa57a4f43c64d53a648b5a5e05151aae947b 261 | FirebaseAnalyticsInterop: efbe45c8385ec626e29f9525e5ebd38520dfb6c1 262 | FirebaseAuth: dd7bbf03a5aee0eafb3a1aee4d2812bd74bac890 263 | FirebaseAuthInterop: 0ffa57668be100582bb7643d4fcb7615496c41fc 264 | FirebaseCore: f1a9a8be1aee4bf71a2fc0f4096df6788bdfda61 265 | FirebaseDatabase: 2c15b0ea6f2c6eb5e57413f9d6340f1e50b81ae3 266 | FirebaseFirestore: faca891c0f0d1d6c10c793473e2f6a29d75014b5 267 | FirebaseInstanceID: a122b0c258720cf250551bb2bedf48c699f80d90 268 | FirebaseMessaging: 4235f949ce1c4e827aeb19705ba5c53f9b85aa10 269 | FirebaseStorage: 6162ef4322502b818d9de0ec552f5226d283de43 270 | Flutter: 58dd7d1b27887414a370fcccb9e645c08ffd7a6a 271 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a 272 | geolocator: f3dd3b5b1761a15a4da00665774c5a8319e657d6 273 | google_api_availability: 163b30f802e6148c67f092aa4501c90ddd8eec8d 274 | google_sign_in: 27e70a98b529f0b076d4b19f231b81da28b1750b 275 | GoogleAppMeasurement: ffe513e90551844a739e7bcbb1d2aca1c28a4338 276 | GoogleSignIn: 7ff245e1a7b26d379099d3243a562f5747e23d39 277 | GoogleToolboxForMac: b3553629623a3b1bff17f555e736cd5a6d95ad55 278 | GoogleUtilities: 04fce34bcd5620c1ee76fb79172105c74a4df335 279 | "gRPC-C++": e76441995900ac90e9bd98644ab4733f12521edf 280 | gRPC-Core: 4028031ed2c5267cca0d846c876d8046b1ecb9b6 281 | GTMSessionFetcher: 61bb0f61a4cb560030f1222021178008a5727a23 282 | image_picker: 16e5fec1fbc87fd3b297c53e4048521eaf17cd06 283 | leveldb-library: 08cba283675b7ed2d99629a4bc5fd052cd2bb6a5 284 | location_permissions: 67cfaff583afbb027a9f9248196f4b79c40f3cdc 285 | nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48 286 | path_provider: f96fff6166a8867510d2c25fdcc346327cc4b259 287 | Protobuf: 3f617b9a6e73605565086864c9bc26b2bf2dd5a3 288 | sqflite: ff1d9da63c06588cc8d1faf7256d741f16989d5a 289 | 290 | PODFILE CHECKSUM: 81d9101721a74b9b88ddd9e9dfe15eec968bc82e 291 | 292 | COCOAPODS: 1.7.2 293 | -------------------------------------------------------------------------------- /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 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14 | 42DBA82922BF724A004B56DE /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 42DBA82822BF724A004B56DE /* GoogleService-Info.plist */; }; 15 | 964BD1FD9684CA9BF42F6F1F /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 23F4EADA84AE2F83891E1EBA /* libPods-Runner.a */; }; 16 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 17 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 18 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 19 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 20 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 21 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 22 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 23 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXCopyFilesBuildPhase section */ 27 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 28 | isa = PBXCopyFilesBuildPhase; 29 | buildActionMask = 2147483647; 30 | dstPath = ""; 31 | dstSubfolderSpec = 10; 32 | files = ( 33 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 34 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 35 | ); 36 | name = "Embed Frameworks"; 37 | runOnlyForDeploymentPostprocessing = 0; 38 | }; 39 | /* End PBXCopyFilesBuildPhase section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 43 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 44 | 1FEA9F5AFAA9BFC8F1DB4F8B /* 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 = ""; }; 45 | 23F4EADA84AE2F83891E1EBA /* libPods-Runner.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Runner.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 47 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 48 | 3BEF546D702808C3C51CCEFE /* 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 = ""; }; 49 | 3C9F2C70703F7ECC26A8DB67 /* 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 = ""; }; 50 | 42DBA82822BF724A004B56DE /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 51 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 52 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 53 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 54 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 55 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 56 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 57 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 59 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 60 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 61 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 62 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 63 | /* End PBXFileReference section */ 64 | 65 | /* Begin PBXFrameworksBuildPhase section */ 66 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 71 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 72 | 964BD1FD9684CA9BF42F6F1F /* libPods-Runner.a in Frameworks */, 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | /* End PBXFrameworksBuildPhase section */ 77 | 78 | /* Begin PBXGroup section */ 79 | 8CBEE9C8FA89F5CC2911FDC6 /* Pods */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 3BEF546D702808C3C51CCEFE /* Pods-Runner.debug.xcconfig */, 83 | 3C9F2C70703F7ECC26A8DB67 /* Pods-Runner.release.xcconfig */, 84 | 1FEA9F5AFAA9BFC8F1DB4F8B /* Pods-Runner.profile.xcconfig */, 85 | ); 86 | name = Pods; 87 | path = Pods; 88 | sourceTree = ""; 89 | }; 90 | 9740EEB11CF90186004384FC /* Flutter */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 3B80C3931E831B6300D905FE /* App.framework */, 94 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 95 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 96 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 97 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 98 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 99 | ); 100 | name = Flutter; 101 | sourceTree = ""; 102 | }; 103 | 97C146E51CF9000F007C117D = { 104 | isa = PBXGroup; 105 | children = ( 106 | 42DBA82822BF724A004B56DE /* GoogleService-Info.plist */, 107 | 9740EEB11CF90186004384FC /* Flutter */, 108 | 97C146F01CF9000F007C117D /* Runner */, 109 | 97C146EF1CF9000F007C117D /* Products */, 110 | 8CBEE9C8FA89F5CC2911FDC6 /* Pods */, 111 | F70933126535390CEB47CF53 /* Frameworks */, 112 | ); 113 | sourceTree = ""; 114 | }; 115 | 97C146EF1CF9000F007C117D /* Products */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 97C146EE1CF9000F007C117D /* Runner.app */, 119 | ); 120 | name = Products; 121 | sourceTree = ""; 122 | }; 123 | 97C146F01CF9000F007C117D /* Runner */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 127 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 128 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 129 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 130 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 131 | 97C147021CF9000F007C117D /* Info.plist */, 132 | 97C146F11CF9000F007C117D /* Supporting Files */, 133 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 134 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 135 | ); 136 | path = Runner; 137 | sourceTree = ""; 138 | }; 139 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 140 | isa = PBXGroup; 141 | children = ( 142 | 97C146F21CF9000F007C117D /* main.m */, 143 | ); 144 | name = "Supporting Files"; 145 | sourceTree = ""; 146 | }; 147 | F70933126535390CEB47CF53 /* Frameworks */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | 23F4EADA84AE2F83891E1EBA /* libPods-Runner.a */, 151 | ); 152 | name = Frameworks; 153 | sourceTree = ""; 154 | }; 155 | /* End PBXGroup section */ 156 | 157 | /* Begin PBXNativeTarget section */ 158 | 97C146ED1CF9000F007C117D /* Runner */ = { 159 | isa = PBXNativeTarget; 160 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 161 | buildPhases = ( 162 | 37AFA7892B569BF2318ABDEF /* [CP] Check Pods Manifest.lock */, 163 | 9740EEB61CF901F6004384FC /* Run Script */, 164 | 97C146EA1CF9000F007C117D /* Sources */, 165 | 97C146EB1CF9000F007C117D /* Frameworks */, 166 | 97C146EC1CF9000F007C117D /* Resources */, 167 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 168 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 169 | D3C678522ED76F8552974CE4 /* [CP] Embed Pods Frameworks */, 170 | 5F3382C918B825F864321B1C /* [CP] Copy Pods Resources */, 171 | ); 172 | buildRules = ( 173 | ); 174 | dependencies = ( 175 | ); 176 | name = Runner; 177 | productName = Runner; 178 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 179 | productType = "com.apple.product-type.application"; 180 | }; 181 | /* End PBXNativeTarget section */ 182 | 183 | /* Begin PBXProject section */ 184 | 97C146E61CF9000F007C117D /* Project object */ = { 185 | isa = PBXProject; 186 | attributes = { 187 | LastUpgradeCheck = 1020; 188 | ORGANIZATIONNAME = "The Chromium Authors"; 189 | TargetAttributes = { 190 | 97C146ED1CF9000F007C117D = { 191 | CreatedOnToolsVersion = 7.3.1; 192 | }; 193 | }; 194 | }; 195 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 196 | compatibilityVersion = "Xcode 3.2"; 197 | developmentRegion = en; 198 | hasScannedForEncodings = 0; 199 | knownRegions = ( 200 | en, 201 | Base, 202 | ); 203 | mainGroup = 97C146E51CF9000F007C117D; 204 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 205 | projectDirPath = ""; 206 | projectRoot = ""; 207 | targets = ( 208 | 97C146ED1CF9000F007C117D /* Runner */, 209 | ); 210 | }; 211 | /* End PBXProject section */ 212 | 213 | /* Begin PBXResourcesBuildPhase section */ 214 | 97C146EC1CF9000F007C117D /* Resources */ = { 215 | isa = PBXResourcesBuildPhase; 216 | buildActionMask = 2147483647; 217 | files = ( 218 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 219 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 220 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 221 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 222 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 223 | 42DBA82922BF724A004B56DE /* GoogleService-Info.plist in Resources */, 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | }; 227 | /* End PBXResourcesBuildPhase section */ 228 | 229 | /* Begin PBXShellScriptBuildPhase section */ 230 | 37AFA7892B569BF2318ABDEF /* [CP] Check Pods Manifest.lock */ = { 231 | isa = PBXShellScriptBuildPhase; 232 | buildActionMask = 2147483647; 233 | files = ( 234 | ); 235 | inputFileListPaths = ( 236 | ); 237 | inputPaths = ( 238 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 239 | "${PODS_ROOT}/Manifest.lock", 240 | ); 241 | name = "[CP] Check Pods Manifest.lock"; 242 | outputFileListPaths = ( 243 | ); 244 | outputPaths = ( 245 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 246 | ); 247 | runOnlyForDeploymentPostprocessing = 0; 248 | shellPath = /bin/sh; 249 | 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"; 250 | showEnvVarsInLog = 0; 251 | }; 252 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 253 | isa = PBXShellScriptBuildPhase; 254 | buildActionMask = 2147483647; 255 | files = ( 256 | ); 257 | inputPaths = ( 258 | ); 259 | name = "Thin Binary"; 260 | outputPaths = ( 261 | ); 262 | runOnlyForDeploymentPostprocessing = 0; 263 | shellPath = /bin/sh; 264 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 265 | }; 266 | 5F3382C918B825F864321B1C /* [CP] Copy Pods Resources */ = { 267 | isa = PBXShellScriptBuildPhase; 268 | buildActionMask = 2147483647; 269 | files = ( 270 | ); 271 | inputPaths = ( 272 | ); 273 | name = "[CP] Copy Pods Resources"; 274 | outputPaths = ( 275 | ); 276 | runOnlyForDeploymentPostprocessing = 0; 277 | shellPath = /bin/sh; 278 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; 279 | showEnvVarsInLog = 0; 280 | }; 281 | 9740EEB61CF901F6004384FC /* Run Script */ = { 282 | isa = PBXShellScriptBuildPhase; 283 | buildActionMask = 2147483647; 284 | files = ( 285 | ); 286 | inputPaths = ( 287 | ); 288 | name = "Run Script"; 289 | outputPaths = ( 290 | ); 291 | runOnlyForDeploymentPostprocessing = 0; 292 | shellPath = /bin/sh; 293 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 294 | }; 295 | D3C678522ED76F8552974CE4 /* [CP] Embed Pods Frameworks */ = { 296 | isa = PBXShellScriptBuildPhase; 297 | buildActionMask = 2147483647; 298 | files = ( 299 | ); 300 | inputPaths = ( 301 | ); 302 | name = "[CP] Embed Pods Frameworks"; 303 | outputPaths = ( 304 | ); 305 | runOnlyForDeploymentPostprocessing = 0; 306 | shellPath = /bin/sh; 307 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 308 | showEnvVarsInLog = 0; 309 | }; 310 | /* End PBXShellScriptBuildPhase section */ 311 | 312 | /* Begin PBXSourcesBuildPhase section */ 313 | 97C146EA1CF9000F007C117D /* Sources */ = { 314 | isa = PBXSourcesBuildPhase; 315 | buildActionMask = 2147483647; 316 | files = ( 317 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 318 | 97C146F31CF9000F007C117D /* main.m in Sources */, 319 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | }; 323 | /* End PBXSourcesBuildPhase section */ 324 | 325 | /* Begin PBXVariantGroup section */ 326 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 327 | isa = PBXVariantGroup; 328 | children = ( 329 | 97C146FB1CF9000F007C117D /* Base */, 330 | ); 331 | name = Main.storyboard; 332 | sourceTree = ""; 333 | }; 334 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 335 | isa = PBXVariantGroup; 336 | children = ( 337 | 97C147001CF9000F007C117D /* Base */, 338 | ); 339 | name = LaunchScreen.storyboard; 340 | sourceTree = ""; 341 | }; 342 | /* End PBXVariantGroup section */ 343 | 344 | /* Begin XCBuildConfiguration section */ 345 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 346 | isa = XCBuildConfiguration; 347 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 348 | buildSettings = { 349 | ALWAYS_SEARCH_USER_PATHS = NO; 350 | CLANG_ANALYZER_NONNULL = YES; 351 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 352 | CLANG_CXX_LIBRARY = "libc++"; 353 | CLANG_ENABLE_MODULES = YES; 354 | CLANG_ENABLE_OBJC_ARC = YES; 355 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 356 | CLANG_WARN_BOOL_CONVERSION = YES; 357 | CLANG_WARN_COMMA = YES; 358 | CLANG_WARN_CONSTANT_CONVERSION = YES; 359 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 360 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 361 | CLANG_WARN_EMPTY_BODY = YES; 362 | CLANG_WARN_ENUM_CONVERSION = YES; 363 | CLANG_WARN_INFINITE_RECURSION = YES; 364 | CLANG_WARN_INT_CONVERSION = YES; 365 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 366 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 367 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 368 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 369 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 370 | CLANG_WARN_STRICT_PROTOTYPES = YES; 371 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 372 | CLANG_WARN_UNREACHABLE_CODE = YES; 373 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 374 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 375 | COPY_PHASE_STRIP = NO; 376 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 377 | ENABLE_NS_ASSERTIONS = NO; 378 | ENABLE_STRICT_OBJC_MSGSEND = YES; 379 | GCC_C_LANGUAGE_STANDARD = gnu99; 380 | GCC_NO_COMMON_BLOCKS = YES; 381 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 382 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 383 | GCC_WARN_UNDECLARED_SELECTOR = YES; 384 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 385 | GCC_WARN_UNUSED_FUNCTION = YES; 386 | GCC_WARN_UNUSED_VARIABLE = YES; 387 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 388 | MTL_ENABLE_DEBUG_INFO = NO; 389 | SDKROOT = iphoneos; 390 | TARGETED_DEVICE_FAMILY = "1,2"; 391 | VALIDATE_PRODUCT = YES; 392 | }; 393 | name = Profile; 394 | }; 395 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 396 | isa = XCBuildConfiguration; 397 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 398 | buildSettings = { 399 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 400 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 401 | DEVELOPMENT_TEAM = S8QB4VV633; 402 | ENABLE_BITCODE = NO; 403 | FRAMEWORK_SEARCH_PATHS = ( 404 | "$(inherited)", 405 | "$(PROJECT_DIR)/Flutter", 406 | ); 407 | INFOPLIST_FILE = Runner/Info.plist; 408 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 409 | LIBRARY_SEARCH_PATHS = ( 410 | "$(inherited)", 411 | "$(PROJECT_DIR)/Flutter", 412 | ); 413 | PRODUCT_BUNDLE_IDENTIFIER = com.codeartistry.fluttershare; 414 | PRODUCT_NAME = "$(TARGET_NAME)"; 415 | VERSIONING_SYSTEM = "apple-generic"; 416 | }; 417 | name = Profile; 418 | }; 419 | 97C147031CF9000F007C117D /* Debug */ = { 420 | isa = XCBuildConfiguration; 421 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 422 | buildSettings = { 423 | ALWAYS_SEARCH_USER_PATHS = NO; 424 | CLANG_ANALYZER_NONNULL = YES; 425 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 426 | CLANG_CXX_LIBRARY = "libc++"; 427 | CLANG_ENABLE_MODULES = YES; 428 | CLANG_ENABLE_OBJC_ARC = YES; 429 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 430 | CLANG_WARN_BOOL_CONVERSION = YES; 431 | CLANG_WARN_COMMA = YES; 432 | CLANG_WARN_CONSTANT_CONVERSION = YES; 433 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 434 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 435 | CLANG_WARN_EMPTY_BODY = YES; 436 | CLANG_WARN_ENUM_CONVERSION = YES; 437 | CLANG_WARN_INFINITE_RECURSION = YES; 438 | CLANG_WARN_INT_CONVERSION = YES; 439 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 440 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 441 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 442 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 443 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 444 | CLANG_WARN_STRICT_PROTOTYPES = YES; 445 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 446 | CLANG_WARN_UNREACHABLE_CODE = YES; 447 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 448 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 449 | COPY_PHASE_STRIP = NO; 450 | DEBUG_INFORMATION_FORMAT = dwarf; 451 | ENABLE_STRICT_OBJC_MSGSEND = YES; 452 | ENABLE_TESTABILITY = YES; 453 | GCC_C_LANGUAGE_STANDARD = gnu99; 454 | GCC_DYNAMIC_NO_PIC = NO; 455 | GCC_NO_COMMON_BLOCKS = YES; 456 | GCC_OPTIMIZATION_LEVEL = 0; 457 | GCC_PREPROCESSOR_DEFINITIONS = ( 458 | "DEBUG=1", 459 | "$(inherited)", 460 | ); 461 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 462 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 463 | GCC_WARN_UNDECLARED_SELECTOR = YES; 464 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 465 | GCC_WARN_UNUSED_FUNCTION = YES; 466 | GCC_WARN_UNUSED_VARIABLE = YES; 467 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 468 | MTL_ENABLE_DEBUG_INFO = YES; 469 | ONLY_ACTIVE_ARCH = YES; 470 | SDKROOT = iphoneos; 471 | TARGETED_DEVICE_FAMILY = "1,2"; 472 | }; 473 | name = Debug; 474 | }; 475 | 97C147041CF9000F007C117D /* Release */ = { 476 | isa = XCBuildConfiguration; 477 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 478 | buildSettings = { 479 | ALWAYS_SEARCH_USER_PATHS = NO; 480 | CLANG_ANALYZER_NONNULL = YES; 481 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 482 | CLANG_CXX_LIBRARY = "libc++"; 483 | CLANG_ENABLE_MODULES = YES; 484 | CLANG_ENABLE_OBJC_ARC = YES; 485 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 486 | CLANG_WARN_BOOL_CONVERSION = YES; 487 | CLANG_WARN_COMMA = YES; 488 | CLANG_WARN_CONSTANT_CONVERSION = YES; 489 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 490 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 491 | CLANG_WARN_EMPTY_BODY = YES; 492 | CLANG_WARN_ENUM_CONVERSION = YES; 493 | CLANG_WARN_INFINITE_RECURSION = YES; 494 | CLANG_WARN_INT_CONVERSION = YES; 495 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 496 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 497 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 498 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 499 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 500 | CLANG_WARN_STRICT_PROTOTYPES = YES; 501 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 502 | CLANG_WARN_UNREACHABLE_CODE = YES; 503 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 504 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 505 | COPY_PHASE_STRIP = NO; 506 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 507 | ENABLE_NS_ASSERTIONS = NO; 508 | ENABLE_STRICT_OBJC_MSGSEND = YES; 509 | GCC_C_LANGUAGE_STANDARD = gnu99; 510 | GCC_NO_COMMON_BLOCKS = YES; 511 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 512 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 513 | GCC_WARN_UNDECLARED_SELECTOR = YES; 514 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 515 | GCC_WARN_UNUSED_FUNCTION = YES; 516 | GCC_WARN_UNUSED_VARIABLE = YES; 517 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 518 | MTL_ENABLE_DEBUG_INFO = NO; 519 | SDKROOT = iphoneos; 520 | TARGETED_DEVICE_FAMILY = "1,2"; 521 | VALIDATE_PRODUCT = YES; 522 | }; 523 | name = Release; 524 | }; 525 | 97C147061CF9000F007C117D /* Debug */ = { 526 | isa = XCBuildConfiguration; 527 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 528 | buildSettings = { 529 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 530 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 531 | ENABLE_BITCODE = NO; 532 | FRAMEWORK_SEARCH_PATHS = ( 533 | "$(inherited)", 534 | "$(PROJECT_DIR)/Flutter", 535 | ); 536 | INFOPLIST_FILE = Runner/Info.plist; 537 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 538 | LIBRARY_SEARCH_PATHS = ( 539 | "$(inherited)", 540 | "$(PROJECT_DIR)/Flutter", 541 | ); 542 | PRODUCT_BUNDLE_IDENTIFIER = com.codeartistry.fluttershare; 543 | PRODUCT_NAME = "$(TARGET_NAME)"; 544 | VERSIONING_SYSTEM = "apple-generic"; 545 | }; 546 | name = Debug; 547 | }; 548 | 97C147071CF9000F007C117D /* Release */ = { 549 | isa = XCBuildConfiguration; 550 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 551 | buildSettings = { 552 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 553 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 554 | ENABLE_BITCODE = NO; 555 | FRAMEWORK_SEARCH_PATHS = ( 556 | "$(inherited)", 557 | "$(PROJECT_DIR)/Flutter", 558 | ); 559 | INFOPLIST_FILE = Runner/Info.plist; 560 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 561 | LIBRARY_SEARCH_PATHS = ( 562 | "$(inherited)", 563 | "$(PROJECT_DIR)/Flutter", 564 | ); 565 | PRODUCT_BUNDLE_IDENTIFIER = com.codeartistry.fluttershare; 566 | PRODUCT_NAME = "$(TARGET_NAME)"; 567 | VERSIONING_SYSTEM = "apple-generic"; 568 | }; 569 | name = Release; 570 | }; 571 | /* End XCBuildConfiguration section */ 572 | 573 | /* Begin XCConfigurationList section */ 574 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 575 | isa = XCConfigurationList; 576 | buildConfigurations = ( 577 | 97C147031CF9000F007C117D /* Debug */, 578 | 97C147041CF9000F007C117D /* Release */, 579 | 249021D3217E4FDB00AE95B9 /* Profile */, 580 | ); 581 | defaultConfigurationIsVisible = 0; 582 | defaultConfigurationName = Release; 583 | }; 584 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 585 | isa = XCConfigurationList; 586 | buildConfigurations = ( 587 | 97C147061CF9000F007C117D /* Debug */, 588 | 97C147071CF9000F007C117D /* Release */, 589 | 249021D4217E4FDB00AE95B9 /* Profile */, 590 | ); 591 | defaultConfigurationIsVisible = 0; 592 | defaultConfigurationName = Release; 593 | }; 594 | /* End XCConfigurationList section */ 595 | }; 596 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 597 | } 598 | -------------------------------------------------------------------------------- /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 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muhammedkamal/Socilize/ec338ee2253880edab447a18846f3f8c546b2853/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 | 6 | CFBundleURLTypes 7 | 8 | 9 | CFBundleTypeRole 10 | Editor 11 | CFBundleURLSchemes 12 | 13 | 14 | 15 | com.googleusercontent.apps.59618786383-06uqombe6l6uf7p44l18vd8m90hjlhe5 16 | 17 | 18 | 19 | 20 | 21 | 22 | NSLocationWhenInUseUsageDescription 23 | This app needs access to location when open. 24 | 25 | 26 | 27 | NSCameraUsageDescription 28 | Used to demonstrate image picker plugin 29 | NSMicrophoneUsageDescription 30 | Used to capture audio for image picker plugin 31 | NSPhotoLibraryUsageDescription 32 | Used to demonstrate image picker plugin 33 | 34 | 35 | CFBundleDevelopmentRegion 36 | $(DEVELOPMENT_LANGUAGE) 37 | CFBundleExecutable 38 | $(EXECUTABLE_NAME) 39 | CFBundleIdentifier 40 | $(PRODUCT_BUNDLE_IDENTIFIER) 41 | CFBundleInfoDictionaryVersion 42 | 6.0 43 | CFBundleName 44 | fluttershare 45 | CFBundlePackageType 46 | APPL 47 | CFBundleShortVersionString 48 | $(FLUTTER_BUILD_NAME) 49 | CFBundleSignature 50 | ???? 51 | CFBundleVersion 52 | $(FLUTTER_BUILD_NUMBER) 53 | LSRequiresIPhoneOS 54 | 55 | UILaunchStoryboardName 56 | LaunchScreen 57 | UIMainStoryboardFile 58 | Main 59 | UISupportedInterfaceOrientations 60 | 61 | UIInterfaceOrientationPortrait 62 | UIInterfaceOrientationLandscapeLeft 63 | UIInterfaceOrientationLandscapeRight 64 | 65 | UISupportedInterfaceOrientations~ipad 66 | 67 | UIInterfaceOrientationPortrait 68 | UIInterfaceOrientationPortraitUpsideDown 69 | UIInterfaceOrientationLandscapeLeft 70 | UIInterfaceOrientationLandscapeRight 71 | 72 | UIViewControllerBasedStatusBarAppearance 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:socialize/pages/home.dart'; 3 | 4 | void main() { 5 | // Firestore.instance.settings(timestampsInSnapshotsEnabled: true).then((_){}); 6 | runApp(MyApp()); 7 | } 8 | 9 | class MyApp extends StatelessWidget { 10 | @override 11 | Widget build(BuildContext context) { 12 | return MaterialApp( 13 | theme: ThemeData.dark().copyWith( 14 | primaryColor: Color(0xff000a12), 15 | accentColor: Color(0xff00675b), 16 | ), 17 | title: 'Socialize', 18 | debugShowCheckedModeBanner: false, 19 | home: Home(), 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/models/user.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | 3 | class User { 4 | final String username,id,email,photoUrl,displayName,bio; 5 | User({this.username,this.id,this.email,this.displayName,this.photoUrl,this.bio}); 6 | 7 | factory User.fromDocument(DocumentSnapshot doc) 8 | { 9 | return User( 10 | id: doc['id'], 11 | username: doc['username'], 12 | email: doc['email'], 13 | displayName: doc['displayName'], 14 | photoUrl: doc['photoURL'], 15 | bio: doc['bio'] 16 | ); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /lib/pages/activity_feed.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:cloud_firestore/cloud_firestore.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:socialize/pages/home.dart'; 5 | import 'package:socialize/pages/post_screen.dart'; 6 | import 'package:socialize/pages/profile.dart'; 7 | import 'package:socialize/widgets/header.dart'; 8 | import 'package:socialize/widgets/progress.dart'; 9 | import 'package:timeago/timeago.dart' as timeago; 10 | 11 | 12 | class ActivityFeed extends StatefulWidget { 13 | @override 14 | _ActivityFeedState createState() => _ActivityFeedState(); 15 | } 16 | Widget mediaPreview; 17 | String activityItemText; 18 | class _ActivityFeedState extends State { 19 | getActivityFeed ()async 20 | { 21 | QuerySnapshot snapshot = await activityFeedRef.document(currentUser.id) 22 | .collection('feedItems').orderBy('timestamp',descending: true).limit(50) 23 | .getDocuments(); 24 | List feedItems=[]; 25 | snapshot.documents.forEach((doc){ 26 | feedItems.add(ActivityFeedItem.fromDocument(doc)); 27 | }); 28 | return feedItems; 29 | } 30 | @override 31 | Widget build(BuildContext context) { 32 | return Scaffold( 33 | appBar: header(context,pageTitle: "Activity Feed"), 34 | body: FutureBuilder( 35 | future: getActivityFeed(), 36 | builder: (context,snapshot){ 37 | if (!snapshot.hasData) 38 | return circularProgress(); 39 | return ListView( 40 | children: snapshot.data, 41 | ); 42 | }, 43 | ), 44 | ); 45 | } 46 | } 47 | 48 | class ActivityFeedItem extends StatelessWidget { 49 | final String username,userId,type,commentData,mediaUrl,userProfileImg,postId; 50 | final Timestamp timestamp; 51 | ActivityFeedItem ({this.username, this.userId, this.type, this.commentData, this.mediaUrl, this.userProfileImg, this.postId, this.timestamp}); 52 | factory ActivityFeedItem.fromDocument(DocumentSnapshot doc){ 53 | return ActivityFeedItem( 54 | username : doc['username'], 55 | userId : doc['userId'], 56 | type: doc['type'], 57 | userProfileImg :doc['userProfileImg'], 58 | commentData : doc['commentData'], 59 | postId :doc['postId'], 60 | timestamp: doc['timestamp'], 61 | mediaUrl: doc['mediaUrl'], 62 | ); 63 | } 64 | showPost(context){ 65 | Navigator.push(context, MaterialPageRoute(builder: (context)=>PostScreen(userId: currentUser.id,postId: postId,),),); 66 | } 67 | configureMediaPreview(BuildContext context) 68 | { 69 | if (type=='like'||type=='comment') 70 | { 71 | mediaPreview = GestureDetector( 72 | onTap: ()=>showPost(context), 73 | child: Container( 74 | height: 50.0, 75 | width: 50.0, 76 | child: AspectRatio( 77 | aspectRatio: 16/9, 78 | child: Container( 79 | decoration: BoxDecoration( 80 | image: DecorationImage( 81 | fit: BoxFit.cover, 82 | image: CachedNetworkImageProvider(mediaUrl), 83 | ), 84 | ), 85 | ), 86 | ), 87 | ), 88 | ); 89 | } 90 | else{ 91 | mediaPreview=Text(""); 92 | } 93 | if(type=='like') 94 | activityItemText = "liked your post"; 95 | else if(type=='comment') 96 | activityItemText = "commented: '$commentData'"; 97 | else if(type=='follow') 98 | activityItemText = "start following you"; 99 | else 100 | activityItemText = "Error: Unknown type $type"; 101 | } 102 | 103 | @override 104 | Widget build(BuildContext context) { 105 | configureMediaPreview(context); 106 | return Padding( 107 | padding: EdgeInsets.only(bottom: 2), 108 | child: Container( 109 | color: Colors.black, 110 | child: ListTile( 111 | title: GestureDetector( 112 | onTap: ()=>showProfile(context,profileId: userId), 113 | child: RichText( 114 | overflow: TextOverflow.ellipsis, 115 | text: TextSpan( 116 | style: TextStyle(fontSize: 14.0), 117 | children: [ 118 | TextSpan( 119 | text: username, 120 | style: TextStyle(fontWeight: FontWeight.bold), 121 | ), 122 | TextSpan( 123 | text:' $activityItemText', 124 | ), 125 | ], 126 | ), 127 | ), 128 | ), 129 | leading: CircleAvatar( 130 | backgroundImage: CachedNetworkImageProvider(userProfileImg), 131 | ), 132 | subtitle: Text( 133 | timeago.format(timestamp.toDate()), 134 | overflow: TextOverflow.ellipsis, 135 | ), 136 | trailing: mediaPreview, 137 | ), 138 | ), 139 | ); 140 | } 141 | } 142 | 143 | showProfile(BuildContext context,{String profileId}) 144 | { 145 | Navigator.push(context, MaterialPageRoute(builder: (context)=>Profile(profileId: profileId,),),); 146 | } -------------------------------------------------------------------------------- /lib/pages/comments.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:cloud_firestore/cloud_firestore.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:socialize/pages/home.dart'; 5 | import 'package:socialize/widgets/header.dart'; 6 | import 'package:socialize/widgets/progress.dart'; 7 | import 'package:timeago/timeago.dart' as timeago; 8 | 9 | class Comments extends StatefulWidget { 10 | final String postId, postOwnerId,mediaUrl; 11 | Comments({this.postId,this.mediaUrl,this.postOwnerId}); 12 | @override 13 | CommentsState createState() => CommentsState( 14 | postId: this.postId, 15 | postOwnerId: this.postOwnerId, 16 | mediaUrl: this.mediaUrl 17 | ); 18 | } 19 | 20 | class CommentsState extends State { 21 | final String postId, postOwnerId,mediaUrl; 22 | TextEditingController commentController = TextEditingController(); 23 | CommentsState({this.postId,this.mediaUrl,this.postOwnerId}); 24 | addComment() 25 | { 26 | commentsRef.document(postId).collection('comment') 27 | .add({ 28 | "username":currentUser.username, 29 | "comment":commentController.text, 30 | "timeStamp":timeStamp, 31 | "avatarUrl":currentUser.photoUrl, 32 | "userId":currentUser.id, 33 | }); 34 | if (currentUser.id!=postOwnerId) { 35 | activityFeedRef.document(postOwnerId).collection('feedItems').add({ 36 | 'type': 'comment', 37 | 'commentData': commentController.text, 38 | 'username': currentUser.username, 39 | 'userId': currentUser.id, 40 | 'userProfileImg': currentUser.photoUrl, 41 | 'postId': postId, 42 | 'mediaUrl': mediaUrl, 43 | 'timestamp': timeStamp, 44 | }); 45 | } 46 | commentController.clear(); 47 | } 48 | buildComments(){ 49 | return StreamBuilder( 50 | stream: commentsRef.document(postId).collection('comment') 51 | .orderBy('timeStamp',descending: true).snapshots(), 52 | builder: (context,snapShot){ 53 | if (!snapShot.hasData) 54 | { 55 | return circularProgress(); 56 | } 57 | List comments=[]; 58 | snapShot.data.documents.forEach((doc){ 59 | comments.add(Comment.fromDocument(doc)); 60 | }); 61 | return ListView( 62 | children: comments 63 | ); 64 | }, 65 | ); 66 | } 67 | @override 68 | Widget build(BuildContext context) { 69 | return Scaffold( 70 | appBar: header(context,pageTitle: "Comments"), 71 | body: Column( 72 | children: [ 73 | Expanded(child: buildComments(),), 74 | Divider(), 75 | ListTile( 76 | title: TextFormField(controller: commentController, 77 | decoration: InputDecoration(labelText: "Write a comment ..."),), 78 | trailing: OutlineButton( 79 | onPressed: addComment, 80 | borderSide: BorderSide.none, 81 | child: Text("Comment"), 82 | ), 83 | ), 84 | ], 85 | ), 86 | ); 87 | } 88 | } 89 | 90 | class Comment extends StatelessWidget { 91 | final String username,userId,avatarUrl,comment; 92 | final Timestamp timestamp; 93 | Comment({ 94 | this.username, this.userId, this.avatarUrl, this.comment, this.timestamp, 95 | }); 96 | factory Comment.fromDocument(DocumentSnapshot doc){ 97 | return Comment( 98 | username: doc['username'], 99 | userId: doc['userId'], 100 | avatarUrl: doc['avatarUrl'], 101 | comment: doc['comment'], 102 | timestamp: doc['timeStamp'], 103 | ); 104 | } 105 | @override 106 | Widget build(BuildContext context) { 107 | return Column( 108 | children: [ 109 | ListTile( 110 | title: Text(comment), 111 | leading: CircleAvatar(backgroundImage: CachedNetworkImageProvider(avatarUrl),), 112 | subtitle: Text(timeago.format(timestamp.toDate())), 113 | ), 114 | Divider(), 115 | ], 116 | ); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /lib/pages/create_account.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:socialize/widgets/header.dart'; 3 | 4 | class CreateAccount extends StatefulWidget { 5 | @override 6 | _CreateAccountState createState() => _CreateAccountState(); 7 | } 8 | 9 | class _CreateAccountState extends State { 10 | final _formKey = GlobalKey(); 11 | String username; 12 | 13 | submit() 14 | { 15 | _formKey.currentState.save(); 16 | Navigator.pop(context,username); 17 | } 18 | @override 19 | Widget build(BuildContext parentContext) { 20 | return Scaffold( 21 | appBar: header(context,isTimeLine: false,pageTitle: 'Create Acount'), 22 | body: Container( 23 | child: ListView( 24 | children: [ 25 | Padding( 26 | padding: const EdgeInsets.only(top: 25.0), 27 | child: Center( 28 | child: Text('Enter Username', 29 | style: TextStyle( 30 | fontSize: 25.0, 31 | ), 32 | ), 33 | ), 34 | ), 35 | Padding( 36 | padding: EdgeInsets.all(16.0), 37 | child: Form( 38 | key: _formKey, 39 | child: TextFormField( 40 | onSaved: (val)=>username=val, 41 | decoration: InputDecoration( 42 | border: OutlineInputBorder(), 43 | hintText: 'Username must be more than 4 characters', 44 | labelText: 'Username', 45 | labelStyle: TextStyle( 46 | fontSize: 15.0, 47 | ), 48 | ), 49 | ), 50 | ), 51 | ), 52 | FlatButton( 53 | onPressed: submit, 54 | child: Container( 55 | height: 50.0, // not good for small mobiles please figure out how to solve it 56 | width: 350.0, 57 | decoration: BoxDecoration( 58 | color: Colors.teal, 59 | borderRadius: BorderRadius.circular(7.0), 60 | //may need to add a color 61 | ), 62 | child: Center( 63 | child: Text('Submit', 64 | style: TextStyle( 65 | fontSize: 15.0, 66 | fontWeight: FontWeight.bold, 67 | ), 68 | ), 69 | ), 70 | ), 71 | ) 72 | ], 73 | ), 74 | ), 75 | ); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/pages/edit_profile.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:cloud_firestore/cloud_firestore.dart'; 3 | import "package:flutter/material.dart"; 4 | import 'package:flutter/rendering.dart'; 5 | import 'package:socialize/models/user.dart'; 6 | import 'package:socialize/pages/home.dart'; 7 | import 'package:socialize/widgets/progress.dart'; 8 | 9 | class EditProfile extends StatefulWidget { 10 | final String currentUserID; 11 | EditProfile({this.currentUserID}); 12 | @override 13 | _EditProfileState createState() => _EditProfileState(); 14 | } 15 | 16 | class _EditProfileState extends State { 17 | final _scaffoldKey =GlobalKey(); 18 | bool isLoading=false,_bioValid=true,_displayNameValid=true; 19 | User user; 20 | TextEditingController displayNameController = TextEditingController(); 21 | TextEditingController bioController = TextEditingController(); 22 | 23 | Column buildDisplayField() 24 | { 25 | return Column( 26 | crossAxisAlignment: CrossAxisAlignment.start, 27 | children: [ 28 | Padding( 29 | padding: EdgeInsets.only(top:12.0), 30 | child: Text('Display Name'), 31 | ), 32 | TextField( 33 | controller: displayNameController, 34 | decoration: InputDecoration( 35 | hintText: 'Update Display Name', 36 | errorText: _displayNameValid?null:"Display name is too short", 37 | ), 38 | ), 39 | ], 40 | ); 41 | } 42 | Column buildBioField() 43 | { 44 | return Column( 45 | crossAxisAlignment: CrossAxisAlignment.start, 46 | children: [ 47 | Padding( 48 | padding: EdgeInsets.only(top:12.0), 49 | child: Text('Bio'), 50 | ), 51 | TextField( 52 | controller: bioController, 53 | decoration: InputDecoration( 54 | hintText: 'Update Bio', 55 | errorText: _bioValid?null:'Bio is too long', 56 | ), 57 | ) 58 | ], 59 | ); 60 | } 61 | getUser()async{ 62 | setState(() { 63 | isLoading=true; 64 | }); 65 | DocumentSnapshot doc = await usersRef.document(widget.currentUserID).get(); 66 | user = User.fromDocument(doc); 67 | displayNameController.text = user.displayName; 68 | bioController.text = user.bio; 69 | setState(() { 70 | isLoading=false; 71 | }); 72 | } 73 | 74 | updateProfileData() 75 | { 76 | setState(() { 77 | displayNameController.text.trim().length<3||displayNameController.text.isEmpty?_displayNameValid=false:_displayNameValid=true; 78 | bioController.text.trim().length>150?_bioValid=false:_bioValid=true; 79 | }); 80 | if (_displayNameValid&&_bioValid) 81 | { 82 | usersRef.document(widget.currentUserID).updateData({ 83 | 'displayName': displayNameController.text, 84 | 'bio':bioController.text 85 | }); 86 | } 87 | SnackBar snackBar =SnackBar(content: Text('Profile updated successfully!'),); 88 | _scaffoldKey.currentState.showSnackBar(snackBar); 89 | } 90 | logout() { 91 | googleSignIn.signOut(); 92 | Navigator.push(context, MaterialPageRoute(builder: (context)=>Home())); 93 | } 94 | @override 95 | void initState() { 96 | getUser(); 97 | super.initState(); 98 | } 99 | @override 100 | Widget build(BuildContext context) { 101 | return Scaffold( 102 | key: _scaffoldKey, 103 | appBar: AppBar( 104 | title: Text('Edit Profile'), 105 | actions: [ 106 | IconButton( 107 | icon: Icon( 108 | Icons.done,size: 30.0,color: Colors.green, 109 | ), 110 | onPressed: ()=>Navigator.pop(context), 111 | ), 112 | ], 113 | ), 114 | body: isLoading?circularProgress(): 115 | ListView( 116 | children: [ 117 | Container( 118 | child: Column( 119 | children: [ 120 | Padding( 121 | padding: EdgeInsets.only(top: 16,bottom: 8.0), 122 | child: CircleAvatar(radius: 50.0,backgroundImage: CachedNetworkImageProvider(currentUser.photoUrl),), 123 | ), 124 | Padding( 125 | padding: EdgeInsets.all(16.0), 126 | child: Column( 127 | children: [ 128 | buildDisplayField(), 129 | buildBioField(), 130 | ], 131 | ), 132 | ), 133 | RaisedButton( 134 | onPressed: updateProfileData, 135 | child: Text('Update Profile',style: TextStyle(fontSize: 20.0,fontWeight: FontWeight.bold),), 136 | ), 137 | Padding( 138 | padding: const EdgeInsets.all(16.0), 139 | child: FlatButton.icon(onPressed: logout, icon: Icon(Icons.cancel,color: Colors.red,), label: Text('Log Out',style: TextStyle(color: Colors.red),),), 140 | ), 141 | ], 142 | ), 143 | ), 144 | ], 145 | ), 146 | ); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /lib/pages/home.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:cloud_firestore/cloud_firestore.dart'; 4 | import 'package:firebase_messaging/firebase_messaging.dart'; 5 | import 'package:firebase_storage/firebase_storage.dart'; 6 | import 'package:flutter/cupertino.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:socialize/models/user.dart'; 9 | import 'package:socialize/pages/create_account.dart'; 10 | import 'package:socialize/pages/activity_feed.dart'; 11 | import 'package:socialize/pages/profile.dart'; 12 | import 'package:socialize/pages/search.dart'; 13 | import 'package:socialize/pages/timeline.dart'; 14 | import 'package:socialize/pages/upload.dart'; 15 | import 'package:google_sign_in/google_sign_in.dart'; 16 | 17 | GoogleSignIn googleSignIn = GoogleSignIn(); 18 | final usersRef = Firestore.instance.collection('users'); 19 | final postsRef = Firestore.instance.collection('posts'); 20 | final commentsRef = Firestore.instance.collection('comments'); 21 | final activityFeedRef = Firestore.instance.collection('feed'); 22 | final followersRef = Firestore.instance.collection('followers'); 23 | final followingRef = Firestore.instance.collection('following'); 24 | final timelineRef = Firestore.instance.collection('timeline'); 25 | final StorageReference storageRef = FirebaseStorage.instance.ref(); 26 | final DateTime timeStamp = DateTime.now(); 27 | User currentUser; 28 | 29 | class Home extends StatefulWidget { 30 | @override 31 | _HomeState createState() => _HomeState(); 32 | } 33 | 34 | class _HomeState extends State { 35 | bool isAuth = false; 36 | PageController pageController; 37 | int pageIndex = 0; 38 | final _scaffoldKey = GlobalKey(); 39 | FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); 40 | onTap(int pageIndex) { 41 | pageController.animateToPage( 42 | pageIndex, 43 | duration: Duration(milliseconds: 300), 44 | curve: Curves.easeInOutCubic, 45 | ); 46 | } 47 | 48 | onPageChanged(int pageIndex) { 49 | setState(() { 50 | this.pageIndex = pageIndex; 51 | }); 52 | } 53 | 54 | login() { 55 | googleSignIn.signIn(); 56 | } //sign in and sign out functions 57 | 58 | logout() { 59 | googleSignIn.signOut(); 60 | } 61 | 62 | handleSignIn(GoogleSignInAccount account) async{ 63 | if (account != null) { 64 | await createUserInFireStore(); 65 | setState(() { 66 | isAuth = true; 67 | }); 68 | configurePushNotifications(); 69 | } else { 70 | setState(() { 71 | isAuth = false; 72 | }); 73 | } 74 | } 75 | configurePushNotifications(){ 76 | final GoogleSignInAccount user = googleSignIn.currentUser; 77 | if (Platform.isIOS) getIosPermissions(); 78 | 79 | _firebaseMessaging.getToken().then((token) { 80 | // print("Firebase Messaging Token: $token\n"); 81 | usersRef 82 | .document(user.id) 83 | .updateData({"androidNotificationToken": token}); 84 | }); 85 | 86 | _firebaseMessaging.configure( 87 | // onLaunch: (Map message) async {}, 88 | // onResume: (Map message) async {}, 89 | onMessage: (Map message) async { 90 | //print("on message: $message\n"); 91 | final String recipientId = message['data']['recipient']; 92 | final String body = message['notification']['body']; 93 | if (recipientId == user.id) { 94 | //print("Notification shown!"); 95 | SnackBar snackbar = SnackBar( 96 | content: Text( 97 | body, 98 | overflow: TextOverflow.ellipsis, 99 | )); 100 | _scaffoldKey.currentState.showSnackBar(snackbar); 101 | } 102 | print("Notification NOT shown"); 103 | }, 104 | ); 105 | } 106 | getIosPermissions(){ 107 | _firebaseMessaging.requestNotificationPermissions(IosNotificationSettings(alert: true,badge: true,sound: true,)); 108 | _firebaseMessaging.onIosSettingsRegistered.listen((settings) { 109 | //print("settings registered : $settings"); 110 | }); 111 | } 112 | createUserInFireStore() async { 113 | // check if the user is on our database 114 | final GoogleSignInAccount user = googleSignIn.currentUser; 115 | DocumentSnapshot doc = await usersRef.document(user.id).get(); 116 | // if not create new user 117 | if (!doc.exists) { 118 | final username = await Navigator.push( 119 | context, 120 | MaterialPageRoute( 121 | builder: (context) => CreateAccount(), 122 | ), 123 | ); 124 | usersRef.document(user.id).setData({ 125 | "id": user.id, 126 | "username": username, 127 | "photoURL": user.photoUrl, 128 | "displayName": user.displayName, 129 | "email": user.email, 130 | "bio": "", 131 | "timeStamp": timeStamp, 132 | }); 133 | //add user to his own followers 134 | followersRef.document(user.id).collection('userFollowers').document(user.id).setData({}); 135 | doc = await usersRef.document(user.id).get(); 136 | } 137 | currentUser =User.fromDocument(doc); 138 | // print(currentUser.email); 139 | 140 | } 141 | 142 | @override 143 | void dispose() { 144 | pageController.dispose(); 145 | super.dispose(); 146 | } 147 | 148 | Scaffold buildAuthScreen() // will be the timeline screen soon isa 149 | { 150 | return Scaffold( 151 | key : _scaffoldKey, 152 | body: PageView( 153 | children: [ 154 | Timeline(currentUser : currentUser), 155 | ActivityFeed(), 156 | Upload(currentUser : currentUser), 157 | Search(), 158 | Profile(profileId: currentUser?.id,), 159 | ], 160 | controller: pageController, 161 | onPageChanged: onPageChanged, 162 | physics: NeverScrollableScrollPhysics(), 163 | ), 164 | bottomNavigationBar: CupertinoTabBar( 165 | activeColor: Theme.of(context).accentColor, 166 | currentIndex: pageIndex, 167 | onTap: onTap, 168 | items: [ 169 | BottomNavigationBarItem(icon: Icon(Icons.whatshot)), 170 | BottomNavigationBarItem(icon: Icon(Icons.notifications_active)), 171 | BottomNavigationBarItem( 172 | icon: Icon( 173 | Icons.photo_camera, 174 | size: 35.0, 175 | )), 176 | BottomNavigationBarItem(icon: Icon(Icons.search)), 177 | BottomNavigationBarItem(icon: Icon(Icons.account_circle)), 178 | ], 179 | ), 180 | ); 181 | } 182 | 183 | Scaffold buildUnAuthScreen() { 184 | return Scaffold( 185 | body: Container( 186 | decoration: BoxDecoration( 187 | gradient: LinearGradient( 188 | begin: Alignment.topRight, 189 | end: Alignment.bottomLeft, 190 | colors: [ 191 | Theme.of(context).accentColor, 192 | Theme.of(context).primaryColorLight, 193 | ], 194 | ), 195 | ), 196 | alignment: Alignment.center, 197 | child: Column( 198 | mainAxisAlignment: MainAxisAlignment.center, 199 | crossAxisAlignment: CrossAxisAlignment.center, 200 | children: [ 201 | Text( 202 | 'Socialize!', 203 | style: TextStyle( 204 | fontFamily: 'Signatra', 205 | fontSize: 90.0, 206 | color: Colors.white, 207 | ), 208 | ), //title 209 | GestureDetector( 210 | onTap: login, 211 | child: Image.asset('assets/images/google_signin_button.png'), 212 | ), // i was able to use flat button also ?google sign in 213 | ], 214 | ), 215 | ), 216 | ); 217 | } 218 | 219 | @override 220 | void initState() { 221 | // recognizeing loging in and out 222 | googleSignIn.onCurrentUserChanged.listen((account) { 223 | handleSignIn(account); 224 | }, onError: (err) { 225 | // print(err); 226 | }); 227 | googleSignIn.signInSilently(suppressErrors: false).then((account) { 228 | handleSignIn(account); 229 | }).catchError((err) { 230 | // print(err); 231 | }); 232 | pageController = PageController(); //can change initital page 233 | //followersRef.document(currentUser.id).collection('userFollowers').document(currentUser.id).setData({}); 234 | 235 | super.initState(); 236 | } 237 | 238 | @override 239 | Widget build(BuildContext context) { 240 | return isAuth ? buildAuthScreen() : buildUnAuthScreen(); 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /lib/pages/post_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:socialize/pages/home.dart'; 3 | import 'package:socialize/widgets/header.dart'; 4 | import 'package:socialize/widgets/post.dart'; 5 | import 'package:socialize/widgets/progress.dart'; 6 | 7 | class PostScreen extends StatelessWidget { 8 | final String postId,userId; 9 | PostScreen({this.postId, this.userId}); 10 | @override 11 | Widget build(BuildContext context) { 12 | return FutureBuilder( 13 | future: postsRef.document(userId).collection('usersPosts').document(postId).get(), 14 | builder: (context,snapshot){ 15 | if (!snapshot.hasData) 16 | return circularProgress(); 17 | Post post = Post.fromDocument(snapshot.data); 18 | return Center( 19 | child: Scaffold( 20 | appBar: header(context,pageTitle: post.caption), 21 | body: ListView( 22 | children: [ 23 | Container( 24 | child: post, 25 | ) 26 | ], 27 | ), 28 | ), 29 | ); 30 | }, 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/pages/profile.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:cloud_firestore/cloud_firestore.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/rendering.dart'; 5 | import 'package:flutter_svg/svg.dart'; 6 | import 'package:socialize/pages/edit_profile.dart'; 7 | import 'package:socialize/widgets/header.dart'; 8 | import 'package:socialize/widgets/post.dart'; 9 | import 'package:socialize/widgets/post_tile.dart'; 10 | import 'package:socialize/widgets/progress.dart'; 11 | import 'home.dart'; 12 | import 'package:socialize/models/user.dart'; 13 | class Profile extends StatefulWidget { 14 | final profileId; 15 | 16 | Profile({this.profileId}); 17 | @override 18 | _ProfileState createState() => _ProfileState(); 19 | } 20 | 21 | class _ProfileState extends State { 22 | final String currentUserId = currentUser?.id; 23 | String postOrientation='grid'; 24 | List posts =[]; 25 | int postCount=0; 26 | int followersCount=0; 27 | int followingCount=0; 28 | bool isLoading=false; 29 | bool isFollowing= false; 30 | Column buildCountColumn(String label, int count) 31 | { 32 | return Column( 33 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 34 | mainAxisSize: MainAxisSize.min, 35 | children: [ 36 | Text( 37 | count.toString(), 38 | style: TextStyle(fontSize: 22.0,fontWeight: FontWeight.bold), 39 | ), 40 | SizedBox(height: 4,), 41 | Text( 42 | label, 43 | style: TextStyle(fontSize: 16,fontWeight: FontWeight.w400), 44 | ), 45 | ], 46 | ); 47 | } 48 | Container buildButton({String text,Function onPressed}) 49 | { 50 | return Container( 51 | padding: EdgeInsets.only(top: 2.0), 52 | child: FlatButton( 53 | onPressed: onPressed, 54 | child: Container( 55 | decoration: BoxDecoration( 56 | color: isFollowing?Colors.white:Theme.of(context).accentColor, 57 | border: Border.all(color:isFollowing?Colors.white:Theme.of(context).accentColor,), 58 | borderRadius: BorderRadius.circular(5.0), 59 | ), 60 | alignment: Alignment.center, 61 | child: Text(text, 62 | style: TextStyle(fontWeight: FontWeight.bold, 63 | color: isFollowing?Colors.black:Colors.white), 64 | ), 65 | width: 250.0, 66 | height: 27.0, 67 | ), 68 | ), 69 | ); 70 | } 71 | buildProfileButton(){ 72 | bool isProfileOwner = currentUserId==widget.profileId; 73 | if (isProfileOwner) 74 | return buildButton(text:'Edit Profile',onPressed: (){ 75 | Navigator.push(context, MaterialPageRoute(builder: (context)=>EditProfile(currentUserID: currentUserId,))); 76 | }); 77 | else if (isFollowing) 78 | { 79 | return buildButton(text: "UnFollow",onPressed: handleUnFollow); 80 | } 81 | else if (!isFollowing) 82 | { 83 | return buildButton(text: "Follow",onPressed: handleFollow); 84 | } 85 | } 86 | handleUnFollow() 87 | { 88 | setState(() { 89 | isFollowing=false; 90 | followersCount--; 91 | }); 92 | // remove current user to this user profile followers 93 | followersRef.document(widget.profileId).collection('userFollowers').document(currentUserId) 94 | .get().then((doc){ 95 | if (doc.exists) 96 | doc.reference.delete(); 97 | }); 98 | // remove this user to current user following 99 | followingRef.document(currentUserId).collection('userFollowers').document(widget.profileId) 100 | .get().then((doc){ 101 | if (doc.exists) 102 | doc.reference.delete(); 103 | }); 104 | // remove activity feed to this user 105 | activityFeedRef.document(widget.profileId).collection('feedItems').document(currentUserId) 106 | .get().then((doc){ 107 | if (doc.exists) 108 | doc.reference.delete(); 109 | }); 110 | } 111 | handleFollow() 112 | { 113 | setState(() { 114 | isFollowing=true; 115 | followersCount++; 116 | }); 117 | // adding current user to this user profile followers 118 | followersRef.document(widget.profileId).collection('userFollowers').document(currentUserId) 119 | .setData({}); 120 | // adding this user to current user following 121 | followingRef.document(currentUserId).collection('userFollowers').document(widget.profileId) 122 | .setData({}); 123 | // add activity feed to this user 124 | activityFeedRef.document(widget.profileId).collection('feedItems').document(currentUserId) 125 | .setData({ 126 | 'type': 'follow', 127 | 'ownerId':widget.profileId, 128 | 'username': currentUser.username, 129 | 'userId': currentUser.id, 130 | 'userProfileImg': currentUser.photoUrl, 131 | 'timestamp': timeStamp, 132 | }); 133 | } 134 | buildProfileHeader(){ 135 | return FutureBuilder( 136 | future: usersRef.document(widget.profileId).get(), 137 | builder: (context,snapshot){ 138 | if (!snapshot.hasData) 139 | return circularProgress(); 140 | User user = User.fromDocument(snapshot.data); 141 | return Padding( 142 | padding: EdgeInsets.all(16.0), 143 | child: Column( 144 | children: [ 145 | Row( 146 | children: [ 147 | CircleAvatar( 148 | radius: 40.0, 149 | backgroundImage: CachedNetworkImageProvider(user.photoUrl), 150 | backgroundColor: Colors.teal[500], 151 | ), 152 | Expanded( 153 | flex: 1, 154 | child: Column( 155 | children: [ 156 | Row( 157 | mainAxisSize: MainAxisSize.max, 158 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 159 | children: [ 160 | buildCountColumn('Posts',postCount), 161 | buildCountColumn('Followers',followersCount-1), 162 | buildCountColumn('Following',followingCount), 163 | ], 164 | ), 165 | Row( 166 | mainAxisAlignment: MainAxisAlignment.center, 167 | children: [ 168 | buildProfileButton(), 169 | ], 170 | ), 171 | ], 172 | ), 173 | ) 174 | ], 175 | ), 176 | Container( 177 | alignment: Alignment.centerLeft, 178 | padding: EdgeInsets.only(top: 12.0), 179 | child: Text( 180 | user.username,style: TextStyle(fontSize: 16.0,fontWeight: FontWeight.bold), 181 | ), 182 | ), 183 | Container( 184 | alignment: Alignment.centerLeft, 185 | padding: EdgeInsets.only(top: 12.0), 186 | child: Text( 187 | user.displayName,style: TextStyle(fontWeight: FontWeight.bold), 188 | ), 189 | ), 190 | Container( 191 | alignment: Alignment.centerLeft, 192 | padding: EdgeInsets.only(top: 12.0), 193 | child: Text( 194 | user.bio, 195 | ), 196 | ), 197 | ], 198 | ), 199 | ); 200 | }, 201 | ); 202 | } 203 | getUserPosts()async{ 204 | setState(() { 205 | isLoading = true; 206 | }); 207 | QuerySnapshot snapshot = await postsRef.document(widget.profileId) 208 | .collection('usersPosts').orderBy('timeStamp',descending: true) 209 | .getDocuments(); 210 | setState(() { 211 | isLoading =false; 212 | postCount = snapshot.documents.length; 213 | posts=snapshot.documents.map((doc)=>Post.fromDocument(doc)).toList(); 214 | }); 215 | } 216 | buildProfilePosts() 217 | { 218 | if (isLoading) 219 | return circularProgress(); 220 | if (posts.isEmpty) 221 | { 222 | return Container( 223 | child: Column( 224 | mainAxisAlignment: MainAxisAlignment.center, 225 | children: [ 226 | Padding( 227 | padding: const EdgeInsets.only(top: 20,bottom: 20.0), 228 | child: Text( 229 | 'No posts yet', 230 | style: TextStyle( 231 | fontSize: 22.0, 232 | fontWeight: FontWeight.bold, 233 | color: Colors.pink[400], 234 | ), 235 | ), 236 | ), 237 | SvgPicture.asset('assets/images/no_content.svg',height: 260.0,), 238 | 239 | ], 240 | ), 241 | ); 242 | } 243 | else if (postOrientation=='grid') 244 | { 245 | List gridTiles=[]; 246 | posts.forEach((post){ 247 | gridTiles.add(GridTile(child: PostTile(post),),); 248 | }); 249 | return GridView.count( 250 | children: gridTiles, 251 | physics: NeverScrollableScrollPhysics(), 252 | crossAxisCount: 3, 253 | childAspectRatio: 1, 254 | mainAxisSpacing: 1.5, 255 | crossAxisSpacing: 1.5, 256 | shrinkWrap: true, 257 | ); 258 | } 259 | else 260 | return Column(children: posts); 261 | } 262 | buildTogglePostOreintation(){ 263 | return Row( 264 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 265 | children: [ 266 | IconButton( 267 | icon: Icon(Icons.grid_on,color: postOrientation=='grid'?Theme.of(context).accentColor:Colors.white,), 268 | onPressed: (){ 269 | setState(() { 270 | postOrientation='grid'; 271 | }); 272 | }, 273 | ), 274 | IconButton( 275 | onPressed: (){ 276 | setState(() { 277 | postOrientation='list'; 278 | }); 279 | }, 280 | icon: Icon(Icons.list,color: postOrientation=='list'?Theme.of(context).accentColor:Colors.white,), 281 | ), 282 | ], 283 | ); 284 | } 285 | @override 286 | void initState() { 287 | getUserPosts(); 288 | getFollowers(); 289 | getFollowing(); 290 | checkFollowing(); 291 | super.initState(); 292 | } 293 | getFollowers()async { 294 | QuerySnapshot snapshot = await followersRef.document(widget.profileId).collection('userFollowers').getDocuments(); 295 | setState(() { 296 | followersCount = snapshot.documents.length; 297 | }); 298 | } 299 | getFollowing() async{ 300 | QuerySnapshot snapshot = await followingRef.document(widget.profileId).collection('userFollowers').getDocuments(); 301 | setState(() { 302 | followingCount = snapshot.documents.length; 303 | }); 304 | } 305 | checkFollowing()async{ 306 | DocumentSnapshot doc=await followersRef.document(widget.profileId).collection('userFollowers').document(currentUserId) 307 | .get(); 308 | setState(() { 309 | isFollowing = doc.exists; 310 | }); 311 | } 312 | @override 313 | Widget build(BuildContext context) { 314 | return Scaffold( 315 | appBar: header(context,pageTitle: "Profile"), 316 | body: ListView( 317 | children: [ 318 | buildProfileHeader(), 319 | Divider(height: 0.0,), 320 | buildTogglePostOreintation(), 321 | Divider(height: 0.0,), 322 | buildProfilePosts(), 323 | ], 324 | ), 325 | ); 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /lib/pages/search.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:cloud_firestore/cloud_firestore.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/painting.dart'; 5 | import 'package:flutter_svg/flutter_svg.dart'; 6 | import 'package:socialize/pages/activity_feed.dart'; 7 | import 'package:socialize/pages/home.dart'; 8 | import 'package:socialize/widgets/progress.dart'; 9 | import 'package:socialize/models/user.dart'; 10 | 11 | class Search extends StatefulWidget { 12 | @override 13 | _SearchState createState() => _SearchState(); 14 | } 15 | 16 | class _SearchState extends State with AutomaticKeepAliveClientMixin{ 17 | TextEditingController searchController = TextEditingController(); 18 | Future searchResultsFuture; 19 | 20 | handleSearch(String query) { 21 | Future users = usersRef 22 | .where('displayName', isGreaterThanOrEqualTo: query) 23 | .getDocuments(); 24 | setState(() { 25 | searchResultsFuture = users; 26 | }); 27 | } 28 | 29 | buildSearchResults() { 30 | return FutureBuilder( 31 | future: searchResultsFuture, 32 | builder: (context, snapshot) { 33 | if (!snapshot.hasData) return circularProgress(); 34 | List searchResults = []; 35 | snapshot.data.documents.forEach((doc) { 36 | User user = User.fromDocument(doc); 37 | UserResult searchResult = UserResult(user); 38 | searchResults.add(searchResult); 39 | }); 40 | return ListView(children: searchResults); 41 | }); 42 | } 43 | 44 | AppBar buildSearchField() { 45 | return AppBar( 46 | title: TextFormField( 47 | controller: searchController, 48 | onFieldSubmitted: handleSearch, 49 | decoration: InputDecoration( 50 | hintText: "Serach for User ...", 51 | filled: true, 52 | prefixIcon: Icon( 53 | Icons.account_box, 54 | size: 28.0, 55 | ), 56 | suffixIcon: IconButton( 57 | icon: Icon( 58 | Icons.clear, 59 | ), 60 | onPressed: () { 61 | searchController.clear(); 62 | }, 63 | )), 64 | ), 65 | ); 66 | } 67 | 68 | Container buildNoContent() { 69 | final orientation = MediaQuery.of(context).orientation; 70 | return Container( 71 | child: Center( 72 | child: ListView( 73 | shrinkWrap: true, 74 | children: [ 75 | SvgPicture.asset( 76 | 'assets/images/search.svg', 77 | height: orientation == Orientation.portrait ? 300 : 200, 78 | ), 79 | Text( 80 | 'Find User', 81 | textAlign: TextAlign.center, 82 | style: TextStyle( 83 | fontWeight: FontWeight.w600, 84 | fontSize: 60.0, 85 | fontStyle: FontStyle.italic, 86 | ), 87 | ), 88 | ], 89 | ), 90 | ), 91 | ); 92 | } 93 | bool get wantKeepAlive=>true; 94 | @override 95 | Widget build(BuildContext context) { 96 | super.build(context); 97 | return Scaffold( 98 | appBar: buildSearchField(), 99 | body: 100 | searchResultsFuture == null ? buildNoContent() : buildSearchResults(), 101 | ); 102 | } 103 | } 104 | 105 | class UserResult extends StatelessWidget { 106 | final User user; 107 | UserResult(this.user); 108 | @override 109 | Widget build(BuildContext context) { 110 | return Container( 111 | color: Theme.of(context).primaryColorLight, 112 | child: Column( 113 | children: [ 114 | GestureDetector( 115 | onTap: () =>showProfile(context,profileId: user.id), 116 | child: ListTile( 117 | leading: CircleAvatar( 118 | backgroundColor: Colors.teal, 119 | backgroundImage: CachedNetworkImageProvider(user.photoUrl), 120 | ), 121 | title: Text( 122 | user.displayName, 123 | style: TextStyle(fontWeight: FontWeight.bold), 124 | ), 125 | subtitle: Text( 126 | user.username, 127 | ), 128 | ), 129 | ), 130 | Divider( 131 | height: 2.0, 132 | color: Colors.teal, 133 | ) 134 | ], 135 | ), 136 | ); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /lib/pages/timeline.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:socialize/models/user.dart'; 4 | import 'package:socialize/pages/search.dart'; 5 | import 'package:socialize/widgets/header.dart'; 6 | import 'package:socialize/widgets/post.dart'; 7 | import 'package:socialize/widgets/progress.dart'; 8 | import 'home.dart'; 9 | 10 | class Timeline extends StatefulWidget { 11 | final User currentUser; 12 | Timeline({this.currentUser}); 13 | @override 14 | _TimelineState createState() => _TimelineState(); 15 | } 16 | 17 | class _TimelineState extends State { 18 | List posts; 19 | List followingList = []; 20 | getTimeline() async { 21 | QuerySnapshot snapshot = await timelineRef 22 | .document(widget.currentUser.id) 23 | .collection("timelinePosts") 24 | .orderBy("timeStamp", descending: true) 25 | .getDocuments(); 26 | List posts = 27 | snapshot.documents.map((doc) => Post.fromDocument(doc)).toList(); 28 | setState(() { 29 | this.posts = posts; 30 | }); 31 | } 32 | 33 | buildTimeline() { 34 | if (posts == null) { 35 | return circularProgress(); 36 | } else if (posts.isEmpty) { 37 | return buildUsersToFollow(); 38 | } else 39 | return ListView( 40 | children: posts, 41 | ); 42 | } 43 | 44 | buildUsersToFollow() { 45 | return StreamBuilder( 46 | stream: usersRef 47 | .orderBy('timeStamp', descending: false) 48 | .limit(30) 49 | .snapshots(), 50 | builder: (context, snapshot) { 51 | if (!snapshot.hasData) { 52 | return circularProgress(); 53 | } 54 | List userResults = []; 55 | snapshot.data.documents.forEach((doc) { 56 | User user = User.fromDocument(doc); 57 | final bool isAuth = widget.currentUser.id == user.id; 58 | final bool isFollowingUser = followingList.contains(user.id); 59 | if (isAuth || isFollowingUser) 60 | return; 61 | else { 62 | UserResult userResult = UserResult(user); 63 | userResults.add(userResult); 64 | } 65 | }); 66 | return Container( 67 | color: Theme.of(context).primaryColor.withOpacity(.2), 68 | child: Column( 69 | children: [ 70 | Container( 71 | padding: EdgeInsets.all(10.0), 72 | child: Row( 73 | mainAxisAlignment: MainAxisAlignment.center, 74 | children: [ 75 | Icon( 76 | Icons.person_add, 77 | color: Theme.of(context).accentColor, 78 | size: 30, 79 | ), 80 | SizedBox(width: 10.0), 81 | Text( 82 | "Users To Follow", 83 | style: TextStyle( 84 | fontSize: 30.0, 85 | fontWeight: FontWeight.bold, 86 | 87 | ), 88 | ), 89 | ], 90 | ), 91 | ), 92 | Column( 93 | children: userResults, 94 | ), 95 | ], 96 | ), 97 | ); 98 | }); 99 | } 100 | 101 | getFollowingUsers() async { 102 | QuerySnapshot snapshot = await followingRef 103 | .document(currentUser.id) 104 | .collection('userFollowers') 105 | .getDocuments(); 106 | setState(() { 107 | followingList = snapshot.documents.map((doc) => doc.documentID).toList(); 108 | }); 109 | } 110 | 111 | @override 112 | void initState() { 113 | getTimeline(); 114 | getFollowingUsers(); 115 | super.initState(); 116 | } 117 | 118 | @override 119 | Widget build(context) { 120 | return Scaffold( 121 | appBar: header(context, isTimeLine: true), 122 | body: RefreshIndicator( 123 | child: buildTimeline(), onRefresh: () => getTimeline()), 124 | ); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /lib/pages/upload.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'package:cached_network_image/cached_network_image.dart'; 3 | import 'package:firebase_storage/firebase_storage.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter_svg/flutter_svg.dart'; 6 | import 'package:geolocator/geolocator.dart'; 7 | import 'package:image_picker/image_picker.dart'; 8 | import 'package:path_provider/path_provider.dart'; 9 | import 'package:socialize/models/user.dart'; 10 | import 'package:image/image.dart' as Im; 11 | import 'package:socialize/pages/home.dart'; 12 | import 'package:socialize/widgets/progress.dart'; 13 | import 'package:uuid/uuid.dart'; 14 | 15 | class Upload extends StatefulWidget { 16 | final User currentUser; 17 | Upload({this.currentUser}); 18 | @override 19 | _UploadState createState() => _UploadState(); 20 | } 21 | 22 | class _UploadState extends State with AutomaticKeepAliveClientMixin{ 23 | TextEditingController locationController =TextEditingController(); 24 | TextEditingController captionController =TextEditingController(); 25 | bool isUploading = false; 26 | File file; 27 | String postId = Uuid().v4(); 28 | handleTakePhoto() async{ 29 | Navigator.pop(context); 30 | File file =await ImagePicker.pickImage(source: ImageSource.camera); 31 | setState(() { 32 | this.file =file; 33 | }); 34 | } 35 | handleGallaryPhoto() async{ 36 | Navigator.pop(context); 37 | File file =await ImagePicker.pickImage(source: ImageSource.gallery,); 38 | setState(() { 39 | this.file =file; 40 | }); 41 | } 42 | selectImage(parentContext) 43 | { 44 | return showDialog( 45 | context: parentContext, 46 | builder: (context){ 47 | return SimpleDialog( 48 | title: Text('Craete Post'), 49 | children: [ 50 | SimpleDialogOption( 51 | child: Text( 52 | 'Take a Photo' 53 | ), 54 | onPressed: handleTakePhoto, 55 | ), 56 | SimpleDialogOption( 57 | child: Text( 58 | 'Photo from Gallary' 59 | ), 60 | onPressed: handleGallaryPhoto, 61 | ), 62 | SimpleDialogOption( 63 | child: Text( 64 | 'Cancel' 65 | ), 66 | onPressed: (){ 67 | Navigator.pop(context); 68 | }, 69 | ), 70 | ], 71 | ); 72 | } 73 | ); 74 | } 75 | Container buildSplashScreen() { 76 | return Container( 77 | child: Column( 78 | mainAxisAlignment: MainAxisAlignment.center, 79 | children: [ 80 | SvgPicture.asset('assets/images/upload.svg'), 81 | Padding( 82 | padding: EdgeInsets.only(top: 20.0), 83 | child: RaisedButton( 84 | shape: RoundedRectangleBorder( 85 | borderRadius: BorderRadius.circular(8.0), 86 | ), 87 | onPressed: ()=>selectImage(context), 88 | child: Text( 89 | 'Upload Image', 90 | style: TextStyle( 91 | fontSize: 22.0, 92 | ), 93 | ), 94 | ), 95 | ) 96 | ], 97 | ), 98 | ); 99 | } 100 | clearImage(){ 101 | setState(() { 102 | file=null; 103 | }); 104 | } 105 | compressImage() async{ 106 | final tempDir = await getTemporaryDirectory(); 107 | final path = tempDir.path; 108 | Im.Image imageFile = Im.decodeImage(file.readAsBytesSync()); 109 | final compressedImageFile = File('$path/img_$postId.jpg')..writeAsBytesSync(Im.encodeJpg(imageFile,quality: 85)); 110 | setState(() { 111 | file=compressedImageFile; 112 | }); 113 | } 114 | FutureuploadImage(imageFile)async 115 | { 116 | StorageUploadTask uploadTask=storageRef.child('post_$postId.jpg').putFile(imageFile); 117 | StorageTaskSnapshot storageSnap =await uploadTask.onComplete; 118 | return await storageSnap.ref.getDownloadURL(); 119 | } 120 | createPostInFireStore({String mediaUrl,String location,String caption}) 121 | { 122 | postsRef.document((widget.currentUser.id)).collection('usersPosts').document(postId) 123 | .setData({ 124 | 'postId':postId, 125 | 'ownerId':widget.currentUser.id, 126 | 'username':widget.currentUser.username, 127 | 'mediaUrl':mediaUrl, 128 | 'caption':caption, 129 | "location":location, 130 | 'timeStamp':timeStamp, 131 | 'likes':{} 132 | 133 | }); 134 | } 135 | handleSubmit() async 136 | { 137 | setState(() { 138 | isUploading =true; 139 | }); 140 | await compressImage(); 141 | String mediaUrl = await uploadImage(file); 142 | await createPostInFireStore(mediaUrl: mediaUrl,location: locationController.text,caption: captionController.text); 143 | locationController.clear(); 144 | captionController.clear(); 145 | setState(() { 146 | isUploading =false; 147 | file=null; 148 | }); 149 | Navigator.push(context, MaterialPageRoute(builder: (context)=>Home())); 150 | } 151 | Scaffold buildUploadForm(){ 152 | return Scaffold( 153 | appBar: AppBar( 154 | leading: IconButton( 155 | icon: Icon(Icons.arrow_back), 156 | onPressed: clearImage, 157 | ), 158 | title: Center(child: Text('Caption Post')), 159 | actions: [ 160 | FlatButton( 161 | child: Text('Post', 162 | style: TextStyle( 163 | fontWeight: FontWeight.bold, 164 | fontSize: 20.0 165 | ), 166 | ), 167 | onPressed: isUploading?null:()=>handleSubmit(), 168 | ), 169 | ], 170 | ), 171 | body: ListView( 172 | children: [ 173 | isUploading?linearProgress():Text(""), 174 | Container( 175 | height: 220, 176 | width: MediaQuery.of(context).size.width*.8, 177 | child: Center( 178 | child: AspectRatio(aspectRatio: 16/9, 179 | child: Container( 180 | decoration: BoxDecoration( 181 | image: DecorationImage( 182 | fit: BoxFit.cover, 183 | image: FileImage(file), 184 | ) 185 | ), 186 | ), 187 | ), 188 | ), 189 | ), 190 | SizedBox( 191 | height: 10, 192 | ), 193 | ListTile( 194 | leading: CircleAvatar( 195 | backgroundImage: CachedNetworkImageProvider(widget.currentUser.photoUrl), 196 | ), 197 | title: Container( 198 | width: 250.0, 199 | child: TextField( 200 | controller: captionController, 201 | decoration: InputDecoration( 202 | hintText: 'Write a caption ...', 203 | border: InputBorder.none, 204 | ), 205 | ), 206 | ), 207 | ), 208 | Divider(), 209 | ListTile( 210 | leading: Icon(Icons.pin_drop,size: 35.0,), 211 | title: Container( 212 | width: 250.0, 213 | child: TextField( 214 | controller: locationController, 215 | decoration: InputDecoration( 216 | hintText: 'Where this photo taken!', 217 | border: InputBorder.none, 218 | ), 219 | ), 220 | ), 221 | ), 222 | Container( 223 | width: 200.0, 224 | height: 100.0, 225 | alignment: Alignment.center, 226 | child: RaisedButton.icon( 227 | label: Text('Use current location'), 228 | icon: Icon(Icons.my_location,), 229 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)), 230 | color: Theme.of(context).accentColor, 231 | onPressed: getUserLocation, 232 | ), 233 | ) 234 | ], 235 | ), 236 | ); 237 | } 238 | getUserLocation() async{ 239 | Position position = await Geolocator().getCurrentPosition(desiredAccuracy : LocationAccuracy.medium); 240 | List placeMarks = await Geolocator().placemarkFromCoordinates(position.latitude, position.longitude); 241 | 242 | Placemark placeMark = placeMarks[0]; 243 | String adress= '${placeMark.locality}, ${placeMark.country}'; 244 | locationController.text =adress; 245 | } 246 | bool get wantKeepAlive=>true; 247 | @override 248 | Widget build(BuildContext context) { 249 | super.build(context); 250 | return file ==null ?buildSplashScreen():buildUploadForm(); 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /lib/widgets/custom_image.dart: -------------------------------------------------------------------------------- 1 | import 'package:cached_network_image/cached_network_image.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | cachedNetworkImage(mediaUrl) { 5 | return CachedNetworkImage( 6 | imageUrl: mediaUrl, 7 | fit: BoxFit.cover, 8 | placeholder: (context,url)=>Padding( 9 | child: CircularProgressIndicator(), 10 | padding: EdgeInsets.all(20), 11 | ), 12 | errorWidget: (context,url,error)=>Icon( 13 | Icons.error, 14 | ), 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /lib/widgets/header.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | AppBar header(context, {bool isTimeLine=false, String pageTitle}) { 4 | return AppBar( 5 | title: Text( 6 | isTimeLine?"Socilicze":pageTitle, 7 | style:TextStyle( 8 | fontSize: isTimeLine? 50.0:22.0, 9 | fontFamily: isTimeLine? "Signatra":"", 10 | ), 11 | overflow: TextOverflow.ellipsis, 12 | ), 13 | centerTitle: true, 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /lib/widgets/post.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:animator/animator.dart'; 4 | import 'package:cached_network_image/cached_network_image.dart'; 5 | import 'package:cloud_firestore/cloud_firestore.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:socialize/models/user.dart'; 8 | import 'package:socialize/pages/activity_feed.dart'; 9 | import 'package:socialize/pages/comments.dart'; 10 | import 'package:socialize/pages/home.dart'; 11 | import 'package:socialize/widgets/custom_image.dart'; 12 | import 'package:socialize/widgets/progress.dart'; 13 | 14 | class Post extends StatefulWidget { 15 | final String ownerId, postId, username, location, caption, mediaUrl; 16 | final dynamic likes; 17 | Post({ 18 | this.username, 19 | this.location, 20 | this.mediaUrl, 21 | this.postId, 22 | this.caption, 23 | this.likes, 24 | this.ownerId, 25 | }); 26 | factory Post.fromDocument(DocumentSnapshot doc) { 27 | return Post( 28 | ownerId: doc['ownerId'], 29 | postId: doc['postId'], 30 | username: doc['username'], 31 | location: doc['location'], 32 | mediaUrl: doc['mediaUrl'], 33 | caption: doc['caption'], 34 | likes: doc['likes'], 35 | ); 36 | } 37 | int getLikesCount(likes) { 38 | if (likes == null) return 0; 39 | int likesCount = 0; 40 | likes.values.forEach((val) { 41 | if (val == true) likesCount++; 42 | }); 43 | return likesCount; 44 | } 45 | 46 | @override 47 | _PostState createState() => _PostState( 48 | postId: this.postId, 49 | username: this.username, 50 | ownerId: this.ownerId, 51 | mediaUrl: this.mediaUrl, 52 | location: this.location, 53 | caption: this.caption, 54 | likes: this.likes, 55 | likesCount: getLikesCount(this.likes), 56 | ); 57 | } 58 | 59 | class _PostState extends State { 60 | final String ownerId, postId, username, location, caption, mediaUrl; 61 | final String currentUserId = currentUser?.id; 62 | Map likes; 63 | int likesCount; 64 | bool isLiked; 65 | bool showHeart = false; 66 | _PostState( 67 | {this.username, 68 | this.location, 69 | this.mediaUrl, 70 | this.postId, 71 | this.caption, 72 | this.likes, 73 | this.ownerId, 74 | this.likesCount}); 75 | buildPostHeader() { 76 | return FutureBuilder( 77 | future: usersRef.document(ownerId).get(), 78 | builder: (context, snapshot) { 79 | if (!snapshot.hasData) return circularProgress(); 80 | User user = User.fromDocument(snapshot.data); 81 | return ListTile( 82 | leading: CircleAvatar( 83 | backgroundImage: CachedNetworkImageProvider(user.photoUrl), 84 | backgroundColor: Colors.teal, 85 | ), 86 | title: Text( 87 | user.username, 88 | style: TextStyle(fontWeight: FontWeight.bold), 89 | ), 90 | onTap: () => showProfile(context, profileId: ownerId), 91 | subtitle: Text(location), 92 | trailing: ownerId==currentUserId?IconButton( 93 | onPressed: () => handleDeletePost(context), 94 | icon: Icon(Icons.more_vert), 95 | ):Text(""), 96 | ); 97 | }, 98 | ); 99 | } 100 | 101 | handleDeletePost(BuildContext parentContext) { 102 | return showDialog( 103 | context: parentContext, 104 | builder: (context) { 105 | return SimpleDialog( 106 | title: Text("Remove this post..?!"), 107 | children: [ 108 | SimpleDialogOption( 109 | child: Text( 110 | "Delete", 111 | style: TextStyle(color: Colors.red), 112 | ), 113 | onPressed: () { 114 | Navigator.push(context, MaterialPageRoute( 115 | builder: (context)=>Home() 116 | )); 117 | deletePost(); 118 | }, 119 | ), 120 | SimpleDialogOption( 121 | child: Text( 122 | "cancel", 123 | ), 124 | onPressed: () { 125 | Navigator.pop(context); 126 | }, 127 | ), 128 | ], 129 | ); 130 | }); 131 | } 132 | 133 | deletePost() async { 134 | // delete post itself 135 | postsRef 136 | .document(ownerId) 137 | .collection("usersPosts") 138 | .document(postId) 139 | .get() 140 | .then((doc) { 141 | if (doc.exists) { 142 | doc.reference.delete(); 143 | } 144 | }); 145 | // delete img from database 146 | storageRef.child("post_$postId.jpg").delete(); 147 | // delete activity feed 148 | QuerySnapshot activityFeedSnapshot = await activityFeedRef 149 | .document(ownerId) 150 | .collection("feedItems") 151 | .where("postId", isEqualTo: postId) 152 | .getDocuments(); 153 | activityFeedSnapshot.documents.forEach((doc){ 154 | if (doc.exists) { 155 | doc.reference.delete(); 156 | } 157 | }); 158 | // delete comments 159 | QuerySnapshot commentsSnapshot = await commentsRef 160 | .document(postId) 161 | .collection("comment") 162 | .getDocuments(); 163 | commentsSnapshot.documents.forEach((doc){ 164 | if (doc.exists) { 165 | doc.reference.delete(); 166 | } 167 | }); 168 | } 169 | 170 | addLikeToActivityFeed() { 171 | if (currentUserId != ownerId) { 172 | activityFeedRef 173 | .document(ownerId) 174 | .collection('feedItems') 175 | .document(postId) 176 | .setData({ 177 | 'type': 'like', 178 | 'username': currentUser.username, 179 | 'userId': currentUser.id, 180 | 'userProfileImg': currentUser.photoUrl, 181 | 'postId': postId, 182 | 'mediaUrl': mediaUrl, 183 | 'timestamp': timeStamp, 184 | }); 185 | } 186 | } 187 | 188 | removeLikeFromFeed() { 189 | if (currentUserId != ownerId) { 190 | activityFeedRef 191 | .document(ownerId) 192 | .collection('feedItems') 193 | .document(postId) 194 | .get() 195 | .then((doc) { 196 | if (doc.exists) doc.reference.delete(); 197 | }); 198 | } 199 | } 200 | 201 | handleLikePost() { 202 | bool _isLiked = likes[currentUserId] == true; 203 | if (_isLiked) { 204 | postsRef 205 | .document(ownerId) 206 | .collection('usersPosts') 207 | .document(postId) 208 | .updateData({'likes.$currentUserId': false}); 209 | removeLikeFromFeed(); 210 | setState(() { 211 | likesCount -= 1; 212 | isLiked = false; 213 | likes[currentUserId] = false; 214 | }); 215 | } else if (!_isLiked) { 216 | postsRef 217 | .document(ownerId) 218 | .collection('usersPosts') 219 | .document(postId) 220 | .updateData({'likes.$currentUserId': true}); 221 | addLikeToActivityFeed(); 222 | setState(() { 223 | likesCount += 1; 224 | isLiked = true; 225 | likes[currentUserId] = true; 226 | showHeart = true; 227 | }); 228 | Timer(Duration(milliseconds: 500), () { 229 | setState(() { 230 | showHeart = false; 231 | }); 232 | }); 233 | } 234 | } 235 | 236 | buildPostImage() { 237 | return GestureDetector( 238 | onDoubleTap: handleLikePost, 239 | child: Stack( 240 | alignment: Alignment.center, 241 | children: [ 242 | cachedNetworkImage(mediaUrl), 243 | showHeart 244 | ? Animator( 245 | duration: Duration(milliseconds: 300), 246 | tween: Tween(begin: .8, end: 1.6), 247 | curve: Curves.elasticOut, 248 | cycles: 0, 249 | builder: (context, anim, child) => Transform.scale( 250 | scale: anim.value, 251 | child: Icon( 252 | Icons.favorite, 253 | size: 120.0, 254 | color: Colors.red, 255 | ), 256 | ), 257 | ) 258 | : Text(""), 259 | ], 260 | ), 261 | ); 262 | } 263 | 264 | showComments(BuildContext context, 265 | {String postId, String ownerId, String mediaUrl}) { 266 | Navigator.push(context, MaterialPageRoute(builder: (context) { 267 | return Comments( 268 | postId: postId, 269 | postOwnerId: ownerId, 270 | mediaUrl: mediaUrl, 271 | ); 272 | })); 273 | } 274 | 275 | buildPostFooter() { 276 | return Column( 277 | children: [ 278 | Row( 279 | crossAxisAlignment: CrossAxisAlignment.start, 280 | children: [ 281 | Padding( 282 | padding: EdgeInsets.only(top: 40, left: 20), 283 | ), 284 | GestureDetector( 285 | onTap: handleLikePost, 286 | child: Icon( 287 | isLiked ? Icons.favorite : Icons.favorite_border, 288 | size: 28, 289 | color: Colors.pink, 290 | ), 291 | ), 292 | Padding( 293 | padding: EdgeInsets.only(right: 20), 294 | ), 295 | GestureDetector( 296 | onTap: () => showComments( 297 | context, 298 | postId: postId, 299 | ownerId: ownerId, 300 | mediaUrl: mediaUrl, 301 | ), 302 | child: Icon( 303 | Icons.chat, 304 | size: 28, 305 | color: Colors.blue[900], 306 | ), 307 | ), 308 | ], 309 | ), 310 | Row( 311 | children: [ 312 | Container( 313 | margin: EdgeInsets.only(left: 20), 314 | child: Text( 315 | '$likesCount likes', 316 | style: TextStyle(fontWeight: FontWeight.bold), 317 | ), 318 | ), 319 | ], 320 | ), 321 | Row( 322 | children: [ 323 | Container( 324 | margin: EdgeInsets.only(left: 20), 325 | child: Text( 326 | '$username ', 327 | style: TextStyle(fontWeight: FontWeight.bold), 328 | ), 329 | ), 330 | Expanded( 331 | child: Text(caption), 332 | ), 333 | ], 334 | ), 335 | ], 336 | ); 337 | } 338 | 339 | @override 340 | Widget build(BuildContext context) { 341 | isLiked = (likes[currentUserId] == true); 342 | return Column( 343 | mainAxisSize: MainAxisSize.min, 344 | children: [ 345 | buildPostHeader(), 346 | buildPostImage(), 347 | buildPostFooter(), 348 | ], 349 | ); 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /lib/widgets/post_tile.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:socialize/widgets/custom_image.dart'; 3 | import 'package:socialize/widgets/post.dart'; 4 | import 'package:socialize/pages/post_screen.dart'; 5 | 6 | class PostTile extends StatelessWidget { 7 | final Post post; 8 | showPost(context){ 9 | Navigator.push(context, MaterialPageRoute(builder: (context)=>PostScreen(userId: post.ownerId,postId: post.postId,))); 10 | } 11 | PostTile(this.post); 12 | @override 13 | Widget build(BuildContext context) { 14 | return GestureDetector( 15 | child: cachedNetworkImage(post.mediaUrl), 16 | onTap:()=> showPost(context), 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/widgets/progress.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | Container circularProgress() { 4 | return Container( 5 | alignment: Alignment.center, 6 | padding: EdgeInsets.only(top:10.0), 7 | child: CircularProgressIndicator( 8 | valueColor: AlwaysStoppedAnimation(Colors.teal), 9 | ), 10 | ); 11 | } 12 | 13 | Container linearProgress() { 14 | return Container( 15 | padding: EdgeInsets.only(bottom:10.0), 16 | child: LinearProgressIndicator( 17 | valueColor: AlwaysStoppedAnimation(Colors.teal), 18 | ), 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | animator: 5 | dependency: "direct main" 6 | description: 7 | name: animator 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.0.1" 11 | archive: 12 | dependency: transitive 13 | description: 14 | name: archive 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.0.13" 18 | args: 19 | dependency: transitive 20 | description: 21 | name: args 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.6.0" 25 | async: 26 | dependency: transitive 27 | description: 28 | name: async 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.4.1" 32 | boolean_selector: 33 | dependency: transitive 34 | description: 35 | name: boolean_selector 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "2.0.0" 39 | cached_network_image: 40 | dependency: "direct main" 41 | description: 42 | name: cached_network_image 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "2.0.0" 46 | charcode: 47 | dependency: transitive 48 | description: 49 | name: charcode 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.1.3" 53 | cloud_firestore: 54 | dependency: "direct main" 55 | description: 56 | name: cloud_firestore 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "0.9.13+1" 60 | collection: 61 | dependency: transitive 62 | description: 63 | name: collection 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.14.12" 67 | convert: 68 | dependency: transitive 69 | description: 70 | name: convert 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "2.1.1" 74 | crypto: 75 | dependency: transitive 76 | description: 77 | name: crypto 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "2.1.4" 81 | cupertino_icons: 82 | dependency: "direct main" 83 | description: 84 | name: cupertino_icons 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "0.1.3" 88 | firebase_auth: 89 | dependency: "direct main" 90 | description: 91 | name: firebase_auth 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "0.8.4+5" 95 | firebase_core: 96 | dependency: transitive 97 | description: 98 | name: firebase_core 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "0.3.4" 102 | firebase_messaging: 103 | dependency: "direct main" 104 | description: 105 | name: firebase_messaging 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "4.0.0+4" 109 | firebase_storage: 110 | dependency: "direct main" 111 | description: 112 | name: firebase_storage 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "2.1.1+2" 116 | flutter: 117 | dependency: "direct main" 118 | description: flutter 119 | source: sdk 120 | version: "0.0.0" 121 | flutter_cache_manager: 122 | dependency: transitive 123 | description: 124 | name: flutter_cache_manager 125 | url: "https://pub.dartlang.org" 126 | source: hosted 127 | version: "1.1.3" 128 | flutter_plugin_android_lifecycle: 129 | dependency: transitive 130 | description: 131 | name: flutter_plugin_android_lifecycle 132 | url: "https://pub.dartlang.org" 133 | source: hosted 134 | version: "1.0.8" 135 | flutter_svg: 136 | dependency: "direct main" 137 | description: 138 | name: flutter_svg 139 | url: "https://pub.dartlang.org" 140 | source: hosted 141 | version: "0.17.4" 142 | flutter_test: 143 | dependency: "direct dev" 144 | description: flutter 145 | source: sdk 146 | version: "0.0.0" 147 | flutter_web_plugins: 148 | dependency: transitive 149 | description: flutter 150 | source: sdk 151 | version: "0.0.0" 152 | geolocator: 153 | dependency: "direct main" 154 | description: 155 | name: geolocator 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "5.0.1" 159 | google_api_availability: 160 | dependency: transitive 161 | description: 162 | name: google_api_availability 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "2.0.4" 166 | google_sign_in: 167 | dependency: "direct main" 168 | description: 169 | name: google_sign_in 170 | url: "https://pub.dartlang.org" 171 | source: hosted 172 | version: "4.5.1" 173 | google_sign_in_platform_interface: 174 | dependency: transitive 175 | description: 176 | name: google_sign_in_platform_interface 177 | url: "https://pub.dartlang.org" 178 | source: hosted 179 | version: "1.1.2" 180 | google_sign_in_web: 181 | dependency: transitive 182 | description: 183 | name: google_sign_in_web 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "0.9.1+1" 187 | http: 188 | dependency: transitive 189 | description: 190 | name: http 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "0.12.1" 194 | http_parser: 195 | dependency: transitive 196 | description: 197 | name: http_parser 198 | url: "https://pub.dartlang.org" 199 | source: hosted 200 | version: "3.1.4" 201 | image: 202 | dependency: "direct main" 203 | description: 204 | name: image 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "2.1.12" 208 | image_picker: 209 | dependency: "direct main" 210 | description: 211 | name: image_picker 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "0.6.7+2" 215 | image_picker_platform_interface: 216 | dependency: transitive 217 | description: 218 | name: image_picker_platform_interface 219 | url: "https://pub.dartlang.org" 220 | source: hosted 221 | version: "1.1.0" 222 | js: 223 | dependency: transitive 224 | description: 225 | name: js 226 | url: "https://pub.dartlang.org" 227 | source: hosted 228 | version: "0.6.2" 229 | location_permissions: 230 | dependency: transitive 231 | description: 232 | name: location_permissions 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "2.0.5" 236 | matcher: 237 | dependency: transitive 238 | description: 239 | name: matcher 240 | url: "https://pub.dartlang.org" 241 | source: hosted 242 | version: "0.12.6" 243 | meta: 244 | dependency: transitive 245 | description: 246 | name: meta 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "1.1.8" 250 | path: 251 | dependency: transitive 252 | description: 253 | name: path 254 | url: "https://pub.dartlang.org" 255 | source: hosted 256 | version: "1.6.4" 257 | path_drawing: 258 | dependency: transitive 259 | description: 260 | name: path_drawing 261 | url: "https://pub.dartlang.org" 262 | source: hosted 263 | version: "0.4.1" 264 | path_parsing: 265 | dependency: transitive 266 | description: 267 | name: path_parsing 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "0.1.4" 271 | path_provider: 272 | dependency: "direct main" 273 | description: 274 | name: path_provider 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "0.5.0+1" 278 | pedantic: 279 | dependency: transitive 280 | description: 281 | name: pedantic 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "1.9.0" 285 | petitparser: 286 | dependency: transitive 287 | description: 288 | name: petitparser 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "2.4.0" 292 | platform: 293 | dependency: transitive 294 | description: 295 | name: platform 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "2.2.1" 299 | plugin_platform_interface: 300 | dependency: transitive 301 | description: 302 | name: plugin_platform_interface 303 | url: "https://pub.dartlang.org" 304 | source: hosted 305 | version: "1.0.2" 306 | quiver: 307 | dependency: transitive 308 | description: 309 | name: quiver 310 | url: "https://pub.dartlang.org" 311 | source: hosted 312 | version: "2.1.3" 313 | sky_engine: 314 | dependency: transitive 315 | description: flutter 316 | source: sdk 317 | version: "0.0.99" 318 | source_span: 319 | dependency: transitive 320 | description: 321 | name: source_span 322 | url: "https://pub.dartlang.org" 323 | source: hosted 324 | version: "1.7.0" 325 | sqflite: 326 | dependency: transitive 327 | description: 328 | name: sqflite 329 | url: "https://pub.dartlang.org" 330 | source: hosted 331 | version: "1.3.1" 332 | sqflite_common: 333 | dependency: transitive 334 | description: 335 | name: sqflite_common 336 | url: "https://pub.dartlang.org" 337 | source: hosted 338 | version: "1.0.1" 339 | stack_trace: 340 | dependency: transitive 341 | description: 342 | name: stack_trace 343 | url: "https://pub.dartlang.org" 344 | source: hosted 345 | version: "1.9.3" 346 | states_rebuilder: 347 | dependency: transitive 348 | description: 349 | name: states_rebuilder 350 | url: "https://pub.dartlang.org" 351 | source: hosted 352 | version: "2.2.0" 353 | stream_channel: 354 | dependency: transitive 355 | description: 356 | name: stream_channel 357 | url: "https://pub.dartlang.org" 358 | source: hosted 359 | version: "2.0.0" 360 | string_scanner: 361 | dependency: transitive 362 | description: 363 | name: string_scanner 364 | url: "https://pub.dartlang.org" 365 | source: hosted 366 | version: "1.0.5" 367 | synchronized: 368 | dependency: transitive 369 | description: 370 | name: synchronized 371 | url: "https://pub.dartlang.org" 372 | source: hosted 373 | version: "2.2.0" 374 | term_glyph: 375 | dependency: transitive 376 | description: 377 | name: term_glyph 378 | url: "https://pub.dartlang.org" 379 | source: hosted 380 | version: "1.1.0" 381 | test_api: 382 | dependency: transitive 383 | description: 384 | name: test_api 385 | url: "https://pub.dartlang.org" 386 | source: hosted 387 | version: "0.2.15" 388 | timeago: 389 | dependency: "direct main" 390 | description: 391 | name: timeago 392 | url: "https://pub.dartlang.org" 393 | source: hosted 394 | version: "2.0.17" 395 | typed_data: 396 | dependency: transitive 397 | description: 398 | name: typed_data 399 | url: "https://pub.dartlang.org" 400 | source: hosted 401 | version: "1.1.6" 402 | uuid: 403 | dependency: "direct main" 404 | description: 405 | name: uuid 406 | url: "https://pub.dartlang.org" 407 | source: hosted 408 | version: "2.1.0" 409 | vector_math: 410 | dependency: transitive 411 | description: 412 | name: vector_math 413 | url: "https://pub.dartlang.org" 414 | source: hosted 415 | version: "2.0.8" 416 | xml: 417 | dependency: transitive 418 | description: 419 | name: xml 420 | url: "https://pub.dartlang.org" 421 | source: hosted 422 | version: "3.6.1" 423 | sdks: 424 | dart: ">=2.7.0 <3.0.0" 425 | flutter: ">=1.12.13+hotfix.6 <2.0.0" 426 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: socialize 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 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 1.0.0+1 15 | 16 | environment: 17 | sdk: ">=2.1.0 <3.0.0" 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | cloud_firestore: ^0.9.7+2 23 | image_picker: ^0.6.0+2 24 | firebase_storage: ^2.1.0+1 25 | firebase_auth: ^0.8.3 26 | google_sign_in: ^4.0.1+1 27 | geolocator: 5.0.1 28 | uuid: ^2.0.0 29 | image: ^2.0.7 30 | animator: ^2.0.1 31 | cupertino_icons: ^0.1.2 32 | path_provider: ^0.5.0+1 33 | firebase_messaging: ^4.0.0+1 34 | timeago: 2.0.17 35 | cached_network_image: 36 | flutter_svg: 37 | 38 | dev_dependencies: 39 | flutter_test: 40 | sdk: flutter 41 | 42 | # For information on the generic Dart part of this file, see the 43 | # following page: https://dart.dev/tools/pub/pubspec 44 | 45 | # The following section is specific to Flutter. 46 | flutter: 47 | uses-material-design: true 48 | fonts: 49 | - family: Signatra 50 | fonts: 51 | - asset: assets/fonts/Signatra.ttf 52 | assets: 53 | - assets/images/google_signin_button.png 54 | - assets/images/upload.svg 55 | - assets/images/search.svg 56 | - assets/images/activity_feed.svg 57 | - assets/images/no_content.svg 58 | -------------------------------------------------------------------------------- /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:socialize/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 | --------------------------------------------------------------------------------