├── .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 | 
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 |
--------------------------------------------------------------------------------