├── .gitignore ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── LogoDesigns ├── black.png ├── logodesigns ├── logotype1black.png ├── logotype1white.png ├── logotype1yellow.png ├── logotype2black.png ├── logotype2white.png ├── logotype2yellow.png ├── white.png └── yellow.png ├── README.md ├── _config.yml ├── android.iml ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── yourcompany │ │ │ └── newsapp │ │ │ └── MainActivity.java │ │ └── res │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ └── mipmap-xxxhdpi │ │ └── ic_launcher.png ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Podfile ├── Podfile.lock ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ └── contents.xcworkspacedata └── Runner │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── 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 │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── main.m ├── lib ├── ArticleSourceScreen.dart ├── BookmarkScreen.dart ├── CategoriesScreen.dart ├── HomeFeedScreen.dart ├── SearchScreen.dart ├── SourceLibraryScreen.dart ├── categoriesList.dart ├── globalStore.dart └── main.dart ├── newsapp.iml ├── newsapp_android.iml ├── pubspec.yaml ├── screenshots └── NewsBuzz.gif └── test └── widget_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .atom/ 3 | .idea 4 | .packages 5 | .pub/ 6 | build/ 7 | ios/.generated/ 8 | packages 9 | pubspec.lock 10 | .flutter-plugins 11 | google-services.json 12 | key.properties 13 | ios/GoogleService-Info.plist 14 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Flutter mobile app", 9 | "type": "flutter", 10 | "request": "launch" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Ankur Kedia 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LogoDesigns/black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/LogoDesigns/black.png -------------------------------------------------------------------------------- /LogoDesigns/logodesigns: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LogoDesigns/logotype1black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/LogoDesigns/logotype1black.png -------------------------------------------------------------------------------- /LogoDesigns/logotype1white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/LogoDesigns/logotype1white.png -------------------------------------------------------------------------------- /LogoDesigns/logotype1yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/LogoDesigns/logotype1yellow.png -------------------------------------------------------------------------------- /LogoDesigns/logotype2black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/LogoDesigns/logotype2black.png -------------------------------------------------------------------------------- /LogoDesigns/logotype2white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/LogoDesigns/logotype2white.png -------------------------------------------------------------------------------- /LogoDesigns/logotype2yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/LogoDesigns/logotype2yellow.png -------------------------------------------------------------------------------- /LogoDesigns/white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/LogoDesigns/white.png -------------------------------------------------------------------------------- /LogoDesigns/yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/LogoDesigns/yellow.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # News Buzz 2 | 3 | News App created in Flutter using News API for fetching realtime data and Firebase as the backend and authenticator. 4 | 5 | ## Features 6 | 7 | * Custom news feed based on selected sources 8 | * Saving articles 9 | * Explore news based on categories 10 | * Search for topics 11 | * Sharing articles 12 | 13 | ## Preview 14 | 15 | ![ios-demo](./screenshots/NewsBuzz.gif) 16 | 17 | ## Dependencies 18 | 19 | * [Flutter](https://flutter.io/) 20 | * [Firebase](https://github.com/flutter/plugins/blob/master/FlutterFire.md) 21 | * [Google Sign In](https://github.com/flutter/plugins/tree/master/packages/google_sign_in) 22 | * [Flutter Webview Plugin](https://github.com/dart-flitter/flutter_webview_plugin) 23 | * [News API](https://newsapi.org/) 24 | 25 | ## Getting Started 26 | 27 | #### 1. [Setup Flutter](https://flutter.io/setup/) 28 | 29 | #### 2. Clone the repo 30 | 31 | ```sh 32 | $ git clone https://github.com/theankurkedia/newsbuzz.git 33 | $ cd newsbuzz/ 34 | ``` 35 | 36 | #### 3. Setup firebase app 37 | 38 | 1. You'll need to create a Firebase instance. Follow the instructions at https://console.firebase.google.com. 39 | 2. Once your Firebase instance is created, you'll need to enable anonymous authentication. 40 | 41 | * Go to the Firebase Console for your new instance. 42 | * Click "Authentication" in the left-hand menu 43 | * Click the "sign-in method" tab 44 | * Click "Google" and enable it 45 | 46 | 3. (skip if not running on Android) 47 | 48 | * Create an app within your Firebase instance for Android, with package name com.yourcompany.news 49 | * Run the following command to get your SHA-1 key: 50 | 51 | ``` 52 | keytool -exportcert -list -v \ 53 | -alias androiddebugkey -keystore ~/.android/debug.keystore 54 | ``` 55 | 56 | * In the Firebase console, in the settings of your Android app, add your SHA-1 key by clicking "Add Fingerprint". 57 | * Follow instructions to download google-services.json 58 | * place `google-services.json` into `newsbuzz/android/app/`. 59 | 60 | 4. (skip if not running on iOS) 61 | 62 | * Create an app within your Firebase instance for iOS, with package name com.yourcompany.news 63 | * Follow instructions to download GoogleService-Info.plist, and place it into newsbuzz/ios/Runner in XCode 64 | * Open newsbuzz/ios/Runner/Info.plist. Locate the CFBundleURLSchemes key. The second item in the array value of this key is specific to the Firebase instance. Replace it with the value for REVERSED_CLIENT_ID from GoogleService-Info.plist 65 | 66 | #### 4. Run the app 67 | 68 | ```sh 69 | $ flutter run 70 | ``` 71 | 72 | ## License 73 | Licensed under the [MIT license](https://opensource.org/licenses/MIT). 74 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | GeneratedPluginRegistrant.java 10 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withInputStream { stream -> 5 | localProperties.load(stream) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | apply plugin: 'com.android.application' 15 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 16 | 17 | android { 18 | compileSdkVersion 25 19 | buildToolsVersion '25.0.3' 20 | 21 | lintOptions { 22 | disable 'InvalidPackage' 23 | } 24 | 25 | defaultConfig { 26 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 27 | applicationId "com.yourcompany.news" 28 | minSdkVersion 16 29 | targetSdkVersion 25 30 | versionCode 1 31 | versionName "1.0" 32 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 33 | } 34 | 35 | buildTypes { 36 | release { 37 | // TODO: Add your own signing config for the release build. 38 | // Signing with the debug keys for now, so `flutter run --release` works. 39 | signingConfig signingConfigs.debug 40 | } 41 | } 42 | } 43 | 44 | flutter { 45 | source '../..' 46 | } 47 | 48 | dependencies { 49 | androidTestCompile 'com.android.support:support-annotations:25.2.0' 50 | androidTestCompile 'com.android.support.test:runner:0.5' 51 | androidTestCompile 'com.android.support.test:rules:0.5' 52 | } 53 | apply plugin: 'com.google.gms.google-services' -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 15 | 16 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/yourcompany/newsapp/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.yourcompany.news; 2 | 3 | import android.os.Bundle; 4 | 5 | import io.flutter.app.FlutterActivity; 6 | import io.flutter.plugins.GeneratedPluginRegistrant; 7 | 8 | public class MainActivity extends FlutterActivity { 9 | @Override 10 | protected void onCreate(Bundle savedInstanceState) { 11 | super.onCreate(savedInstanceState); 12 | GeneratedPluginRegistrant.registerWith(this); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | maven { 5 | url "https://maven.google.com" 6 | } 7 | } 8 | 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:2.3.3' 11 | classpath 'com.google.gms:google-services:3.1.0' 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | maven { 19 | url "https://maven.google.com" 20 | } 21 | } 22 | } 23 | 24 | rootProject.buildDir = '../build' 25 | subprojects { 26 | project.buildDir = "${rootProject.buildDir}/${project.name}" 27 | project.evaluationDependsOn(':app') 28 | } 29 | 30 | task clean(type: Delete) { 31 | delete rootProject.buildDir 32 | } 33 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /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-3.3-all.zip 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withInputStream { stream -> plugins.load(stream) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | *.pbxuser 16 | *.mode1v3 17 | *.mode2v3 18 | *.perspectivev3 19 | 20 | !default.pbxuser 21 | !default.mode1v3 22 | !default.mode2v3 23 | !default.perspectivev3 24 | 25 | xcuserdata 26 | 27 | *.moved-aside 28 | 29 | *.pyc 30 | *sync/ 31 | Icon? 32 | .tags* 33 | 34 | /Flutter/app.flx 35 | /Flutter/app.zip 36 | /Flutter/App.framework 37 | /Flutter/Flutter.framework 38 | /Flutter/Generated.xcconfig 39 | /ServiceDefinitions.json 40 | 41 | Pods/ 42 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | UIRequiredDeviceCapabilities 24 | 25 | arm64 26 | 27 | MinimumOSVersion 28 | 8.0 29 | 30 | 31 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | if ENV['FLUTTER_FRAMEWORK_DIR'] == nil 5 | abort('Please set FLUTTER_FRAMEWORK_DIR to the directory containing Flutter.framework') 6 | end 7 | 8 | target 'Runner' do 9 | # Pods for Runner 10 | 11 | # Flutter Pods 12 | pod 'Flutter', :path => ENV['FLUTTER_FRAMEWORK_DIR'] 13 | 14 | if File.exists? '../.flutter-plugins' 15 | flutter_root = File.expand_path('..') 16 | File.foreach('../.flutter-plugins') { |line| 17 | plugin = line.split(pattern='=') 18 | if plugin.length == 2 19 | name = plugin[0].strip() 20 | path = plugin[1].strip() 21 | resolved_path = File.expand_path("#{path}/ios", flutter_root) 22 | pod name, :path => resolved_path 23 | else 24 | puts "Invalid plugin specification: #{line}" 25 | end 26 | } 27 | end 28 | end 29 | 30 | post_install do |installer| 31 | installer.pods_project.targets.each do |target| 32 | target.build_configurations.each do |config| 33 | config.build_settings['ENABLE_BITCODE'] = 'NO' 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Firebase/Auth (3.17.0): 3 | - Firebase/Core 4 | - FirebaseAuth (= 3.1.1) 5 | - Firebase/Core (3.17.0): 6 | - FirebaseAnalytics (= 3.9.0) 7 | - FirebaseCore (= 3.6.0) 8 | - Firebase/Database (3.17.0): 9 | - Firebase/Core 10 | - FirebaseDatabase (= 3.1.2) 11 | - Firebase/Storage (3.17.0): 12 | - Firebase/Core 13 | - FirebaseStorage (= 1.1.0) 14 | - firebase_analytics (0.0.1): 15 | - Firebase/Core 16 | - Flutter 17 | - firebase_auth (0.0.1): 18 | - Firebase/Auth 19 | - Firebase/Core 20 | - FirebaseUI/Auth (~> 3.0) 21 | - FirebaseUI/Google 22 | - Flutter 23 | - Google/SignIn 24 | - firebase_database (0.0.1): 25 | - Firebase/Database 26 | - Flutter 27 | - firebase_storage (0.0.1): 28 | - Firebase/Storage 29 | - Flutter 30 | - FirebaseAnalytics (3.9.0): 31 | - FirebaseCore (~> 3.6) 32 | - FirebaseInstanceID (~> 1.0) 33 | - GoogleToolboxForMac/NSData+zlib (~> 2.1) 34 | - FirebaseAuth (3.1.1): 35 | - FirebaseAnalytics (~> 3.7) 36 | - GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1) 37 | - GTMSessionFetcher/Core (~> 1.1) 38 | - FirebaseCore (3.6.0): 39 | - GoogleToolboxForMac/NSData+zlib (~> 2.1) 40 | - FirebaseDatabase (3.1.2): 41 | - FirebaseAnalytics (~> 3.7) 42 | - FirebaseInstanceID (1.0.10): 43 | - FirebaseCore (~> 3.6) 44 | - FirebaseStorage (1.1.0): 45 | - FirebaseAnalytics (~> 3.7) 46 | - GTMSessionFetcher/Core (~> 1.1) 47 | - FirebaseUI/Auth (3.1.1): 48 | - Firebase/Auth 49 | - FirebaseUI/Google (3.1.1): 50 | - FirebaseUI/Auth 51 | - GoogleSignIn (~> 4.0) 52 | - Flutter (1.0.0) 53 | - flutter_webview_plugin (0.0.1): 54 | - Flutter 55 | - Google/Core (3.1.0): 56 | - FirebaseAnalytics (~> 3.2) 57 | - Google/SignIn (3.1.0): 58 | - Google/Core 59 | - GoogleSignIn (~> 4.0) 60 | - google_sign_in (0.0.1): 61 | - Flutter 62 | - GoogleSignIn (~> 4.0) 63 | - GoogleSignIn (4.1.1): 64 | - GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1) 65 | - GoogleToolboxForMac/NSString+URLArguments (~> 2.1) 66 | - GTMOAuth2 (~> 1.0) 67 | - GTMSessionFetcher/Core (~> 1.1) 68 | - GoogleToolboxForMac/DebugUtils (2.1.1): 69 | - GoogleToolboxForMac/Defines (= 2.1.1) 70 | - GoogleToolboxForMac/Defines (2.1.1) 71 | - GoogleToolboxForMac/NSData+zlib (2.1.1): 72 | - GoogleToolboxForMac/Defines (= 2.1.1) 73 | - GoogleToolboxForMac/NSDictionary+URLArguments (2.1.1): 74 | - GoogleToolboxForMac/DebugUtils (= 2.1.1) 75 | - GoogleToolboxForMac/Defines (= 2.1.1) 76 | - GoogleToolboxForMac/NSString+URLArguments (= 2.1.1) 77 | - GoogleToolboxForMac/NSString+URLArguments (2.1.1) 78 | - GTMOAuth2 (1.1.6): 79 | - GTMSessionFetcher (~> 1.1) 80 | - GTMSessionFetcher (1.1.11): 81 | - GTMSessionFetcher/Full (= 1.1.11) 82 | - GTMSessionFetcher/Core (1.1.11) 83 | - GTMSessionFetcher/Full (1.1.11): 84 | - GTMSessionFetcher/Core (= 1.1.11) 85 | - share (0.0.1): 86 | - Flutter 87 | 88 | DEPENDENCIES: 89 | - firebase_analytics (from `/Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/firebase_analytics-0.0.4/ios`) 90 | - firebase_auth (from `/Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/firebase_auth-0.2.0/ios`) 91 | - firebase_database (from `/Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/firebase_database-0.0.12/ios`) 92 | - firebase_storage (from `/Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/firebase_storage-0.0.5/ios`) 93 | - Flutter (from `/Users/ankurkedia/flutter/bin/cache/artifacts/engine/ios`) 94 | - flutter_webview_plugin (from `/Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/flutter_webview_plugin-0.0.9+1/ios`) 95 | - google_sign_in (from `/Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/google_sign_in-0.3.1/ios`) 96 | - share (from `/Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/share-0.2.2/ios`) 97 | 98 | EXTERNAL SOURCES: 99 | firebase_analytics: 100 | :path: /Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/firebase_analytics-0.0.4/ios 101 | firebase_auth: 102 | :path: /Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/firebase_auth-0.2.0/ios 103 | firebase_database: 104 | :path: /Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/firebase_database-0.0.12/ios 105 | firebase_storage: 106 | :path: /Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/firebase_storage-0.0.5/ios 107 | Flutter: 108 | :path: /Users/ankurkedia/flutter/bin/cache/artifacts/engine/ios 109 | flutter_webview_plugin: 110 | :path: /Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/flutter_webview_plugin-0.0.9+1/ios 111 | google_sign_in: 112 | :path: /Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/google_sign_in-0.3.1/ios 113 | share: 114 | :path: /Users/ankurkedia/.pub-cache/hosted/pub.dartlang.org/share-0.2.2/ios 115 | 116 | SPEC CHECKSUMS: 117 | Firebase: 4b66b5b59c43edac745b87f0c87e42cdd0279c13 118 | firebase_analytics: e14732ea6575c050175fa09e07358db87842dbe3 119 | firebase_auth: bc8727f162f8af67ae665f9c533ef546a8f789de 120 | firebase_database: 8d50f5c188b769afc186b0a700b2c6cdb8208df9 121 | firebase_storage: eb8091489a1cfb657eeefc933bb1ccfab23195a3 122 | FirebaseAnalytics: e5fe8486efc01bec33f6bf82e2fa9fce4b124052 123 | FirebaseAuth: cc8a1824170adbd351edb7f994490a3fb5c18be6 124 | FirebaseCore: 9691ee2ade70c098d7cf92440f4303f16d83ca75 125 | FirebaseDatabase: 05c96d7b43a7368dc91c07791adb49683e1738d1 126 | FirebaseInstanceID: b9eedd6846fb5e1f0f7279e1deaa7a7e4cf8392e 127 | FirebaseStorage: a5c55b23741a49a72af8f30f95b3bb5ddbeda12d 128 | FirebaseUI: 6e99ff95e369f5858232e4f65bff215458fe8469 129 | Flutter: d674e78c937094a75ac71dd77e921e840bea3dbf 130 | flutter_webview_plugin: ed9e8a6a96baf0c867e90e1bce2673913eeac694 131 | Google: 98da4b1a60ed0beb80a290387a28333406a1eb90 132 | google_sign_in: 24ea34feed2d7d04e957cd1c4daf063c488532c2 133 | GoogleSignIn: 3fdaa34a2ba04dbd7a25d7db39aecb0da98d5bdc 134 | GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0 135 | GTMOAuth2: c77fe325e4acd453837e72d91e3b5f13116857b2 136 | GTMSessionFetcher: 5ad62e8200fa00ed011fe5e08d27fef72c5b1429 137 | share: ee3d34d3969ad17fc3043eab552e4f082aacfed1 138 | 139 | PODFILE CHECKSUM: 351e02e34b831289961ec3558a535cbd2c4965d2 140 | 141 | COCOAPODS: 1.3.1 142 | -------------------------------------------------------------------------------- /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 | 6DE04636A09C9660F01BC4E8 /* libPods-Runner.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2E941454489C1651DB950C69 /* libPods-Runner.a */; }; 15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 17 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 18 | 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB31CF90195004384FC /* Generated.xcconfig */; }; 19 | 9740EEBB1CF902C7004384FC /* app.flx in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB71CF902C7004384FC /* app.flx */; }; 20 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 21 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 22 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 23 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 24 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXCopyFilesBuildPhase section */ 28 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 29 | isa = PBXCopyFilesBuildPhase; 30 | buildActionMask = 2147483647; 31 | dstPath = ""; 32 | dstSubfolderSpec = 10; 33 | files = ( 34 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 35 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 36 | ); 37 | name = "Embed Frameworks"; 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXCopyFilesBuildPhase section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 44 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 45 | 2E941454489C1651DB950C69 /* 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 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 49 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 50 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 51 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 52 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 53 | 9740EEB71CF902C7004384FC /* app.flx */ = {isa = PBXFileReference; lastKnownFileType = file; name = app.flx; path = Flutter/app.flx; sourceTree = ""; }; 54 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 55 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 57 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 58 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 59 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 60 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | /* End PBXFileReference section */ 62 | 63 | /* Begin PBXFrameworksBuildPhase section */ 64 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 69 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 70 | 6DE04636A09C9660F01BC4E8 /* libPods-Runner.a in Frameworks */, 71 | ); 72 | runOnlyForDeploymentPostprocessing = 0; 73 | }; 74 | /* End PBXFrameworksBuildPhase section */ 75 | 76 | /* Begin PBXGroup section */ 77 | 9740EEB11CF90186004384FC /* Flutter */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | 9740EEB71CF902C7004384FC /* app.flx */, 81 | 3B80C3931E831B6300D905FE /* App.framework */, 82 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 83 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 84 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 85 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 86 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 87 | ); 88 | name = Flutter; 89 | sourceTree = ""; 90 | }; 91 | 97C146E51CF9000F007C117D = { 92 | isa = PBXGroup; 93 | children = ( 94 | 9740EEB11CF90186004384FC /* Flutter */, 95 | 97C146F01CF9000F007C117D /* Runner */, 96 | 97C146EF1CF9000F007C117D /* Products */, 97 | 9F7C7FC5CBFB8F7AFA3D3F77 /* Pods */, 98 | CB9A9DD0989BCD6BB5BA1F25 /* Frameworks */, 99 | ); 100 | sourceTree = ""; 101 | }; 102 | 97C146EF1CF9000F007C117D /* Products */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 97C146EE1CF9000F007C117D /* Runner.app */, 106 | ); 107 | name = Products; 108 | sourceTree = ""; 109 | }; 110 | 97C146F01CF9000F007C117D /* Runner */ = { 111 | isa = PBXGroup; 112 | children = ( 113 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 114 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 115 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 116 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 117 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 118 | 97C147021CF9000F007C117D /* Info.plist */, 119 | 97C146F11CF9000F007C117D /* Supporting Files */, 120 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 121 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 122 | ); 123 | path = Runner; 124 | sourceTree = ""; 125 | }; 126 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 97C146F21CF9000F007C117D /* main.m */, 130 | ); 131 | name = "Supporting Files"; 132 | sourceTree = ""; 133 | }; 134 | 9F7C7FC5CBFB8F7AFA3D3F77 /* Pods */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | ); 138 | name = Pods; 139 | sourceTree = ""; 140 | }; 141 | CB9A9DD0989BCD6BB5BA1F25 /* Frameworks */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 2E941454489C1651DB950C69 /* libPods-Runner.a */, 145 | ); 146 | name = Frameworks; 147 | sourceTree = ""; 148 | }; 149 | /* End PBXGroup section */ 150 | 151 | /* Begin PBXNativeTarget section */ 152 | 97C146ED1CF9000F007C117D /* Runner */ = { 153 | isa = PBXNativeTarget; 154 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 155 | buildPhases = ( 156 | 66F81E6C053A593963D5E1FB /* [CP] Check Pods Manifest.lock */, 157 | 9740EEB61CF901F6004384FC /* Run Script */, 158 | 97C146EA1CF9000F007C117D /* Sources */, 159 | 97C146EB1CF9000F007C117D /* Frameworks */, 160 | 97C146EC1CF9000F007C117D /* Resources */, 161 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 162 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 163 | 6710D27E27414EF4A6954B20 /* [CP] Embed Pods Frameworks */, 164 | FBAA1F6C4DA11D719EC85141 /* [CP] Copy Pods Resources */, 165 | ); 166 | buildRules = ( 167 | ); 168 | dependencies = ( 169 | ); 170 | name = Runner; 171 | productName = Runner; 172 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 173 | productType = "com.apple.product-type.application"; 174 | }; 175 | /* End PBXNativeTarget section */ 176 | 177 | /* Begin PBXProject section */ 178 | 97C146E61CF9000F007C117D /* Project object */ = { 179 | isa = PBXProject; 180 | attributes = { 181 | LastUpgradeCheck = 0830; 182 | ORGANIZATIONNAME = "The Chromium Authors"; 183 | TargetAttributes = { 184 | 97C146ED1CF9000F007C117D = { 185 | CreatedOnToolsVersion = 7.3.1; 186 | ProvisioningStyle = Manual; 187 | }; 188 | }; 189 | }; 190 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 191 | compatibilityVersion = "Xcode 3.2"; 192 | developmentRegion = English; 193 | hasScannedForEncodings = 0; 194 | knownRegions = ( 195 | en, 196 | Base, 197 | ); 198 | mainGroup = 97C146E51CF9000F007C117D; 199 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 200 | projectDirPath = ""; 201 | projectRoot = ""; 202 | targets = ( 203 | 97C146ED1CF9000F007C117D /* Runner */, 204 | ); 205 | }; 206 | /* End PBXProject section */ 207 | 208 | /* Begin PBXResourcesBuildPhase section */ 209 | 97C146EC1CF9000F007C117D /* Resources */ = { 210 | isa = PBXResourcesBuildPhase; 211 | buildActionMask = 2147483647; 212 | files = ( 213 | 9740EEBB1CF902C7004384FC /* app.flx in Resources */, 214 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 215 | 9740EEB51CF90195004384FC /* Generated.xcconfig in Resources */, 216 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 217 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 218 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 219 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 220 | ); 221 | runOnlyForDeploymentPostprocessing = 0; 222 | }; 223 | /* End PBXResourcesBuildPhase section */ 224 | 225 | /* Begin PBXShellScriptBuildPhase section */ 226 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 227 | isa = PBXShellScriptBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | ); 231 | inputPaths = ( 232 | ); 233 | name = "Thin Binary"; 234 | outputPaths = ( 235 | ); 236 | runOnlyForDeploymentPostprocessing = 0; 237 | shellPath = /bin/sh; 238 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 239 | }; 240 | 66F81E6C053A593963D5E1FB /* [CP] Check Pods Manifest.lock */ = { 241 | isa = PBXShellScriptBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | ); 245 | inputPaths = ( 246 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 247 | "${PODS_ROOT}/Manifest.lock", 248 | ); 249 | name = "[CP] Check Pods Manifest.lock"; 250 | outputPaths = ( 251 | "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | shellPath = /bin/sh; 255 | 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"; 256 | showEnvVarsInLog = 0; 257 | }; 258 | 6710D27E27414EF4A6954B20 /* [CP] Embed Pods Frameworks */ = { 259 | isa = PBXShellScriptBuildPhase; 260 | buildActionMask = 2147483647; 261 | files = ( 262 | ); 263 | inputPaths = ( 264 | "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", 265 | "${PODS_ROOT}/../../../../../flutter/bin/cache/artifacts/engine/ios/Flutter.framework", 266 | ); 267 | name = "[CP] Embed Pods Frameworks"; 268 | outputPaths = ( 269 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework", 270 | ); 271 | runOnlyForDeploymentPostprocessing = 0; 272 | shellPath = /bin/sh; 273 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; 274 | showEnvVarsInLog = 0; 275 | }; 276 | 9740EEB61CF901F6004384FC /* Run Script */ = { 277 | isa = PBXShellScriptBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | ); 281 | inputPaths = ( 282 | ); 283 | name = "Run Script"; 284 | outputPaths = ( 285 | ); 286 | runOnlyForDeploymentPostprocessing = 0; 287 | shellPath = /bin/sh; 288 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 289 | }; 290 | FBAA1F6C4DA11D719EC85141 /* [CP] Copy Pods Resources */ = { 291 | isa = PBXShellScriptBuildPhase; 292 | buildActionMask = 2147483647; 293 | files = ( 294 | ); 295 | inputPaths = ( 296 | "${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", 297 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/FUIAuthPickerViewController.nib", 298 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/FUIAuthTableViewCell.nib", 299 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/FUIEmailEntryViewController.nib", 300 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/FUIPasswordRecoveryViewController.nib", 301 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/FUIPasswordSignInViewController.nib", 302 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/FUIPasswordSignUpViewController.nib", 303 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/FUIPasswordVerificationViewController.nib", 304 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/ic_email.png", 305 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/ic_email@2x.png", 306 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/ic_email@3x.png", 307 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/ic_visibility.png", 308 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/ic_visibility@2x.png", 309 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/ic_visibility@3x.png", 310 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/ic_visibility_off.png", 311 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/ic_visibility_off@2x.png", 312 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/ic_visibility_off@3x.png", 313 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseAuthUI/Frameworks/FirebaseAuthUI.framework/en.lproj", 314 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseGoogleAuthUI/Frameworks/FirebaseGoogleAuthUI.framework/ic_google.png", 315 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseGoogleAuthUI/Frameworks/FirebaseGoogleAuthUI.framework/ic_google@2x.png", 316 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseGoogleAuthUI/Frameworks/FirebaseGoogleAuthUI.framework/ic_google@3x.png", 317 | "${PODS_ROOT}/FirebaseUI/FirebaseUIFrameworks/FirebaseGoogleAuthUI/Frameworks/FirebaseGoogleAuthUI.framework/en.lproj", 318 | "${PODS_ROOT}/GTMOAuth2/Source/Touch/GTMOAuth2ViewTouch.xib", 319 | "${PODS_ROOT}/GoogleSignIn/Resources/GoogleSignIn.bundle", 320 | ); 321 | name = "[CP] Copy Pods Resources"; 322 | outputPaths = ( 323 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}", 324 | ); 325 | runOnlyForDeploymentPostprocessing = 0; 326 | shellPath = /bin/sh; 327 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; 328 | showEnvVarsInLog = 0; 329 | }; 330 | /* End PBXShellScriptBuildPhase section */ 331 | 332 | /* Begin PBXSourcesBuildPhase section */ 333 | 97C146EA1CF9000F007C117D /* Sources */ = { 334 | isa = PBXSourcesBuildPhase; 335 | buildActionMask = 2147483647; 336 | files = ( 337 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 338 | 97C146F31CF9000F007C117D /* main.m in Sources */, 339 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 340 | ); 341 | runOnlyForDeploymentPostprocessing = 0; 342 | }; 343 | /* End PBXSourcesBuildPhase section */ 344 | 345 | /* Begin PBXVariantGroup section */ 346 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 347 | isa = PBXVariantGroup; 348 | children = ( 349 | 97C146FB1CF9000F007C117D /* Base */, 350 | ); 351 | name = Main.storyboard; 352 | sourceTree = ""; 353 | }; 354 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 355 | isa = PBXVariantGroup; 356 | children = ( 357 | 97C147001CF9000F007C117D /* Base */, 358 | ); 359 | name = LaunchScreen.storyboard; 360 | sourceTree = ""; 361 | }; 362 | /* End PBXVariantGroup section */ 363 | 364 | /* Begin XCBuildConfiguration section */ 365 | 97C147031CF9000F007C117D /* Debug */ = { 366 | isa = XCBuildConfiguration; 367 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 368 | buildSettings = { 369 | ALWAYS_SEARCH_USER_PATHS = NO; 370 | CLANG_ANALYZER_NONNULL = YES; 371 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 372 | CLANG_CXX_LIBRARY = "libc++"; 373 | CLANG_ENABLE_MODULES = YES; 374 | CLANG_ENABLE_OBJC_ARC = YES; 375 | CLANG_WARN_BOOL_CONVERSION = YES; 376 | CLANG_WARN_CONSTANT_CONVERSION = YES; 377 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 378 | CLANG_WARN_EMPTY_BODY = YES; 379 | CLANG_WARN_ENUM_CONVERSION = YES; 380 | CLANG_WARN_INFINITE_RECURSION = YES; 381 | CLANG_WARN_INT_CONVERSION = YES; 382 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 383 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 384 | CLANG_WARN_UNREACHABLE_CODE = YES; 385 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 386 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 387 | COPY_PHASE_STRIP = NO; 388 | DEBUG_INFORMATION_FORMAT = dwarf; 389 | ENABLE_STRICT_OBJC_MSGSEND = YES; 390 | ENABLE_TESTABILITY = YES; 391 | GCC_C_LANGUAGE_STANDARD = gnu99; 392 | GCC_DYNAMIC_NO_PIC = NO; 393 | GCC_NO_COMMON_BLOCKS = YES; 394 | GCC_OPTIMIZATION_LEVEL = 0; 395 | GCC_PREPROCESSOR_DEFINITIONS = ( 396 | "DEBUG=1", 397 | "$(inherited)", 398 | ); 399 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 400 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 401 | GCC_WARN_UNDECLARED_SELECTOR = YES; 402 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 403 | GCC_WARN_UNUSED_FUNCTION = YES; 404 | GCC_WARN_UNUSED_VARIABLE = YES; 405 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 406 | MTL_ENABLE_DEBUG_INFO = YES; 407 | ONLY_ACTIVE_ARCH = YES; 408 | SDKROOT = iphoneos; 409 | TARGETED_DEVICE_FAMILY = "1,2"; 410 | }; 411 | name = Debug; 412 | }; 413 | 97C147041CF9000F007C117D /* Release */ = { 414 | isa = XCBuildConfiguration; 415 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 416 | buildSettings = { 417 | ALWAYS_SEARCH_USER_PATHS = NO; 418 | CLANG_ANALYZER_NONNULL = YES; 419 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 420 | CLANG_CXX_LIBRARY = "libc++"; 421 | CLANG_ENABLE_MODULES = YES; 422 | CLANG_ENABLE_OBJC_ARC = YES; 423 | CLANG_WARN_BOOL_CONVERSION = YES; 424 | CLANG_WARN_CONSTANT_CONVERSION = YES; 425 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 426 | CLANG_WARN_EMPTY_BODY = YES; 427 | CLANG_WARN_ENUM_CONVERSION = YES; 428 | CLANG_WARN_INFINITE_RECURSION = YES; 429 | CLANG_WARN_INT_CONVERSION = YES; 430 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 431 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 432 | CLANG_WARN_UNREACHABLE_CODE = YES; 433 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 434 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 435 | COPY_PHASE_STRIP = NO; 436 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 437 | ENABLE_NS_ASSERTIONS = NO; 438 | ENABLE_STRICT_OBJC_MSGSEND = YES; 439 | GCC_C_LANGUAGE_STANDARD = gnu99; 440 | GCC_NO_COMMON_BLOCKS = YES; 441 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 442 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 443 | GCC_WARN_UNDECLARED_SELECTOR = YES; 444 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 445 | GCC_WARN_UNUSED_FUNCTION = YES; 446 | GCC_WARN_UNUSED_VARIABLE = YES; 447 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 448 | MTL_ENABLE_DEBUG_INFO = NO; 449 | SDKROOT = iphoneos; 450 | TARGETED_DEVICE_FAMILY = "1,2"; 451 | VALIDATE_PRODUCT = YES; 452 | }; 453 | name = Release; 454 | }; 455 | 97C147061CF9000F007C117D /* Debug */ = { 456 | isa = XCBuildConfiguration; 457 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 458 | buildSettings = { 459 | ARCHS = arm64; 460 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 461 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 462 | CODE_SIGN_STYLE = Manual; 463 | DEVELOPMENT_TEAM = ""; 464 | ENABLE_BITCODE = NO; 465 | FRAMEWORK_SEARCH_PATHS = ( 466 | "$(inherited)", 467 | "$(PROJECT_DIR)/Flutter", 468 | ); 469 | INFOPLIST_FILE = Runner/Info.plist; 470 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 471 | LIBRARY_SEARCH_PATHS = ( 472 | "$(inherited)", 473 | "$(PROJECT_DIR)/Flutter", 474 | ); 475 | PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.news; 476 | PRODUCT_NAME = "$(TARGET_NAME)"; 477 | PROVISIONING_PROFILE_SPECIFIER = ""; 478 | }; 479 | name = Debug; 480 | }; 481 | 97C147071CF9000F007C117D /* Release */ = { 482 | isa = XCBuildConfiguration; 483 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 484 | buildSettings = { 485 | ARCHS = arm64; 486 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 487 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 488 | CODE_SIGN_STYLE = Manual; 489 | DEVELOPMENT_TEAM = ""; 490 | ENABLE_BITCODE = NO; 491 | FRAMEWORK_SEARCH_PATHS = ( 492 | "$(inherited)", 493 | "$(PROJECT_DIR)/Flutter", 494 | ); 495 | INFOPLIST_FILE = Runner/Info.plist; 496 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 497 | LIBRARY_SEARCH_PATHS = ( 498 | "$(inherited)", 499 | "$(PROJECT_DIR)/Flutter", 500 | ); 501 | PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.news; 502 | PRODUCT_NAME = "$(TARGET_NAME)"; 503 | PROVISIONING_PROFILE_SPECIFIER = ""; 504 | }; 505 | name = Release; 506 | }; 507 | /* End XCBuildConfiguration section */ 508 | 509 | /* Begin XCConfigurationList section */ 510 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 511 | isa = XCConfigurationList; 512 | buildConfigurations = ( 513 | 97C147031CF9000F007C117D /* Debug */, 514 | 97C147041CF9000F007C117D /* Release */, 515 | ); 516 | defaultConfigurationIsVisible = 0; 517 | defaultConfigurationName = Release; 518 | }; 519 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 520 | isa = XCConfigurationList; 521 | buildConfigurations = ( 522 | 97C147061CF9000F007C117D /* Debug */, 523 | 97C147071CF9000F007C117D /* Release */, 524 | ); 525 | defaultConfigurationIsVisible = 0; 526 | defaultConfigurationName = Release; 527 | }; 528 | /* End XCConfigurationList section */ 529 | }; 530 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 531 | } 532 | -------------------------------------------------------------------------------- /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/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 didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 7 | [GeneratedPluginRegistrant registerWithRegistry:self]; 8 | // Override point for customization after application launch. 9 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 10 | } 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /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 | "idiom" : "ios-marketing", 113 | "size" : "1024x1024", 114 | "scale" : "1x" 115 | } 116 | ], 117 | "info" : { 118 | "version" : 1, 119 | "author" : "xcode" 120 | } 121 | } -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/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/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.yourcompany.news 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | newsapp 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleURLTypes 22 | 23 | 24 | CFBundleTypeRole 25 | Editor 26 | CFBundleURLSchemes 27 | 28 | 29 | com.yourcompany.news 30 | 31 | 32 | 33 | CFBundleVersion 34 | 1 35 | LSRequiresIPhoneOS 36 | 37 | UILaunchStoryboardName 38 | LaunchScreen 39 | UIMainStoryboardFile 40 | Main 41 | UIRequiredDeviceCapabilities 42 | 43 | arm64 44 | 45 | UISupportedInterfaceOrientations 46 | 47 | UIInterfaceOrientationPortrait 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | UISupportedInterfaceOrientations~ipad 52 | 53 | UIInterfaceOrientationPortrait 54 | UIInterfaceOrientationPortraitUpsideDown 55 | UIInterfaceOrientationLandscapeLeft 56 | UIInterfaceOrientationLandscapeRight 57 | 58 | UIViewControllerBasedStatusBarAppearance 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /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/ArticleSourceScreen.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:async'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:firebase_auth/firebase_auth.dart'; 6 | import 'package:http/http.dart' as http; 7 | import 'package:share/share.dart'; 8 | import 'package:firebase_database/firebase_database.dart'; 9 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; 10 | import 'package:timeago/timeago.dart'; 11 | import './globalStore.dart' as globalStore; 12 | 13 | class ArticleSourceScreen extends StatefulWidget { 14 | ArticleSourceScreen( 15 | {Key key, 16 | this.sourceId = "techcrunch", 17 | this.sourceName = "TechCrunch", 18 | this.isCategory: false}) 19 | : super(key: key); 20 | final sourceId; 21 | final sourceName; 22 | final isCategory; 23 | @override 24 | _ArticleSourceScreenState createState() => new _ArticleSourceScreenState( 25 | sourceId: this.sourceId, 26 | sourceName: this.sourceName, 27 | isCategory: this.isCategory); 28 | } 29 | 30 | class _ArticleSourceScreenState extends State { 31 | _ArticleSourceScreenState({this.sourceId, this.sourceName, this.isCategory}); 32 | var data; 33 | final sourceId; 34 | final sourceName; 35 | final isCategory; 36 | bool change = false; 37 | DataSnapshot snapshot; 38 | final FlutterWebviewPlugin flutterWebviewPlugin = new FlutterWebviewPlugin(); 39 | final auth = FirebaseAuth.instance; 40 | final databaseReference = FirebaseDatabase.instance.reference(); 41 | var userDatabaseReference; 42 | var articleDatabaseReference; 43 | 44 | Future getData() async { 45 | var response; 46 | 47 | if (isCategory) { 48 | response = await http.get( 49 | Uri.encodeFull('https://newsapi.org/v2/top-headlines?category=' + 50 | sourceId + 51 | '&language=en'), 52 | headers: { 53 | "Accept": "application/json", 54 | "X-Api-Key": "ab31ce4a49814a27bbb16dd5c5c06608" 55 | }); 56 | } else { 57 | response = await http.get( 58 | Uri.encodeFull( 59 | 'https://newsapi.org/v2/top-headlines?sources=' + sourceId), 60 | headers: { 61 | "Accept": "application/json", 62 | "X-Api-Key": "ab31ce4a49814a27bbb16dd5c5c06608" 63 | }); 64 | } 65 | userDatabaseReference = databaseReference.child(globalStore.user.id); 66 | articleDatabaseReference = userDatabaseReference.child('articles'); 67 | var snap = await articleDatabaseReference.once(); 68 | if (mounted) { 69 | this.setState(() { 70 | data = JSON.decode(response.body); 71 | snapshot = snap; 72 | }); 73 | } 74 | 75 | return "Success!"; 76 | } 77 | 78 | _hasArticle(article) { 79 | if (snapshot.value != null) { 80 | var value = snapshot.value; 81 | int flag = 0; 82 | if (value != null) { 83 | value.forEach((k, v) { 84 | if (v['url'].compareTo(article['url']) == 0) flag = 1; 85 | return; 86 | }); 87 | if (flag == 1) return true; 88 | } 89 | } 90 | return false; 91 | } 92 | 93 | pushArticle(article) { 94 | articleDatabaseReference.push().set({ 95 | 'source': article["source"]["name"], 96 | 'description': article['description'], 97 | 'publishedAt': article['publishedAt'], 98 | 'title': article['title'], 99 | 'url': article['url'], 100 | 'urlToImage': article['urlToImage'], 101 | }); 102 | } 103 | 104 | _onBookmarkTap(article) { 105 | if (snapshot.value != null) { 106 | var value = snapshot.value; 107 | int flag = 0; 108 | value.forEach((k, v) { 109 | if (v['url'].compareTo(article['url']) == 0) { 110 | flag = 1; 111 | articleDatabaseReference.child(k).remove(); 112 | Scaffold.of(context).showSnackBar(new SnackBar( 113 | content: new Text('Article removed'), 114 | backgroundColor: Colors.grey[600], 115 | )); 116 | } 117 | }); 118 | if (flag != 1) { 119 | pushArticle(article); 120 | Scaffold.of(context).showSnackBar(new SnackBar( 121 | content: new Text('Article added'), 122 | backgroundColor: Colors.grey[600], 123 | )); 124 | } 125 | this.setState(() { 126 | change = true; 127 | }); 128 | } else { 129 | pushArticle(article); 130 | } 131 | } 132 | 133 | void initState() { 134 | super.initState(); 135 | this.getData(); 136 | } 137 | 138 | Column buildButtonColumn(IconData icon) { 139 | Color color = Theme.of(context).primaryColor; 140 | return new Column( 141 | mainAxisSize: MainAxisSize.min, 142 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 143 | children: [ 144 | new Icon(icon, color: color), 145 | ], 146 | ); 147 | } 148 | 149 | @override 150 | Widget build(BuildContext context) { 151 | return new Scaffold( 152 | appBar: new AppBar( 153 | title: new Text(sourceName), 154 | centerTitle: true, 155 | ), 156 | backgroundColor: Colors.grey[200], 157 | body: data == null 158 | ? const Center(child: const CircularProgressIndicator()) 159 | : data["articles"].length != 0 160 | ? new ListView.builder( 161 | itemCount: data == null ? 0 : data["articles"].length, 162 | padding: new EdgeInsets.all(8.0), 163 | itemBuilder: (BuildContext context, int index) { 164 | return new GestureDetector( 165 | child: new Card( 166 | elevation: 1.7, 167 | child: new Padding( 168 | padding: new EdgeInsets.all(10.0), 169 | child: new Column( 170 | children: [ 171 | new Row( 172 | children: [ 173 | new Padding( 174 | padding: new EdgeInsets.only(left: 4.0), 175 | child: new Text( 176 | timeAgo(DateTime.parse(data["articles"] 177 | [index]["publishedAt"])), 178 | style: new TextStyle( 179 | fontWeight: FontWeight.w400, 180 | color: Colors.grey[600], 181 | ), 182 | ), 183 | ), 184 | new Padding( 185 | padding: new EdgeInsets.all(5.0), 186 | child: new Text( 187 | data["articles"][index]["source"]["name"], 188 | style: new TextStyle( 189 | fontWeight: FontWeight.w500, 190 | color: Colors.grey[700], 191 | ), 192 | ), 193 | ), 194 | ], 195 | ), 196 | new Row( 197 | children: [ 198 | new Expanded( 199 | child: new GestureDetector( 200 | child: new Column( 201 | crossAxisAlignment: 202 | CrossAxisAlignment.start, 203 | children: [ 204 | new Padding( 205 | padding: new EdgeInsets.only( 206 | left: 4.0, 207 | right: 8.0, 208 | bottom: 8.0, 209 | top: 8.0), 210 | child: new Text( 211 | data["articles"][index]["title"], 212 | style: new TextStyle( 213 | fontWeight: FontWeight.bold, 214 | ), 215 | ), 216 | ), 217 | new Padding( 218 | padding: new EdgeInsets.only( 219 | left: 4.0, 220 | right: 4.0, 221 | bottom: 4.0), 222 | child: new Text( 223 | data["articles"][index] 224 | ["description"], 225 | style: new TextStyle( 226 | color: Colors.grey[500], 227 | ), 228 | ), 229 | ), 230 | ], 231 | ), 232 | onTap: () { 233 | flutterWebviewPlugin.launch( 234 | data["articles"][index]["url"], 235 | fullScreen: false); 236 | }, 237 | ), 238 | ), 239 | new Column( 240 | children: [ 241 | new Padding( 242 | padding: new EdgeInsets.only(top: 8.0), 243 | child: new SizedBox( 244 | height: 100.0, 245 | width: 100.0, 246 | child: new Image.network( 247 | data["articles"][index] 248 | ["urlToImage"], 249 | fit: BoxFit.cover, 250 | ), 251 | ), 252 | ), 253 | new Row( 254 | children: [ 255 | new GestureDetector( 256 | child: new Padding( 257 | padding: 258 | new EdgeInsets.symmetric( 259 | vertical: 10.0, 260 | horizontal: 5.0), 261 | child: buildButtonColumn( 262 | Icons.share)), 263 | onTap: () { 264 | share(data["articles"][index] 265 | ["url"]); 266 | }, 267 | ), 268 | new GestureDetector( 269 | child: new Padding( 270 | padding: 271 | new EdgeInsets.all(5.0), 272 | child: _hasArticle( 273 | data["articles"][index]) 274 | ? buildButtonColumn( 275 | Icons.bookmark) 276 | : buildButtonColumn( 277 | Icons.bookmark_border)), 278 | onTap: () { 279 | _onBookmarkTap( 280 | data["articles"][index]); 281 | }, 282 | ), 283 | ], 284 | ) 285 | ], 286 | ) 287 | ], 288 | ), 289 | ], 290 | ), 291 | ), 292 | ), 293 | ); 294 | }, 295 | ) 296 | : new Center( 297 | child: new Column( 298 | mainAxisAlignment: MainAxisAlignment.center, 299 | children: [ 300 | new Icon(Icons.chrome_reader_mode, 301 | color: Colors.grey, size: 60.0), 302 | new Text( 303 | "No articles saved", 304 | style: 305 | new TextStyle(fontSize: 24.0, color: Colors.grey), 306 | ), 307 | ], 308 | ), 309 | ), 310 | ); 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /lib/BookmarkScreen.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:share/share.dart'; 5 | import 'package:firebase_database/firebase_database.dart'; 6 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; 7 | import 'package:firebase_database/ui/firebase_animated_list.dart'; 8 | import 'package:timeago/timeago.dart'; 9 | import './globalStore.dart' as globalStore; 10 | 11 | class BookmarksScreen extends StatefulWidget { 12 | BookmarksScreen({Key key}) : super(key: key); 13 | 14 | @override 15 | _BookmarksScreenState createState() => new _BookmarksScreenState(); 16 | } 17 | 18 | class _BookmarksScreenState extends State { 19 | DataSnapshot snapshot; 20 | bool change = false; 21 | final FlutterWebviewPlugin flutterWebviewPlugin = new FlutterWebviewPlugin(); 22 | 23 | Future updateSnapshot() async { 24 | var snap = await globalStore.articleDatabaseReference.once(); 25 | this.setState(() { 26 | snapshot = snap; 27 | }); 28 | return "Success!"; 29 | } 30 | 31 | @override 32 | void initState() { 33 | super.initState(); 34 | this.updateSnapshot(); 35 | } 36 | 37 | _onBookmarkTap(article) { 38 | if (snapshot.value != null) { 39 | var value = snapshot.value; 40 | value.forEach((k, v) { 41 | if (v['url'].compareTo(article['url']) == 0) { 42 | globalStore.articleDatabaseReference.child(k).remove(); 43 | Scaffold.of(context).showSnackBar(new SnackBar( 44 | content: new Text('Article removed'), 45 | backgroundColor: Colors.grey[600], 46 | )); 47 | } 48 | }); 49 | this.updateSnapshot(); 50 | this.setState(() { 51 | change = true; 52 | }); 53 | } 54 | } 55 | 56 | Column buildButtonColumn(IconData icon) { 57 | Color color = Theme.of(context).primaryColor; 58 | return new Column( 59 | mainAxisSize: MainAxisSize.min, 60 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 61 | children: [ 62 | new Icon(icon, color: color), 63 | ], 64 | ); 65 | } 66 | 67 | @override 68 | Widget build(BuildContext context) { 69 | return new Scaffold( 70 | backgroundColor: Colors.grey[200], 71 | body: (snapshot != null && snapshot.value != null) 72 | ? new Column( 73 | children: [ 74 | new Flexible( 75 | child: new FirebaseAnimatedList( 76 | query: globalStore.articleDatabaseReference, 77 | sort: (a, b) => b.key.compareTo(a.key), 78 | padding: new EdgeInsets.all(2.0), 79 | itemBuilder: 80 | (_, DataSnapshot snapshot, Animation animation) { 81 | return new GestureDetector( 82 | child: new Card( 83 | elevation: 1.7, 84 | child: new Padding( 85 | padding: new EdgeInsets.all(10.0), 86 | child: new Column( 87 | children: [ 88 | new Row( 89 | children: [ 90 | new Padding( 91 | padding: new EdgeInsets.only(left: 4.0), 92 | child: new Text( 93 | timeAgo(DateTime.parse( 94 | snapshot.value["publishedAt"])), 95 | style: new TextStyle( 96 | fontWeight: FontWeight.w400, 97 | color: Colors.grey[600], 98 | ), 99 | ), 100 | ), 101 | new Padding( 102 | padding: new EdgeInsets.all(5.0), 103 | child: new Text( 104 | snapshot.value["source"], 105 | style: new TextStyle( 106 | fontWeight: FontWeight.w500, 107 | color: Colors.grey[700], 108 | ), 109 | ), 110 | ), 111 | ], 112 | ), 113 | new Row( 114 | children: [ 115 | new Expanded( 116 | child: new GestureDetector( 117 | child: new Column( 118 | crossAxisAlignment: 119 | CrossAxisAlignment.start, 120 | children: [ 121 | new Padding( 122 | padding: new EdgeInsets.only( 123 | left: 4.0, 124 | right: 8.0, 125 | bottom: 8.0, 126 | top: 8.0), 127 | child: new Text( 128 | snapshot.value["title"], 129 | style: new TextStyle( 130 | fontWeight: FontWeight.bold, 131 | ), 132 | ), 133 | ), 134 | new Padding( 135 | padding: new EdgeInsets.only( 136 | left: 4.0, 137 | right: 4.0, 138 | bottom: 4.0), 139 | child: new Text( 140 | snapshot.value["description"], 141 | style: new TextStyle( 142 | color: Colors.grey[500], 143 | ), 144 | ), 145 | ), 146 | ], 147 | ), 148 | onTap: () { 149 | flutterWebviewPlugin.launch( 150 | snapshot.value["url"], 151 | fullScreen: false); 152 | }, 153 | ), 154 | ), 155 | new Column( 156 | children: [ 157 | new Padding( 158 | padding: new EdgeInsets.only(top: 8.0), 159 | child: new SizedBox( 160 | height: 100.0, 161 | width: 100.0, 162 | child: new Image.network( 163 | snapshot.value["urlToImage"], 164 | fit: BoxFit.cover, 165 | ), 166 | ), 167 | ), 168 | new Row( 169 | children: [ 170 | new GestureDetector( 171 | child: new Padding( 172 | padding: 173 | new EdgeInsets.symmetric( 174 | vertical: 10.0, 175 | horizontal: 5.0), 176 | child: buildButtonColumn( 177 | Icons.share)), 178 | onTap: () { 179 | share(snapshot.value["url"]); 180 | }, 181 | ), 182 | new GestureDetector( 183 | child: buildButtonColumn( 184 | Icons.bookmark), 185 | onTap: () { 186 | _onBookmarkTap(snapshot.value); 187 | }, 188 | ), 189 | ], 190 | ) 191 | ], 192 | ), 193 | ], 194 | ), 195 | ], 196 | ), 197 | ), 198 | ), 199 | ); 200 | }, 201 | )), 202 | ], 203 | ) 204 | : new Center( 205 | child: new Column( 206 | mainAxisAlignment: MainAxisAlignment.center, 207 | children: [ 208 | new Icon(Icons.chrome_reader_mode, 209 | color: Colors.grey, size: 60.0), 210 | new Text( 211 | "No articles saved", 212 | style: new TextStyle(fontSize: 24.0, color: Colors.grey), 213 | ), 214 | ], 215 | ), 216 | ), 217 | ); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /lib/CategoriesScreen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/cupertino.dart'; 3 | import './ArticleSourceScreen.dart' as ArticleSourceScreen; 4 | import './categoriesList.dart' as categoriesList; 5 | 6 | class CategoriesScreen extends StatefulWidget { 7 | CategoriesScreen({Key key}) : super(key: key); 8 | 9 | @override 10 | _CategoriesScreenState createState() => new _CategoriesScreenState(); 11 | } 12 | 13 | class _CategoriesScreenState extends State { 14 | @override 15 | void initState() { 16 | super.initState(); 17 | } 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | return new Scaffold( 22 | backgroundColor: Colors.grey[200], 23 | body: categoriesList.list == null 24 | ? const Center(child: const CircularProgressIndicator()) 25 | : new GridView.builder( 26 | gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( 27 | crossAxisCount: 3, mainAxisSpacing: 25.0), 28 | padding: const EdgeInsets.all(10.0), 29 | itemCount: categoriesList.list.length, 30 | itemBuilder: (BuildContext context, int index) { 31 | return new GridTile( 32 | footer: new Row( 33 | mainAxisAlignment: MainAxisAlignment.center, 34 | children: [ 35 | new Flexible( 36 | child: new SizedBox( 37 | height: 16.0, 38 | width: 100.0, 39 | child: new Text( 40 | categoriesList.list[index]["name"], 41 | maxLines: 2, 42 | textAlign: TextAlign.center, 43 | overflow: TextOverflow.ellipsis, 44 | ), 45 | ), 46 | ) 47 | ]), 48 | child: new Container( 49 | height: 500.0, 50 | child: new GestureDetector( 51 | child: new Column( 52 | crossAxisAlignment: CrossAxisAlignment.center, 53 | children: [ 54 | new SizedBox( 55 | height: 100.0, 56 | width: 100.0, 57 | child: new Row( 58 | children: [ 59 | new Stack( 60 | children: [ 61 | new SizedBox( 62 | child: new Container( 63 | child: new CircleAvatar( 64 | backgroundColor: Colors.white, 65 | radius: 40.0, 66 | child: new Icon( 67 | categoriesList.list[index] 68 | ["icon"], 69 | size: 40.0, 70 | color: categoriesList.list[index] 71 | ["color"]), 72 | ), 73 | padding: const EdgeInsets.only( 74 | left: 10.0, right: 10.0), 75 | ), 76 | ), 77 | ], 78 | ), 79 | ], 80 | ), 81 | ), 82 | ], 83 | ), 84 | onTap: () { 85 | Navigator.push( 86 | context, 87 | new MaterialPageRoute( 88 | builder: (_) => 89 | new ArticleSourceScreen.ArticleSourceScreen( 90 | sourceId: categoriesList.list[index] 91 | ['id'], 92 | sourceName: categoriesList.list[index] 93 | ["name"], 94 | isCategory: true, 95 | ))); 96 | }, 97 | ), 98 | ), 99 | ); 100 | }, 101 | ), 102 | ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lib/HomeFeedScreen.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:async'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:http/http.dart' as http; 6 | import 'package:share/share.dart'; 7 | import 'package:firebase_database/firebase_database.dart'; 8 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; 9 | import 'package:timeago/timeago.dart'; 10 | import './globalStore.dart' as globalStore; 11 | import './SearchScreen.dart' as SearchScreen; 12 | 13 | class HomeFeedScreen extends StatefulWidget { 14 | HomeFeedScreen({Key key}) : super(key: key); 15 | 16 | @override 17 | _HomeFeedScreenState createState() => new _HomeFeedScreenState(); 18 | } 19 | 20 | class _HomeFeedScreenState extends State { 21 | var data; 22 | var newsSelection = "techcrunch"; 23 | DataSnapshot snapshot; 24 | var snapSources; 25 | TimeAgo ta = new TimeAgo(); 26 | final FlutterWebviewPlugin flutterWebviewPlugin = new FlutterWebviewPlugin(); 27 | final TextEditingController _controller = new TextEditingController(); 28 | Future getData() async { 29 | await globalStore.logIn; 30 | if (await globalStore.userDatabaseReference == null) { 31 | await globalStore.logIn; 32 | } 33 | snapSources = await globalStore.articleSourcesDatabaseReference.once(); 34 | var snap = await globalStore.articleDatabaseReference.once(); 35 | if (snapSources.value != null) { 36 | newsSelection = ''; 37 | snapSources.value.forEach((key, source) { 38 | newsSelection = newsSelection + source['id'] + ','; 39 | }); 40 | } 41 | var response = await http.get( 42 | Uri.encodeFull( 43 | 'https://newsapi.org/v2/top-headlines?sources=' + newsSelection), 44 | headers: { 45 | "Accept": "application/json", 46 | "X-Api-Key": "ab31ce4a49814a27bbb16dd5c5c06608" 47 | }); 48 | var localData = JSON.decode(response.body); 49 | if (localData != null && localData["articles"] != null) { 50 | localData["articles"].sort((a, b) => 51 | a["publishedAt"] != null && b["publishedAt"] != null 52 | ? b["publishedAt"].compareTo(a["publishedAt"]) 53 | : null); 54 | } 55 | // if (mounted) { 56 | this.setState(() { 57 | data = localData; 58 | snapshot = snap; 59 | }); 60 | // } 61 | return "Success!"; 62 | } 63 | 64 | _hasArticle(article) { 65 | if (snapshot.value != null) { 66 | var value = snapshot.value; 67 | int flag = 0; 68 | if (value != null) { 69 | value.forEach((k, v) { 70 | if (v['url'].compareTo(article['url']) == 0) { 71 | flag = 1; 72 | return; 73 | } 74 | }); 75 | if (flag == 1) return true; 76 | } 77 | } 78 | return false; 79 | } 80 | 81 | pushArticle(article) { 82 | globalStore.articleDatabaseReference.push().set({ 83 | 'source': article["source"]["name"], 84 | 'description': article['description'], 85 | 'publishedAt': article['publishedAt'], 86 | 'title': article['title'], 87 | 'url': article['url'], 88 | 'urlToImage': article['urlToImage'], 89 | }); 90 | } 91 | 92 | _onBookmarkTap(article) { 93 | if (snapshot.value != null) { 94 | var value = snapshot.value; 95 | int flag = 0; 96 | value.forEach((k, v) { 97 | if (v['url'].compareTo(article['url']) == 0) { 98 | flag = 1; 99 | globalStore.articleDatabaseReference.child(k).remove(); 100 | Scaffold.of(context).showSnackBar(new SnackBar( 101 | content: new Text('Article removed'), 102 | backgroundColor: Colors.grey[600], 103 | )); 104 | } 105 | }); 106 | if (flag != 1) { 107 | Scaffold.of(context).showSnackBar(new SnackBar( 108 | content: new Text('Article saved'), 109 | backgroundColor: Colors.grey[600], 110 | )); 111 | pushArticle(article); 112 | } 113 | } else { 114 | pushArticle(article); 115 | } 116 | this.getData(); 117 | } 118 | 119 | _onRemoveSource(id, name) { 120 | if (snapSources != null) { 121 | snapSources.value.forEach((key, source) { 122 | if (source['id'].compareTo(id) == 0) { 123 | Scaffold.of(context).showSnackBar(new SnackBar( 124 | content: new Text('Are you sure you want to remove $name?'), 125 | backgroundColor: Colors.grey[600], 126 | duration: new Duration(seconds: 3), 127 | action: new SnackBarAction( 128 | label: 'Yes', 129 | onPressed: () { 130 | globalStore.articleSourcesDatabaseReference 131 | .child(key) 132 | .remove(); 133 | Scaffold.of(context).showSnackBar(new SnackBar( 134 | content: new Text('$name removed'), 135 | backgroundColor: Colors.grey[600])); 136 | }), 137 | )); 138 | } 139 | }); 140 | this.getData(); 141 | } 142 | } 143 | 144 | void handleTextInputSubmit(var input) { 145 | if (input != '') { 146 | Navigator.push( 147 | context, 148 | new MaterialPageRoute( 149 | builder: (_) => 150 | new SearchScreen.SearchScreen(searchQuery: input))); 151 | } 152 | } 153 | 154 | @override 155 | void initState() { 156 | super.initState(); 157 | this.getData(); 158 | } 159 | 160 | Column buildButtonColumn(IconData icon) { 161 | Color color = Theme.of(context).primaryColor; 162 | return new Column( 163 | mainAxisSize: MainAxisSize.min, 164 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 165 | children: [ 166 | new Icon(icon, color: color), 167 | ], 168 | ); 169 | } 170 | 171 | @override 172 | Widget build(BuildContext context) { 173 | return new Scaffold( 174 | resizeToAvoidBottomPadding: false, 175 | backgroundColor: Colors.grey[200], 176 | body: new Column(children: [ 177 | new Padding( 178 | padding: new EdgeInsets.all(0.0), 179 | child: new PhysicalModel( 180 | color: Colors.white, 181 | elevation: 3.0, 182 | child: new TextField( 183 | controller: _controller, 184 | onSubmitted: handleTextInputSubmit, 185 | decoration: new InputDecoration( 186 | hintText: 'Finding a News?', icon: new Icon(Icons.search)), 187 | ), 188 | ), 189 | ), 190 | new Expanded( 191 | child: data == null 192 | ? const Center(child: const CircularProgressIndicator()) 193 | : data["articles"].length != 0 194 | ? new ListView.builder( 195 | itemCount: data == null ? 0 : data["articles"].length, 196 | padding: new EdgeInsets.all(8.0), 197 | itemBuilder: (BuildContext context, int index) { 198 | return new Card( 199 | elevation: 1.7, 200 | child: new Padding( 201 | padding: new EdgeInsets.all(10.0), 202 | child: new Column( 203 | children: [ 204 | new Row( 205 | children: [ 206 | new Padding( 207 | padding: new EdgeInsets.only(left: 4.0), 208 | child: new Text( 209 | timeAgo(DateTime.parse(data["articles"] 210 | [index]["publishedAt"])), 211 | style: new TextStyle( 212 | fontWeight: FontWeight.w400, 213 | color: Colors.grey[600], 214 | ), 215 | ), 216 | ), 217 | new Padding( 218 | padding: new EdgeInsets.all(5.0), 219 | child: new Text( 220 | data["articles"][index]["source"] 221 | ["name"], 222 | style: new TextStyle( 223 | fontWeight: FontWeight.w500, 224 | color: Colors.grey[700], 225 | ), 226 | ), 227 | ), 228 | ], 229 | ), 230 | new Row( 231 | children: [ 232 | new Expanded( 233 | child: new GestureDetector( 234 | child: new Column( 235 | crossAxisAlignment: 236 | CrossAxisAlignment.start, 237 | children: [ 238 | new Padding( 239 | padding: new EdgeInsets.only( 240 | left: 4.0, 241 | right: 8.0, 242 | bottom: 8.0, 243 | top: 8.0), 244 | child: new Text( 245 | data["articles"][index] 246 | ["title"], 247 | style: new TextStyle( 248 | fontWeight: FontWeight.bold, 249 | ), 250 | ), 251 | ), 252 | new Padding( 253 | padding: new EdgeInsets.only( 254 | left: 4.0, 255 | right: 4.0, 256 | bottom: 4.0), 257 | child: new Text( 258 | data["articles"][index] 259 | ["description"], 260 | style: new TextStyle( 261 | color: Colors.grey[500], 262 | ), 263 | ), 264 | ), 265 | ], 266 | ), 267 | onTap: () { 268 | flutterWebviewPlugin.launch( 269 | data["articles"][index]["url"], 270 | fullScreen: false); 271 | }, 272 | ), 273 | ), 274 | new Column( 275 | children: [ 276 | new Padding( 277 | padding: 278 | new EdgeInsets.only(top: 8.0), 279 | child: new SizedBox( 280 | height: 100.0, 281 | width: 100.0, 282 | child: new Image.network( 283 | data["articles"][index] 284 | ["urlToImage"], 285 | fit: BoxFit.cover, 286 | ), 287 | ), 288 | ), 289 | new Row( 290 | children: [ 291 | new GestureDetector( 292 | child: new Padding( 293 | padding: 294 | new EdgeInsets.symmetric( 295 | vertical: 10.0, 296 | horizontal: 5.0), 297 | child: buildButtonColumn( 298 | Icons.share)), 299 | onTap: () { 300 | share(data["articles"][index] 301 | ["url"]); 302 | }, 303 | ), 304 | new GestureDetector( 305 | child: new Padding( 306 | padding: 307 | new EdgeInsets.all(5.0), 308 | child: _hasArticle( 309 | data["articles"] 310 | [index]) 311 | ? buildButtonColumn( 312 | Icons.bookmark) 313 | : buildButtonColumn(Icons 314 | .bookmark_border)), 315 | onTap: () { 316 | _onBookmarkTap( 317 | data["articles"][index]); 318 | }, 319 | ), 320 | new GestureDetector( 321 | child: new Padding( 322 | padding: 323 | new EdgeInsets.all(5.0), 324 | child: buildButtonColumn( 325 | Icons.not_interested)), 326 | onTap: () { 327 | _onRemoveSource( 328 | data["articles"][index] 329 | ["source"]["id"], 330 | data["articles"][index] 331 | ["source"]["name"]); 332 | }, 333 | ), 334 | ], 335 | ), 336 | ], 337 | ) 338 | ], 339 | ) 340 | ], 341 | ), //// 342 | ), 343 | ); 344 | }, 345 | ) 346 | : new Center( 347 | child: new Column( 348 | mainAxisAlignment: MainAxisAlignment.center, 349 | children: [ 350 | new Icon(Icons.chrome_reader_mode, 351 | color: Colors.grey, size: 60.0), 352 | new Text( 353 | "No articles saved", 354 | style: new TextStyle( 355 | fontSize: 24.0, color: Colors.grey), 356 | ), 357 | ], 358 | ), 359 | ), 360 | ) 361 | ]), 362 | ); 363 | } 364 | } 365 | -------------------------------------------------------------------------------- /lib/SearchScreen.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:async'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:firebase_auth/firebase_auth.dart'; 6 | import 'package:http/http.dart' as http; 7 | import 'package:share/share.dart'; 8 | import 'package:firebase_database/firebase_database.dart'; 9 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; 10 | import 'package:timeago/timeago.dart'; 11 | import './globalStore.dart' as globalStore; 12 | 13 | class SearchScreen extends StatefulWidget { 14 | SearchScreen({ 15 | Key key, 16 | this.searchQuery = "", 17 | }) 18 | : super(key: key); 19 | final searchQuery; 20 | @override 21 | _SearchScreenState createState() => 22 | new _SearchScreenState(searchQuery: this.searchQuery); 23 | } 24 | 25 | class _SearchScreenState extends State { 26 | _SearchScreenState({this.searchQuery}); 27 | 28 | var searchQuery; 29 | var data; 30 | bool change = false; 31 | DataSnapshot snapshot; 32 | final FlutterWebviewPlugin flutterWebviewPlugin = new FlutterWebviewPlugin(); 33 | final auth = FirebaseAuth.instance; 34 | final databaseReference = FirebaseDatabase.instance.reference(); 35 | var userDatabaseReference; 36 | var articleDatabaseReference; 37 | 38 | Future getData() async { 39 | var response = await http.get( 40 | Uri.encodeFull('https://newsapi.org/v2/everything?q=' + 41 | searchQuery + 42 | '&sortBy=popularity'), 43 | headers: { 44 | "Accept": "application/json", 45 | "X-Api-Key": "ab31ce4a49814a27bbb16dd5c5c06608" 46 | }); 47 | 48 | var snap = await globalStore.articleDatabaseReference.once(); 49 | 50 | if (mounted) { 51 | this.setState(() { 52 | data = JSON.decode(response.body); 53 | snapshot = snap; 54 | }); 55 | } 56 | return "Success!"; 57 | } 58 | 59 | _hasArticle(article) { 60 | if (snapshot.value != null) { 61 | var value = snapshot.value; 62 | int flag = 0; 63 | if (value != null) { 64 | value.forEach((k, v) { 65 | if (v['url'].compareTo(article['url']) == 0) flag = 1; 66 | return; 67 | }); 68 | if (flag == 1) return true; 69 | } 70 | } 71 | return false; 72 | } 73 | 74 | pushArticle(article) { 75 | articleDatabaseReference.push().set({ 76 | 'source': article["source"]["name"], 77 | 'description': article['description'], 78 | 'publishedAt': article['publishedAt'], 79 | 'title': article['title'], 80 | 'url': article['url'], 81 | 'urlToImage': article['urlToImage'], 82 | }); 83 | } 84 | 85 | _onBookmarkTap(article) { 86 | if (snapshot.value != null) { 87 | var value = snapshot.value; 88 | int flag = 0; 89 | value.forEach((k, v) { 90 | if (v['url'].compareTo(article['url']) == 0) { 91 | flag = 1; 92 | articleDatabaseReference.child(k).remove(); 93 | Scaffold.of(context).showSnackBar(new SnackBar( 94 | content: new Text('Bookmark removed'), 95 | backgroundColor: Colors.grey[600], 96 | )); 97 | } 98 | }); 99 | if (flag != 1) { 100 | pushArticle(article); 101 | Scaffold.of(context).showSnackBar(new SnackBar( 102 | content: new Text('Bookmark added'), 103 | backgroundColor: Colors.grey[600], 104 | )); 105 | } 106 | // if (mounted) { 107 | this.setState(() { 108 | change = true; 109 | }); 110 | // } 111 | } else { 112 | pushArticle(article); 113 | } 114 | } 115 | 116 | void initState() { 117 | super.initState(); 118 | this.getData(); 119 | } 120 | 121 | Column buildButtonColumn(IconData icon) { 122 | Color color = Theme.of(context).primaryColor; 123 | return new Column( 124 | mainAxisSize: MainAxisSize.min, 125 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 126 | children: [ 127 | new Icon(icon, color: color), 128 | ], 129 | ); 130 | } 131 | 132 | Widget build(BuildContext context) { 133 | return new Scaffold( 134 | appBar: new AppBar( 135 | title: new Text(searchQuery), 136 | centerTitle: true, 137 | ), 138 | backgroundColor: Colors.grey[200], 139 | body: data == null 140 | ? const Center(child: const CircularProgressIndicator()) 141 | : data["articles"].length < 1 142 | ? new Padding( 143 | padding: new EdgeInsets.only(top: 60.0), 144 | child: new Column( 145 | mainAxisAlignment: MainAxisAlignment.start, 146 | crossAxisAlignment: CrossAxisAlignment.center, 147 | children: [ 148 | new Icon(Icons.error_outline, 149 | size: 60.0, color: Colors.redAccent[200]), 150 | new Center( 151 | child: new Text( 152 | "Could not find anything related to '$searchQuery'", 153 | textScaleFactor: 1.5, 154 | textAlign: TextAlign.center, 155 | style: new TextStyle( 156 | color: Colors.grey[600], 157 | ), 158 | ), 159 | ) 160 | ])) 161 | : new ListView.builder( 162 | itemCount: data['articles'].length < 51 163 | ? data['articles'].length 164 | : 50, 165 | itemBuilder: (BuildContext context, int index) { 166 | return new GestureDetector( 167 | child: new Card( 168 | elevation: 1.7, 169 | child: new Padding( 170 | padding: new EdgeInsets.all(10.0), 171 | child: new Column( 172 | children: [ 173 | new Row( 174 | children: [ 175 | new Padding( 176 | padding: new EdgeInsets.only(left: 4.0), 177 | child: new Text( 178 | timeAgo(DateTime.parse(data["articles"] 179 | [index]["publishedAt"])), 180 | style: new TextStyle( 181 | fontWeight: FontWeight.w400, 182 | color: Colors.grey[600], 183 | ), 184 | ), 185 | ), 186 | new Padding( 187 | padding: new EdgeInsets.all(5.0), 188 | child: new Text( 189 | data["articles"][index]["source"]["name"], 190 | style: new TextStyle( 191 | fontWeight: FontWeight.w500, 192 | color: Colors.grey[700], 193 | ), 194 | ), 195 | ), 196 | ], 197 | ), 198 | new Row( 199 | children: [ 200 | new Expanded( 201 | child: new GestureDetector( 202 | child: new Column( 203 | crossAxisAlignment: 204 | CrossAxisAlignment.start, 205 | children: [ 206 | new Padding( 207 | padding: new EdgeInsets.only( 208 | left: 4.0, 209 | right: 8.0, 210 | bottom: 8.0, 211 | top: 8.0), 212 | child: new Text( 213 | data["articles"][index]["title"], 214 | style: new TextStyle( 215 | fontWeight: FontWeight.bold, 216 | ), 217 | ), 218 | ), 219 | new Padding( 220 | padding: new EdgeInsets.only( 221 | left: 4.0, 222 | right: 4.0, 223 | bottom: 4.0), 224 | child: new Text( 225 | data["articles"][index] 226 | ["description"], 227 | style: new TextStyle( 228 | color: Colors.grey[500], 229 | ), 230 | ), 231 | ), 232 | ], 233 | ), 234 | onTap: () { 235 | flutterWebviewPlugin.launch( 236 | data["articles"][index]["url"], 237 | fullScreen: false); 238 | }, 239 | ), 240 | ), 241 | new Column( 242 | children: [ 243 | new Padding( 244 | padding: new EdgeInsets.only(top: 8.0), 245 | child: new SizedBox( 246 | height: 100.0, 247 | width: 100.0, 248 | child: new Image.network( 249 | data["articles"][index] 250 | ["urlToImage"], 251 | fit: BoxFit.cover, 252 | ), 253 | ), 254 | ), 255 | new Row( 256 | children: [ 257 | new GestureDetector( 258 | child: new Padding( 259 | padding: 260 | new EdgeInsets.symmetric( 261 | vertical: 10.0, 262 | horizontal: 5.0), 263 | child: buildButtonColumn( 264 | Icons.share)), 265 | onTap: () { 266 | share(data["articles"][index] 267 | ["url"]); 268 | }, 269 | ), 270 | new GestureDetector( 271 | child: new Padding( 272 | padding: 273 | new EdgeInsets.all(5.0), 274 | child: _hasArticle( 275 | data["articles"][index]) 276 | ? buildButtonColumn( 277 | Icons.bookmark) 278 | : buildButtonColumn( 279 | Icons.bookmark_border)), 280 | onTap: () { 281 | _onBookmarkTap( 282 | data["articles"][index]); 283 | }, 284 | ), 285 | ], 286 | ) 287 | ], 288 | ) 289 | ], 290 | ), 291 | ], 292 | ), 293 | ), 294 | ), 295 | ); 296 | }, 297 | ), 298 | ); 299 | } 300 | } 301 | //add try-catch in result query 302 | -------------------------------------------------------------------------------- /lib/SourceLibraryScreen.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:async'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:http/http.dart' as http; 6 | import 'package:firebase_database/firebase_database.dart'; 7 | import 'package:flutter_webview_plugin/flutter_webview_plugin.dart'; 8 | import './ArticleSourceScreen.dart' as ArticleSourceScreen; 9 | import './globalStore.dart' as globalStore; 10 | 11 | class SourceLibraryScreen extends StatefulWidget { 12 | SourceLibraryScreen({Key key}) : super(key: key); 13 | 14 | @override 15 | _SourceLibraryScreenState createState() => new _SourceLibraryScreenState(); 16 | } 17 | 18 | class _SourceLibraryScreenState extends State { 19 | DataSnapshot snapshot; 20 | var sources; 21 | bool change = false; 22 | final FlutterWebviewPlugin flutterWebviewPlugin = new FlutterWebviewPlugin(); 23 | 24 | Future getData() async { 25 | var libSources = await http.get( 26 | Uri.encodeFull('https://newsapi.org/v2/sources?language=en'), 27 | headers: { 28 | "Accept": "application/json", 29 | "X-Api-Key": "ab31ce4a49814a27bbb16dd5c5c06608" 30 | }); 31 | 32 | var snap = await globalStore.articleSourcesDatabaseReference.once(); 33 | if (mounted) { 34 | this.setState(() { 35 | sources = JSON.decode(libSources.body); 36 | snapshot = snap; 37 | }); 38 | } 39 | return "Success!"; 40 | } 41 | 42 | _hasSource(id) { 43 | if (snapshot.value != null) { 44 | var value = snapshot.value; 45 | int flag = 0; 46 | if (value != null) { 47 | value.forEach((k, v) { 48 | if (v['id'].compareTo(id) == 0) { 49 | flag = 1; 50 | } 51 | }); 52 | if (flag == 1) return true; 53 | } 54 | } 55 | return false; 56 | } 57 | 58 | pushSource(name, id) { 59 | globalStore.articleSourcesDatabaseReference.push().set({ 60 | 'name': name, 61 | 'id': id, 62 | }); 63 | } 64 | 65 | _onAddTap(name, id) { 66 | if (snapshot.value != null) { 67 | var value = snapshot.value; 68 | int flag = 0; 69 | value.forEach((k, v) { 70 | if (v['id'].compareTo(id) == 0) { 71 | flag = 1; 72 | Scaffold.of(context).showSnackBar(new SnackBar( 73 | content: new Text('$name removed'), 74 | backgroundColor: Colors.grey[600], 75 | )); 76 | globalStore.articleSourcesDatabaseReference.child(k).remove(); 77 | } 78 | }); 79 | if (flag != 1) { 80 | Scaffold.of(context).showSnackBar(new SnackBar( 81 | content: new Text('$name added'), 82 | backgroundColor: Colors.grey[600])); 83 | pushSource(name, id); 84 | } 85 | } else { 86 | pushSource(name, id); 87 | } 88 | this.getData(); 89 | if (mounted) { 90 | this.setState(() { 91 | change = true; 92 | }); 93 | } 94 | } 95 | 96 | CircleAvatar _loadAvatar(var url) { 97 | if (url == "http://www.bleacherreport.com") { 98 | return new CircleAvatar( 99 | backgroundColor: Colors.transparent, 100 | backgroundImage: new NetworkImage( 101 | "http://static-assets.bleacherreport.com/favicon.ico"), 102 | radius: 40.0, 103 | ); 104 | } 105 | try { 106 | return new CircleAvatar( 107 | backgroundColor: Colors.transparent, 108 | backgroundImage: new NetworkImage( 109 | "https://icons.better-idea.org/icon?url=" + url + "&size=120"), 110 | radius: 40.0, 111 | ); 112 | } catch (Exception) { 113 | return new CircleAvatar( 114 | child: new Icon(Icons.library_books), 115 | radius: 40.0, 116 | ); 117 | } 118 | } 119 | 120 | @override 121 | void initState() { 122 | super.initState(); 123 | this.getData(); 124 | } 125 | 126 | @override 127 | Widget build(BuildContext context) { 128 | return new Scaffold( 129 | backgroundColor: Colors.grey[200], 130 | body: sources == null 131 | ? const Center(child: const CircularProgressIndicator()) 132 | : new GridView.builder( 133 | gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( 134 | crossAxisCount: 3, mainAxisSpacing: 25.0), 135 | padding: const EdgeInsets.all(10.0), 136 | itemCount: sources == null ? 0 : sources['sources'].length, 137 | itemBuilder: (BuildContext context, int index) { 138 | return new GridTile( 139 | footer: new Row( 140 | mainAxisAlignment: MainAxisAlignment.center, 141 | children: [ 142 | new Flexible( 143 | child: new SizedBox( 144 | height: 16.0, 145 | width: 100.0, 146 | child: new Text( 147 | sources['sources'][index]['name'], 148 | maxLines: 2, 149 | textAlign: TextAlign.center, 150 | overflow: TextOverflow.ellipsis, 151 | ), 152 | ), 153 | ) 154 | ]), 155 | child: new Container( 156 | height: 500.0, 157 | padding: const EdgeInsets.only(bottom: 5.0), 158 | child: new GestureDetector( 159 | child: new Column( 160 | crossAxisAlignment: CrossAxisAlignment.center, 161 | children: [ 162 | new SizedBox( 163 | height: 100.0, 164 | width: 100.0, 165 | child: new Row( 166 | children: [ 167 | new Stack( 168 | children: [ 169 | new SizedBox( 170 | child: new Container( 171 | child: _loadAvatar( 172 | sources['sources'][index]['url']), 173 | padding: const EdgeInsets.only( 174 | left: 10.0, top: 12.0, right: 10.0), 175 | ), 176 | ), 177 | new Positioned( 178 | right: 0.0, 179 | child: new GestureDetector( 180 | child: _hasSource( 181 | sources['sources'][index]['id']) 182 | ? new Icon( 183 | Icons.check_circle, 184 | color: Colors.greenAccent[700], 185 | ) 186 | : new Icon( 187 | Icons.add_circle_outline, 188 | color: Colors.grey[500], 189 | ), 190 | onTap: () { 191 | _onAddTap( 192 | sources['sources'][index]['name'], 193 | sources['sources'][index]['id']); 194 | }, 195 | ), 196 | ), 197 | ], 198 | ), 199 | ], 200 | ), 201 | ), 202 | ], 203 | ), 204 | onTap: () { 205 | Navigator.push( 206 | context, 207 | new MaterialPageRoute( 208 | builder: (_) => 209 | new ArticleSourceScreen.ArticleSourceScreen( 210 | sourceId: sources['sources'][index]['id'], 211 | sourceName: sources['sources'][index] 212 | ['name'], 213 | isCategory: false, 214 | ))); 215 | }, 216 | ), 217 | ), 218 | ); 219 | }, 220 | ), 221 | ); 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /lib/categoriesList.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | List list = [ 4 | { 5 | "id": "business", 6 | "name": "Business", 7 | "icon": Icons.work, 8 | "color": Colors.teal 9 | }, 10 | { 11 | "id": "technology", 12 | "name": "Technology", 13 | "icon": Icons.smartphone, 14 | "color": Colors.grey[600] 15 | }, 16 | { 17 | "id": "science-and-nature", 18 | "name": "Science and Nature", 19 | "icon": Icons.nature_people, 20 | "color": Colors.green[600] 21 | }, 22 | { 23 | "id": "sport", 24 | "name": "Sports", 25 | "icon": Icons.directions_bike, 26 | "color": Colors.deepOrange 27 | }, 28 | { 29 | "id": "gaming", 30 | "name": "Gaming", 31 | "icon": Icons.videogame_asset, 32 | "color": Colors.orange 33 | }, 34 | { 35 | "id": "general", 36 | "name": "General", 37 | "icon": Icons.people, 38 | "color": Colors.cyan 39 | }, 40 | { 41 | "id": "entertainment", 42 | "name": "Entertainment", 43 | "icon": Icons.local_movies, 44 | "color": Colors.purple 45 | }, 46 | { 47 | "id": "health-and-medical", 48 | "name": "Health and Medical", 49 | "icon": Icons.local_hospital, 50 | "color": Colors.red 51 | }, 52 | { 53 | "id": "music", 54 | "name": "Music", 55 | "icon": Icons.music_note, 56 | "color": Colors.amber 57 | }, 58 | { 59 | "id": "politics", 60 | "name": "Politics", 61 | "icon": Icons.assistant_photo, 62 | "color": Colors.blueGrey 63 | }, 64 | ]; 65 | -------------------------------------------------------------------------------- /lib/globalStore.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:google_sign_in/google_sign_in.dart'; 3 | import 'package:firebase_analytics/firebase_analytics.dart'; 4 | import 'package:firebase_database/firebase_database.dart'; 5 | import 'package:firebase_auth/firebase_auth.dart'; 6 | 7 | var sourceList = []; 8 | final googleSignIn = new GoogleSignIn(); 9 | final analytics = new FirebaseAnalytics(); 10 | final auth = FirebaseAuth.instance; 11 | final databaseReference = FirebaseDatabase.instance.reference(); 12 | GoogleSignInAccount user; 13 | var userDatabaseReference; 14 | var articleSourcesDatabaseReference; 15 | var articleDatabaseReference; 16 | Future _ensureLoggedIn() async { 17 | user = googleSignIn.currentUser; 18 | if (user == null) { 19 | user = await googleSignIn.signInSilently(); 20 | } 21 | if (user == null) { 22 | user = await googleSignIn.signIn(); 23 | analytics.logLogin(); 24 | userDatabaseReference = databaseReference.child(user.id); 25 | articleDatabaseReference = 26 | databaseReference.child(user.id).child('articles'); 27 | articleSourcesDatabaseReference = 28 | databaseReference.child(user.id).child('sources'); 29 | } 30 | if (await auth.currentUser() == null) { 31 | GoogleSignInAuthentication credentials = 32 | await googleSignIn.currentUser.authentication; 33 | await auth.signInWithGoogle( 34 | idToken: credentials.idToken, 35 | accessToken: credentials.accessToken, 36 | ); 37 | } else { 38 | userDatabaseReference = databaseReference.child(user.id); 39 | articleDatabaseReference = 40 | databaseReference.child(user.id).child('articles'); 41 | articleSourcesDatabaseReference = 42 | databaseReference.child(user.id).child('sources'); 43 | } 44 | } 45 | 46 | var logIn = _ensureLoggedIn(); 47 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'package:flutter/material.dart'; 3 | import './HomeFeedScreen.dart' as HomeFeedScreeen; 4 | import './SourceLibraryScreen.dart' as SourceLibraryScreen; 5 | import './CategoriesScreen.dart' as CategoriesScreen; 6 | import './BookmarkScreen.dart' as BookmarkScreen; 7 | import './globalStore.dart' as globalStore; 8 | 9 | void main() { 10 | runApp(new MaterialApp(home: new NewsBuzz())); 11 | } 12 | 13 | class NewsBuzz extends StatefulWidget { 14 | @override 15 | createState() => new NewsBuzzState(); 16 | } 17 | 18 | class NewsBuzzState extends State 19 | with SingleTickerProviderStateMixin { 20 | TabController controller; 21 | Future ensureLogIn() async { 22 | await globalStore.logIn; 23 | } 24 | 25 | @override 26 | void initState() { 27 | super.initState(); 28 | this.ensureLogIn(); 29 | controller = new TabController(vsync: this, length: 4); 30 | } 31 | 32 | @override 33 | void dispose() { 34 | super.dispose(); 35 | controller.dispose(); 36 | } 37 | 38 | @override 39 | Widget build(BuildContext context) { 40 | return new Scaffold( 41 | appBar: new AppBar( 42 | title: new Text("News Buzz"), 43 | centerTitle: true, 44 | ), 45 | bottomNavigationBar: new Material( 46 | color: Colors.blue[600], 47 | child: new TabBar(controller: controller, tabs: [ 48 | new Tab(icon: new Icon(Icons.view_headline, size: 30.0)), 49 | new Tab(icon: new Icon(Icons.view_module, size: 30.0)), 50 | new Tab(icon: new Icon(Icons.explore, size: 30.0)), 51 | new Tab(icon: new Icon(Icons.bookmark, size: 30.0)), 52 | ])), 53 | body: new TabBarView(controller: controller, children: [ 54 | new HomeFeedScreeen.HomeFeedScreen(), 55 | new SourceLibraryScreen.SourceLibraryScreen(), 56 | new CategoriesScreen.CategoriesScreen(), 57 | new BookmarkScreen.BookmarksScreen(), 58 | ])); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /newsapp.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /newsapp_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: NewsBuzz 2 | description: Daily News 3 | 4 | dependencies: 5 | flutter: 6 | sdk: flutter 7 | 8 | dev_dependencies: 9 | flutter_test: 10 | sdk: flutter 11 | share: "^0.2.1" 12 | flutter_webview_plugin: "^0.0.9+1" 13 | google_sign_in: "0.3.1" 14 | firebase_analytics: "0.0.4" 15 | firebase_auth: "0.2.0" 16 | firebase_database: "0.0.12" 17 | firebase_storage: "0.0.5" 18 | timeago: "^1.2.0" 19 | cupertino_icons: ^0.1.0 20 | 21 | 22 | # For information on the generic Dart part of this file, see the 23 | # following page: https://www.dartlang.org/tools/pub/pubspec 24 | 25 | # The following section is specific to Flutter. 26 | flutter: 27 | 28 | # The following line ensures that the Material Icons font is 29 | # included with your application, so that you can use the icons in 30 | # the Icons class. 31 | uses-material-design: true 32 | 33 | # To add assets to your application, add an assets section, like this: 34 | # assets: 35 | # - images/a_dot_burr.jpeg 36 | # - images/a_dot_ham.jpeg 37 | 38 | # An image asset can refer to one or more resolution-specific "variants", see 39 | # https://flutter.io/assets-and-images/. 40 | 41 | # To add assets from package dependencies, first ensure the asset 42 | # is in the lib/ directory of the dependency. Then, 43 | # refer to the asset with a path prefixed with 44 | # `packages/PACKAGE_NAME/`. The `lib/` is implied, do not 45 | # include `lib/` in the asset path. 46 | # 47 | # Here is an example: 48 | # 49 | # assets: 50 | # - packages/PACKAGE_NAME/path/to/asset 51 | 52 | # To add custom fonts to your application, add a fonts section here, 53 | # in this "flutter" section. Each entry in this list should have a 54 | # "family" key with the font family name, and a "fonts" key with a 55 | # list giving the asset and other descriptors for the font. For 56 | # example: 57 | # fonts: 58 | # - family: Schyler 59 | # fonts: 60 | # - asset: fonts/Schyler-Regular.ttf 61 | # - asset: fonts/Schyler-Italic.ttf 62 | # style: italic 63 | # - family: Trajan Pro 64 | # fonts: 65 | # - asset: fonts/TrajanPro.ttf 66 | # - asset: fonts/TrajanPro_Bold.ttf 67 | # weight: 700 68 | -------------------------------------------------------------------------------- /screenshots/NewsBuzz.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theankurkedia/newsbuzz/d78a8089543c247a4861d7fea869c414a79383e8/screenshots/NewsBuzz.gif -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | 2 | --------------------------------------------------------------------------------