├── .gitignore ├── .metadata ├── LICENSE ├── README.md ├── android ├── .gitignore ├── app │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── ic_launcher-playstore.png │ │ ├── java │ │ │ └── com │ │ │ │ └── drinkable │ │ │ │ └── drinkable │ │ │ │ └── MainActivity.java │ │ └── res │ │ │ ├── drawable │ │ │ ├── launch_background.xml │ │ │ └── notification_icon.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ │ ├── mipmap-hdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ ├── ic_launcher_foreground.png │ │ │ └── ic_launcher_round.png │ │ │ ├── raw │ │ │ ├── keep.xml │ │ │ └── notification_sound.mp3 │ │ │ ├── values │ │ │ ├── ic_launcher_background.xml │ │ │ └── styles.xml │ │ │ └── xml │ │ │ └── network_security_config.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets ├── icons │ ├── 01.png │ ├── 02.png │ ├── 03.png │ ├── 04.png │ ├── 09.png │ ├── 10.png │ ├── 11.png │ ├── 13.png │ ├── 50.png │ ├── google.png │ └── logo.png └── images │ └── big_logo.png ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── main.dart ├── models │ ├── app_user.dart │ └── weekly_data.dart ├── providers │ ├── auth_provider.dart │ ├── home_provider.dart │ └── statistics_provider.dart ├── root.dart ├── screens │ ├── auth_screen.dart │ ├── data_entry_screen.dart │ ├── home_screen.dart │ ├── profile_screen.dart │ └── scatistics_screen.dart ├── utils │ ├── get_week.dart │ ├── notification_utils.dart │ └── time_converter.dart ├── values │ ├── months.dart │ ├── weather_icons.dart │ └── weekdays.dart └── widgets │ ├── custom_app_bar.dart │ ├── custom_drawer.dart │ ├── custom_form_field.dart │ ├── custom_progress_indicator.dart │ ├── daily_amout_dial.dart │ ├── daily_goal_amount.dart │ ├── goal_and_add.dart │ ├── loading_screen.dart │ ├── three_layer_background.dart │ ├── water_effect.dart │ ├── weather_suggestion.dart │ └── weekly_statistics_graph.dart ├── pubspec.lock ├── pubspec.yaml ├── screenshot ├── flutter_01.png ├── flutter_02.png ├── flutter_03.png ├── flutter_04.png ├── flutter_05.png ├── flutter_06.png ├── flutter_07.png └── flutter_08.png └── test └── widget_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Exceptions to above rules. 44 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 45 | 46 | /android/app/google-services.json 47 | 48 | /lib/values/api_key.dart -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: bbfbf1770cca2da7c82e887e4e4af910034800b6 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Akash Debnath 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Drinkable 2 | 3 |

4 | 5 |
🌊 Drinkable 🌊
6 |

7 |

8 | Built with ❤︎ by 9 | Akash Debnath 10 |

11 |

Drinkable is a Flutter App powered by Firebase to keep track your daily water intake and remind you to drink water by sending notifications.

12 | 13 | 14 | 15 |

16 | 17 |

18 | 19 | In this app user will sign up using their Google Account (Google Sign-In) and if he/she is a new user, then he/she have to fill a form with basic details like gender, age, weight. We also added the daily wake up time. It will be used to send you a notification dauly at that time. By providing the basis information, your can get your recommended daily water intake which is editable. 20 | 21 |

22 | 23 | 24 |

25 | 26 | Now once you signed up, you can add water that you consumed. You can track your intakes in Statistics screen. If you add water, then you will be notified after one and half hour later to drink water again. If you reach your daily target, then you won't be notified for that day again. 27 | 28 | In future if you want to update your profile data like your weight and get the recommended water intake automatically, then you can do it in profile page. 29 | 30 |

31 | 32 | 33 |

34 | 35 | This app also access your location and gets the weather details from Open Weather api of your location. 36 | 37 | For this app I made a custom looking App Drawer. 38 |

39 | 40 |

41 | 42 | I made this app for my own use and added it on GitHub so that others can use it also. 43 | 44 | ## Getting Started 45 | Just Clone the repository and inside the repository run flutter create . 46 | 47 | Create a Firebase project and add this app in the firebase project with SHA-1 and SHA-256 hash of your signing certificate. Follow the instructions and add google-services.json file in Adroid's App level directory. Then enable Google Sing-In from Firebase Authentication's Sign-In Methods. 48 | 49 | Then connect your emulator and run the app by flutter run 50 | 51 | You are GoodToGo. 52 | 53 | **Free Software, Hell Yeah!** 54 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'com.google.gms.google-services' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | // added 29 | 30 | def keystoreProperties = new Properties() 31 | def keystorePropertiesFile = rootProject.file('key.properties') 32 | if (keystorePropertiesFile.exists()) { 33 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 34 | } 35 | 36 | // added 37 | 38 | android { 39 | compileSdkVersion 28 40 | 41 | lintOptions { 42 | disable 'InvalidPackage' 43 | } 44 | 45 | defaultConfig { 46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 47 | applicationId "com.drinkable.drinkable" 48 | minSdkVersion 21 49 | targetSdkVersion 28 50 | versionCode flutterVersionCode.toInteger() 51 | versionName flutterVersionName 52 | } 53 | 54 | // added 55 | signingConfigs { 56 | release { 57 | keyAlias keystoreProperties['keyAlias'] 58 | keyPassword keystoreProperties['keyPassword'] 59 | storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null 60 | storePassword keystoreProperties['storePassword'] 61 | } 62 | } 63 | // added 64 | 65 | buildTypes { 66 | release { 67 | // TODO: Add your own signing config for the release build. 68 | // Signing with the debug keys for now, so `flutter run --release` works. 69 | // signingConfig signingConfigs.debug 70 | signingConfig signingConfigs.release 71 | 72 | minifyEnabled true 73 | 74 | // Enables resource shrinking, which is performed by the 75 | // Android Gradle plugin. 76 | shrinkResources true 77 | 78 | // Includes the default ProGuard rules files that are packaged with 79 | // the Android Gradle plugin. To learn more, go to the section about 80 | // R8 configuration files. 81 | proguardFiles getDefaultProguardFile( 82 | 'proguard-android-optimize.txt'), 83 | 'proguard-rules.pro' 84 | } 85 | } 86 | } 87 | 88 | flutter { 89 | source '../..' 90 | } 91 | 92 | dependencies { 93 | implementation 'com.google.firebase:firebase-analytics:17.5.0' 94 | } 95 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | ## Flutter wrapper 2 | -keep class io.flutter.app.** { *; } 3 | -keep class io.flutter.plugin.** { *; } 4 | -keep class io.flutter.util.** { *; } 5 | -keep class io.flutter.view.** { *; } 6 | -keep class io.flutter.** { *; } 7 | -keep class io.flutter.plugins.** { *; } 8 | -dontwarn io.flutter.embedding.** 9 | 10 | ## Gson rules 11 | # Gson uses generic type information stored in a class file when working with fields. Proguard 12 | # removes such information by default, so configure it to keep all of it. 13 | -keepattributes Signature 14 | 15 | # For using GSON @Expose annotation 16 | -keepattributes *Annotation* 17 | 18 | # Gson specific classes 19 | -dontwarn sun.misc.** 20 | #-keep class com.google.gson.stream.** { *; } 21 | 22 | # Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory, 23 | # JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) 24 | -keep class * implements com.google.gson.TypeAdapter 25 | -keep class * implements com.google.gson.TypeAdapterFactory 26 | -keep class * implements com.google.gson.JsonSerializer 27 | -keep class * implements com.google.gson.JsonDeserializer 28 | 29 | # Prevent R8 from leaving Data object members always null 30 | -keepclassmembers,allowobfuscation class * { 31 | @com.google.gson.annotations.SerializedName ; 32 | } 33 | 34 | ## flutter_local_notification plugin rules 35 | -keep class com.dexterous.** { *; } -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 22 | 26 | 30 | 35 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 53 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /android/app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /android/app/src/main/java/com/drinkable/drinkable/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.drinkable.drinkable; 2 | 3 | import io.flutter.embedding.android.FlutterActivity; 4 | 5 | public class MainActivity extends FlutterActivity { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/notification_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/drawable/notification_icon.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/raw/keep.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /android/app/src/main/res/raw/notification_sound.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/android/app/src/main/res/raw/notification_sound.mp3 -------------------------------------------------------------------------------- /android/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.5.0' 9 | classpath 'com.google.gms:google-services:4.3.3' 10 | } 11 | } 12 | 13 | allprojects { 14 | repositories { 15 | google() 16 | jcenter() 17 | } 18 | } 19 | 20 | rootProject.buildDir = '../build' 21 | subprojects { 22 | project.buildDir = "${rootProject.buildDir}/${project.name}" 23 | } 24 | subprojects { 25 | project.evaluationDependsOn(':app') 26 | } 27 | 28 | task clean(type: Delete) { 29 | delete rootProject.buildDir 30 | } 31 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /assets/icons/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/assets/icons/01.png -------------------------------------------------------------------------------- /assets/icons/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/assets/icons/02.png -------------------------------------------------------------------------------- /assets/icons/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/assets/icons/03.png -------------------------------------------------------------------------------- /assets/icons/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/assets/icons/04.png -------------------------------------------------------------------------------- /assets/icons/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/assets/icons/09.png -------------------------------------------------------------------------------- /assets/icons/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/assets/icons/10.png -------------------------------------------------------------------------------- /assets/icons/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/assets/icons/11.png -------------------------------------------------------------------------------- /assets/icons/13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/assets/icons/13.png -------------------------------------------------------------------------------- /assets/icons/50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/assets/icons/50.png -------------------------------------------------------------------------------- /assets/icons/google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/assets/icons/google.png -------------------------------------------------------------------------------- /assets/icons/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/assets/icons/logo.png -------------------------------------------------------------------------------- /assets/images/big_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/assets/images/big_logo.png -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = ""; 23 | dstSubfolderSpec = 10; 24 | files = ( 25 | ); 26 | name = "Embed Frameworks"; 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXCopyFilesBuildPhase section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 9740EEB11CF90186004384FC /* Flutter */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 65 | ); 66 | name = Flutter; 67 | sourceTree = ""; 68 | }; 69 | 97C146E51CF9000F007C117D = { 70 | isa = PBXGroup; 71 | children = ( 72 | 9740EEB11CF90186004384FC /* Flutter */, 73 | 97C146F01CF9000F007C117D /* Runner */, 74 | 97C146EF1CF9000F007C117D /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 97C146EF1CF9000F007C117D /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 97C146EE1CF9000F007C117D /* Runner.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 97C146F01CF9000F007C117D /* Runner */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 92 | 97C147021CF9000F007C117D /* Info.plist */, 93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 97 | ); 98 | path = Runner; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 97C146ED1CF9000F007C117D /* Runner */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 107 | buildPhases = ( 108 | 9740EEB61CF901F6004384FC /* Run Script */, 109 | 97C146EA1CF9000F007C117D /* Sources */, 110 | 97C146EB1CF9000F007C117D /* Frameworks */, 111 | 97C146EC1CF9000F007C117D /* Resources */, 112 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = Runner; 120 | productName = Runner; 121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 122 | productType = "com.apple.product-type.application"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 97C146E61CF9000F007C117D /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 1020; 131 | ORGANIZATIONNAME = ""; 132 | TargetAttributes = { 133 | 97C146ED1CF9000F007C117D = { 134 | CreatedOnToolsVersion = 7.3.1; 135 | LastSwiftMigration = 1100; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 140 | compatibilityVersion = "Xcode 9.3"; 141 | developmentRegion = en; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | Base, 146 | ); 147 | mainGroup = 97C146E51CF9000F007C117D; 148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | 97C146ED1CF9000F007C117D /* Runner */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | 97C146EC1CF9000F007C117D /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | inputPaths = ( 178 | ); 179 | name = "Thin Binary"; 180 | outputPaths = ( 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 185 | }; 186 | 9740EEB61CF901F6004384FC /* Run Script */ = { 187 | isa = PBXShellScriptBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | ); 191 | inputPaths = ( 192 | ); 193 | name = "Run Script"; 194 | outputPaths = ( 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | shellPath = /bin/sh; 198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 199 | }; 200 | /* End PBXShellScriptBuildPhase section */ 201 | 202 | /* Begin PBXSourcesBuildPhase section */ 203 | 97C146EA1CF9000F007C117D /* Sources */ = { 204 | isa = PBXSourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin PBXVariantGroup section */ 215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 216 | isa = PBXVariantGroup; 217 | children = ( 218 | 97C146FB1CF9000F007C117D /* Base */, 219 | ); 220 | name = Main.storyboard; 221 | sourceTree = ""; 222 | }; 223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | 97C147001CF9000F007C117D /* Base */, 227 | ); 228 | name = LaunchScreen.storyboard; 229 | sourceTree = ""; 230 | }; 231 | /* End PBXVariantGroup section */ 232 | 233 | /* Begin XCBuildConfiguration section */ 234 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 235 | isa = XCBuildConfiguration; 236 | buildSettings = { 237 | ALWAYS_SEARCH_USER_PATHS = NO; 238 | CLANG_ANALYZER_NONNULL = YES; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_MODULES = YES; 242 | CLANG_ENABLE_OBJC_ARC = YES; 243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_COMMA = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 258 | CLANG_WARN_STRICT_PROTOTYPES = YES; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | SDKROOT = iphoneos; 278 | SUPPORTED_PLATFORMS = iphoneos; 279 | TARGETED_DEVICE_FAMILY = "1,2"; 280 | VALIDATE_PRODUCT = YES; 281 | }; 282 | name = Profile; 283 | }; 284 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 285 | isa = XCBuildConfiguration; 286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | CLANG_ENABLE_MODULES = YES; 290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 291 | ENABLE_BITCODE = NO; 292 | FRAMEWORK_SEARCH_PATHS = ( 293 | "$(inherited)", 294 | "$(PROJECT_DIR)/Flutter", 295 | ); 296 | INFOPLIST_FILE = Runner/Info.plist; 297 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 298 | LIBRARY_SEARCH_PATHS = ( 299 | "$(inherited)", 300 | "$(PROJECT_DIR)/Flutter", 301 | ); 302 | PRODUCT_BUNDLE_IDENTIFIER = com.drinkable.drinkable; 303 | PRODUCT_NAME = "$(TARGET_NAME)"; 304 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 305 | SWIFT_VERSION = 5.0; 306 | VERSIONING_SYSTEM = "apple-generic"; 307 | }; 308 | name = Profile; 309 | }; 310 | 97C147031CF9000F007C117D /* Debug */ = { 311 | isa = XCBuildConfiguration; 312 | buildSettings = { 313 | ALWAYS_SEARCH_USER_PATHS = NO; 314 | CLANG_ANALYZER_NONNULL = YES; 315 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 316 | CLANG_CXX_LIBRARY = "libc++"; 317 | CLANG_ENABLE_MODULES = YES; 318 | CLANG_ENABLE_OBJC_ARC = YES; 319 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 320 | CLANG_WARN_BOOL_CONVERSION = YES; 321 | CLANG_WARN_COMMA = YES; 322 | CLANG_WARN_CONSTANT_CONVERSION = YES; 323 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 324 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 325 | CLANG_WARN_EMPTY_BODY = YES; 326 | CLANG_WARN_ENUM_CONVERSION = YES; 327 | CLANG_WARN_INFINITE_RECURSION = YES; 328 | CLANG_WARN_INT_CONVERSION = YES; 329 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 330 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 331 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 332 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 333 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 334 | CLANG_WARN_STRICT_PROTOTYPES = YES; 335 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 336 | CLANG_WARN_UNREACHABLE_CODE = YES; 337 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 338 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 339 | COPY_PHASE_STRIP = NO; 340 | DEBUG_INFORMATION_FORMAT = dwarf; 341 | ENABLE_STRICT_OBJC_MSGSEND = YES; 342 | ENABLE_TESTABILITY = YES; 343 | GCC_C_LANGUAGE_STANDARD = gnu99; 344 | GCC_DYNAMIC_NO_PIC = NO; 345 | GCC_NO_COMMON_BLOCKS = YES; 346 | GCC_OPTIMIZATION_LEVEL = 0; 347 | GCC_PREPROCESSOR_DEFINITIONS = ( 348 | "DEBUG=1", 349 | "$(inherited)", 350 | ); 351 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 352 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 353 | GCC_WARN_UNDECLARED_SELECTOR = YES; 354 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 355 | GCC_WARN_UNUSED_FUNCTION = YES; 356 | GCC_WARN_UNUSED_VARIABLE = YES; 357 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 358 | MTL_ENABLE_DEBUG_INFO = YES; 359 | ONLY_ACTIVE_ARCH = YES; 360 | SDKROOT = iphoneos; 361 | TARGETED_DEVICE_FAMILY = "1,2"; 362 | }; 363 | name = Debug; 364 | }; 365 | 97C147041CF9000F007C117D /* Release */ = { 366 | isa = XCBuildConfiguration; 367 | buildSettings = { 368 | ALWAYS_SEARCH_USER_PATHS = NO; 369 | CLANG_ANALYZER_NONNULL = YES; 370 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 371 | CLANG_CXX_LIBRARY = "libc++"; 372 | CLANG_ENABLE_MODULES = YES; 373 | CLANG_ENABLE_OBJC_ARC = YES; 374 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 375 | CLANG_WARN_BOOL_CONVERSION = YES; 376 | CLANG_WARN_COMMA = YES; 377 | CLANG_WARN_CONSTANT_CONVERSION = YES; 378 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 379 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 380 | CLANG_WARN_EMPTY_BODY = YES; 381 | CLANG_WARN_ENUM_CONVERSION = YES; 382 | CLANG_WARN_INFINITE_RECURSION = YES; 383 | CLANG_WARN_INT_CONVERSION = YES; 384 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 385 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 386 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 387 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 388 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 389 | CLANG_WARN_STRICT_PROTOTYPES = YES; 390 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 391 | CLANG_WARN_UNREACHABLE_CODE = YES; 392 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 393 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 394 | COPY_PHASE_STRIP = NO; 395 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 396 | ENABLE_NS_ASSERTIONS = NO; 397 | ENABLE_STRICT_OBJC_MSGSEND = YES; 398 | GCC_C_LANGUAGE_STANDARD = gnu99; 399 | GCC_NO_COMMON_BLOCKS = YES; 400 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 401 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 402 | GCC_WARN_UNDECLARED_SELECTOR = YES; 403 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 404 | GCC_WARN_UNUSED_FUNCTION = YES; 405 | GCC_WARN_UNUSED_VARIABLE = YES; 406 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 407 | MTL_ENABLE_DEBUG_INFO = NO; 408 | SDKROOT = iphoneos; 409 | SUPPORTED_PLATFORMS = iphoneos; 410 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 411 | TARGETED_DEVICE_FAMILY = "1,2"; 412 | VALIDATE_PRODUCT = YES; 413 | }; 414 | name = Release; 415 | }; 416 | 97C147061CF9000F007C117D /* Debug */ = { 417 | isa = XCBuildConfiguration; 418 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 419 | buildSettings = { 420 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 421 | CLANG_ENABLE_MODULES = YES; 422 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 423 | ENABLE_BITCODE = NO; 424 | FRAMEWORK_SEARCH_PATHS = ( 425 | "$(inherited)", 426 | "$(PROJECT_DIR)/Flutter", 427 | ); 428 | INFOPLIST_FILE = Runner/Info.plist; 429 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 430 | LIBRARY_SEARCH_PATHS = ( 431 | "$(inherited)", 432 | "$(PROJECT_DIR)/Flutter", 433 | ); 434 | PRODUCT_BUNDLE_IDENTIFIER = com.drinkable.drinkable; 435 | PRODUCT_NAME = "$(TARGET_NAME)"; 436 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 437 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 438 | SWIFT_VERSION = 5.0; 439 | VERSIONING_SYSTEM = "apple-generic"; 440 | }; 441 | name = Debug; 442 | }; 443 | 97C147071CF9000F007C117D /* Release */ = { 444 | isa = XCBuildConfiguration; 445 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 446 | buildSettings = { 447 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 448 | CLANG_ENABLE_MODULES = YES; 449 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 450 | ENABLE_BITCODE = NO; 451 | FRAMEWORK_SEARCH_PATHS = ( 452 | "$(inherited)", 453 | "$(PROJECT_DIR)/Flutter", 454 | ); 455 | INFOPLIST_FILE = Runner/Info.plist; 456 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 457 | LIBRARY_SEARCH_PATHS = ( 458 | "$(inherited)", 459 | "$(PROJECT_DIR)/Flutter", 460 | ); 461 | PRODUCT_BUNDLE_IDENTIFIER = com.drinkable.drinkable; 462 | PRODUCT_NAME = "$(TARGET_NAME)"; 463 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 464 | SWIFT_VERSION = 5.0; 465 | VERSIONING_SYSTEM = "apple-generic"; 466 | }; 467 | name = Release; 468 | }; 469 | /* End XCBuildConfiguration section */ 470 | 471 | /* Begin XCConfigurationList section */ 472 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 473 | isa = XCConfigurationList; 474 | buildConfigurations = ( 475 | 97C147031CF9000F007C117D /* Debug */, 476 | 97C147041CF9000F007C117D /* Release */, 477 | 249021D3217E4FDB00AE95B9 /* Profile */, 478 | ); 479 | defaultConfigurationIsVisible = 0; 480 | defaultConfigurationName = Release; 481 | }; 482 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 483 | isa = XCConfigurationList; 484 | buildConfigurations = ( 485 | 97C147061CF9000F007C117D /* Debug */, 486 | 97C147071CF9000F007C117D /* Release */, 487 | 249021D4217E4FDB00AE95B9 /* Profile */, 488 | ); 489 | defaultConfigurationIsVisible = 0; 490 | defaultConfigurationName = Release; 491 | }; 492 | /* End XCConfigurationList section */ 493 | }; 494 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 495 | } 496 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /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 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/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/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | drinkable 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter/services.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:firebase_core/firebase_core.dart'; 5 | import 'package:flutter_local_notifications/flutter_local_notifications.dart'; 6 | 7 | // providers 8 | import './providers/home_provider.dart'; 9 | import './providers/auth_provider.dart'; 10 | import './providers/statistics_provider.dart'; 11 | 12 | // screens 13 | import './root.dart'; 14 | import './screens/data_entry_screen.dart'; 15 | 16 | void main() async { 17 | WidgetsFlutterBinding.ensureInitialized(); 18 | await Firebase.initializeApp(); 19 | await SystemChrome.setPreferredOrientations( 20 | [ 21 | DeviceOrientation.portraitDown, 22 | DeviceOrientation.portraitUp 23 | ] 24 | ); 25 | 26 | FlutterLocalNotificationsPlugin notificationsPlugin = FlutterLocalNotificationsPlugin(); 27 | AndroidInitializationSettings android = AndroidInitializationSettings('notification_icon'); 28 | IOSInitializationSettings ios = IOSInitializationSettings(); 29 | InitializationSettings settings = InitializationSettings( 30 | android,ios 31 | ); 32 | await notificationsPlugin.initialize( 33 | settings, 34 | ); 35 | 36 | runApp(MyApp()); 37 | } 38 | 39 | class MyApp extends StatelessWidget { 40 | @override 41 | Widget build(BuildContext context) { 42 | return MultiProvider( 43 | providers: [ 44 | ChangeNotifierProvider( 45 | create: (context) => AuthProvider(), 46 | ), 47 | ChangeNotifierProxyProvider( 48 | create: (context) => HomeProvider(), 49 | update: (context, authProvider, homeProvider) => homeProvider..update(authProvider.user), 50 | ), 51 | ChangeNotifierProxyProvider( 52 | create: (context) => StatisticsProvider(), 53 | update: (context, authProvider, statisticsProvider) => statisticsProvider..update(authProvider.user), 54 | ) 55 | ], 56 | child: MaterialApp( 57 | //showPerformanceOverlay: true, 58 | title: 'Drinkable', 59 | theme: ThemeData( 60 | primarySwatch: Colors.blue, 61 | visualDensity: VisualDensity.adaptivePlatformDensity, 62 | pageTransitionsTheme: PageTransitionsTheme( 63 | builders: { 64 | TargetPlatform.android : CupertinoPageTransitionsBuilder() 65 | } 66 | ), 67 | ), 68 | home: Root(), 69 | routes: { 70 | DataEntryScreen.routeName : (ctx)=>DataEntryScreen(), 71 | }, 72 | ), 73 | ); 74 | } 75 | } -------------------------------------------------------------------------------- /lib/models/app_user.dart: -------------------------------------------------------------------------------- 1 | import 'package:cloud_firestore/cloud_firestore.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class AppUser { 5 | String uid; 6 | String googleId; 7 | String email; 8 | String name; 9 | String gender; 10 | DateTime birthday; 11 | double weight; 12 | TimeOfDay wakeUpTime; 13 | int dailyTarget; 14 | 15 | AppUser({ 16 | this.uid, 17 | this.googleId, 18 | this.email, 19 | this.name, 20 | this.gender, 21 | this.birthday, 22 | this.weight, 23 | this.wakeUpTime, 24 | this.dailyTarget 25 | }); 26 | 27 | factory AppUser.fromDoc(Map doc){ 28 | return AppUser( 29 | uid: doc['uid'], 30 | googleId: doc['google_id'], 31 | email: doc['email'], 32 | name: doc['name'], 33 | gender: doc['gender'], 34 | birthday: (doc['birthday'] as Timestamp).toDate(), 35 | weight: doc['weight'], 36 | wakeUpTime: TimeOfDay( 37 | hour: doc['wake_up_time']['hour'], 38 | minute: doc['wake_up_time']['minute'] 39 | ), 40 | dailyTarget: doc['daily_target'] 41 | ); 42 | } 43 | toDoc(){ 44 | return { 45 | 'uid' : this.uid, 46 | 'google_id' : this.googleId, 47 | 'email' : this.email, 48 | 'name' : this.name, 49 | 'gender' : this.gender, 50 | 'birthday' : Timestamp.fromDate(this.birthday), 51 | 'weight' : this.weight, 52 | 'wake_up_time' : { 53 | 'hour' : this.wakeUpTime.hour, 54 | 'minute' : this.wakeUpTime.minute 55 | }, 56 | 'daily_target' : dailyTarget 57 | }; 58 | } 59 | } -------------------------------------------------------------------------------- /lib/models/weekly_data.dart: -------------------------------------------------------------------------------- 1 | // utils 2 | import '../utils/get_week.dart'; 3 | 4 | class WeeklyData { 5 | String id; 6 | int year; 7 | int month; 8 | int week; 9 | Map amounts; 10 | int dailyTarget; 11 | 12 | WeeklyData({ 13 | this.id,this.year,this.month,this.week,this.amounts,this.dailyTarget 14 | }); 15 | 16 | factory WeeklyData.fromDoc(Map doc){ 17 | Map rawAmounts = doc.containsKey('amounts') ? doc['amounts'] : {}; 18 | for(int i=1;i<=7;i++){ 19 | if(!rawAmounts.containsKey(i.toString())){ 20 | rawAmounts[i.toString()] = 0; 21 | } 22 | } 23 | return WeeklyData( 24 | id: doc['id'], 25 | year: doc['year'], 26 | month: doc['month'], 27 | week: doc['week'], 28 | amounts: rawAmounts, 29 | dailyTarget: doc['daily_target'] 30 | ); 31 | } 32 | 33 | 34 | Map createNewWeek(String id,int year,int month,int week,int target){ 35 | return { 36 | 'id' : id, 37 | 'year' : year, 38 | 'month' : month, 39 | 'week' : week, 40 | 'daily_target' : target 41 | }; 42 | } 43 | 44 | double totalThisWeek(){ 45 | double total = 0; 46 | amounts.forEach((key, value) { 47 | total+=value; 48 | }); 49 | return total; 50 | } 51 | 52 | int percentThisWeek(){ 53 | DateTime today = DateTime.now(); 54 | int thisWeek = getWeek(today); 55 | double max; 56 | if(thisWeek==this.week && today.year==this.year){ 57 | max = (dailyTarget*DateTime.now().weekday).toDouble(); 58 | }else{ 59 | max = (dailyTarget*7).toDouble(); 60 | } 61 | double total = totalThisWeek(); 62 | return ((total/max)*100).toInt(); 63 | } 64 | } -------------------------------------------------------------------------------- /lib/providers/auth_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:cloud_firestore/cloud_firestore.dart'; 3 | import 'package:firebase_auth/firebase_auth.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:google_sign_in/google_sign_in.dart'; 6 | 7 | // models 8 | import '../models/app_user.dart'; 9 | 10 | //utils 11 | import '../utils/notification_utils.dart'; 12 | 13 | class AuthProvider extends ChangeNotifier { 14 | FirebaseFirestore _firestore = FirebaseFirestore.instance; 15 | GoogleSignIn _googleSignIn = GoogleSignIn(); 16 | FirebaseAuth _firebaseAuth = FirebaseAuth.instance; 17 | 18 | GoogleSignInAccount get googleAcount => _googleSignIn.currentUser; 19 | 20 | User get user => _firebaseAuth.currentUser; 21 | 22 | Future selectGoogleAcount() async { 23 | try { 24 | await _googleSignIn.signOut(); 25 | GoogleSignInAccount googleAccount = await _googleSignIn.signIn(); 26 | QuerySnapshot querySnapshot = await _firestore.collection('users').where('google_id',isEqualTo: googleAccount.id).get(); 27 | List docs = querySnapshot.docs; 28 | if(docs.length==0){ 29 | return true; 30 | } 31 | QueryDocumentSnapshot userDoc = docs[0]; 32 | Map data = userDoc.data(); 33 | TimeOfDay wakeUpTime = TimeOfDay( 34 | hour: data['wake_up_time']['hour'], 35 | minute: data['wake_up_time']['minute'] 36 | ); 37 | await setDailyStartNotification(wakeUpTime,data['name']); 38 | return false; 39 | }catch(e){ 40 | print(e); 41 | return true; 42 | } 43 | } 44 | 45 | Future signIn() async { 46 | try{ 47 | if(_googleSignIn.currentUser!=null){ 48 | GoogleSignInAuthentication _googleSignInAuthentication = await _googleSignIn.currentUser.authentication; 49 | OAuthCredential _oAuthCredential = GoogleAuthProvider.credential( 50 | accessToken: _googleSignInAuthentication.accessToken, 51 | idToken: _googleSignInAuthentication.idToken 52 | ); 53 | await _firebaseAuth.signInWithCredential(_oAuthCredential); 54 | notifyListeners(); 55 | } 56 | }catch(e){ 57 | print(e); 58 | } 59 | } 60 | 61 | Future signUp(String gender,DateTime birthday,double weight,TimeOfDay time,int water) async { 62 | try{ 63 | await signIn(); 64 | User user = _firebaseAuth.currentUser; 65 | DocumentReference userRef = _firestore.collection('users').doc(user.uid); 66 | await userRef.set(AppUser( 67 | uid: user.uid, 68 | googleId: _googleSignIn.currentUser.id, 69 | email: user.email, 70 | name: user.displayName, 71 | gender: gender, 72 | birthday: birthday, 73 | weight: weight, 74 | wakeUpTime: time, 75 | dailyTarget: water 76 | ).toDoc()); 77 | await setDailyStartNotification(time,user.displayName); 78 | notifyListeners(); 79 | }catch(e){ 80 | print(e); 81 | } 82 | } 83 | 84 | void clearGoogleAccount()async{ 85 | await _googleSignIn.signOut(); 86 | notifyListeners(); 87 | } 88 | 89 | void signOut() async { 90 | await cancelAllNotifications(); 91 | await _googleSignIn.signOut(); 92 | await _firebaseAuth.signOut(); 93 | notifyListeners(); 94 | } 95 | } -------------------------------------------------------------------------------- /lib/providers/home_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:http/http.dart' as http; 3 | import 'package:location/location.dart'; 4 | import 'dart:convert'; 5 | import 'package:cloud_firestore/cloud_firestore.dart'; 6 | import 'package:firebase_auth/firebase_auth.dart'; 7 | 8 | // utils 9 | import '../utils/get_week.dart'; 10 | import '../utils/notification_utils.dart'; 11 | //values 12 | import '../values/api_key.dart'; 13 | 14 | // models 15 | import '../models/weekly_data.dart'; 16 | import '../models/app_user.dart'; 17 | 18 | 19 | class HomeProvider extends ChangeNotifier { 20 | FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance; 21 | Location _location = Location(); 22 | bool _isInited = false; 23 | DateTime _today = DateTime.now(); 24 | 25 | WeeklyData _weeklyData; 26 | String _uid; 27 | AppUser _appUser; 28 | 29 | CollectionReference _weekColRef; 30 | DocumentReference _userRef; 31 | DocumentReference _currentWeek; 32 | 33 | Map _weather; 34 | LocationData _locationData; 35 | 36 | void update(User user){ 37 | if(user!=null){ 38 | _uid = user.uid; 39 | _weekColRef = _firebaseFirestore.collection('users').doc(_uid).collection('weeks'); 40 | _userRef = _firebaseFirestore.collection('users').doc(_uid); 41 | }else{ 42 | _isInited = false; 43 | _uid = null; 44 | _weeklyData = null; 45 | _appUser = null; 46 | _weekColRef = null; 47 | _userRef = null; 48 | _currentWeek = null; 49 | _weather = null; 50 | _locationData = null; 51 | } 52 | notifyListeners(); 53 | } 54 | 55 | Map get weather => _weather; 56 | 57 | AppUser get appUser => _appUser; 58 | 59 | String get dailyTarget { 60 | int target = _appUser.dailyTarget; 61 | if(target<1000){ 62 | return '$target mL'; 63 | }else{ 64 | return '${(target/1000).toStringAsFixed(1)} L'; 65 | } 66 | } 67 | 68 | int get leftAmount { 69 | int target = _appUser.dailyTarget; 70 | int consumed = _weeklyData.amounts[_today.weekday.toString()].toInt(); 71 | int left = target-consumed; 72 | return left; 73 | } 74 | 75 | double get targetReached { 76 | int target = _appUser.dailyTarget; 77 | int consumed = _weeklyData.amounts[_today.weekday.toString()].toInt(); 78 | return consumed/target; 79 | } 80 | 81 | Future init()async{ 82 | if(_isInited==false){ 83 | try { 84 | int week = getWeek(_today); 85 | String docId = '${_today.year}_$week'; 86 | _currentWeek = _weekColRef.doc(docId); 87 | DocumentSnapshot userSnapshot = await _userRef.get(); 88 | _appUser = AppUser.fromDoc(userSnapshot.data()); 89 | DocumentSnapshot snapshot = await _currentWeek.get(); 90 | if(!snapshot.exists){ 91 | Map newWeek = WeeklyData().createNewWeek(docId,_today.year,_today.month,week,_appUser.dailyTarget); 92 | await _currentWeek.set(newWeek); 93 | _weeklyData = WeeklyData.fromDoc(newWeek); 94 | }else{ 95 | _weeklyData = WeeklyData.fromDoc(snapshot.data()); 96 | } 97 | _isInited = true; 98 | bool canGetLocation = await getLocationService(); 99 | if(canGetLocation){ 100 | _locationData = await _location.getLocation(); 101 | http.Response response = await http.get( 102 | 'https://api.openweathermap.org/data/2.5/weather?lat=${_locationData.latitude}&lon=${_locationData.longitude}&appid=${keys['openweather']}&units=metric' 103 | ); 104 | if(response.statusCode==200){ 105 | final weatherInfo = jsonDecode(response.body); 106 | _weather = weatherInfo['weather'][0]; 107 | } 108 | } 109 | notifyListeners(); 110 | }catch(e){ 111 | print(e); 112 | } 113 | }else{ 114 | print('Data already inited'); 115 | } 116 | } 117 | 118 | Future addWater(int amount,DateTime time) async { 119 | try{ 120 | int weekday = time.weekday; 121 | int week = getWeek(time); 122 | String weekId = '${time.year}_$week'; 123 | await _firebaseFirestore.runTransaction((transaction)async{ 124 | DocumentReference weekDocRef = _firebaseFirestore.collection('users').doc(_uid).collection('weeks').doc(weekId); 125 | DocumentReference yearDocRef = _firebaseFirestore.collection('users').doc(_uid).collection('years').doc('${time.year}'); 126 | DocumentReference monthDocRef = _firebaseFirestore.collection('users').doc(_uid).collection('months').doc('${time.year}_${time.month}'); 127 | DocumentSnapshot yearDocSnap = await transaction.get(yearDocRef); 128 | DocumentSnapshot monthDocSnap = await transaction.get(monthDocRef); 129 | DocumentSnapshot weekDocSnap = await transaction.get(weekDocRef); 130 | 131 | if(!yearDocSnap.exists){ 132 | transaction.set(yearDocRef, { 133 | 'year' : time.year 134 | },SetOptions(merge: true)); 135 | } 136 | 137 | if(!monthDocSnap.exists){ 138 | transaction.set(monthDocRef, { 139 | 'year' : time.year, 140 | 'month' : time.month 141 | },SetOptions(merge: true)); 142 | } 143 | 144 | if(!weekDocSnap.exists){ 145 | transaction.set(weekDocRef, { 146 | 'daily_target' : _appUser.dailyTarget, 147 | 'year' : time.year, 148 | 'month' : time.month, 149 | 'week' : week, 150 | 'id' : weekId, 151 | },SetOptions(merge: true)); 152 | } 153 | 154 | transaction.update(yearDocRef, { 155 | 'amounts.${time.month}' : FieldValue.increment(amount) 156 | }); 157 | 158 | transaction.update(monthDocRef, { 159 | 'amounts.${time.day}' : FieldValue.increment(amount) 160 | }); 161 | transaction.update(weekDocRef, { 162 | 'amounts.$weekday' : FieldValue.increment(amount) 163 | }); 164 | 165 | }); 166 | if(_weeklyData.id==weekId){ 167 | _weeklyData.amounts[weekday.toString()] += amount; 168 | if(weekday==DateTime.now().weekday){ 169 | if(leftAmount>0){ 170 | await waterNotification(leftAmount); 171 | } 172 | } 173 | notifyListeners(); 174 | } 175 | }catch(e){ 176 | print(e); 177 | } 178 | 179 | } 180 | 181 | Future getLocationService()async{ 182 | bool isServiceEnabled = await _location.serviceEnabled(); 183 | 184 | if(!isServiceEnabled){ 185 | bool _enabled = await _location.requestService(); 186 | if (_enabled) { 187 | }else{ 188 | return false; 189 | } 190 | } 191 | 192 | PermissionStatus permissionGranted = await _location.hasPermission(); 193 | if (permissionGranted == PermissionStatus.denied) { 194 | PermissionStatus _isGranted = await _location.requestPermission(); 195 | if (_isGranted != PermissionStatus.granted) { 196 | return false; 197 | } 198 | } 199 | return true; 200 | } 201 | 202 | Future updateUser(AppUser appUser)async{ 203 | try{ 204 | await _firebaseFirestore.runTransaction((transaction)async{ 205 | transaction.update(_currentWeek,{ 206 | 'daily_target' : appUser.dailyTarget 207 | }); 208 | transaction.update(_userRef, appUser.toDoc()); 209 | }); 210 | await setDailyStartNotification(appUser.wakeUpTime,appUser.name); 211 | _appUser = appUser; 212 | notifyListeners(); 213 | }catch(e){ 214 | print(e); 215 | } 216 | } 217 | } 218 | 219 | -------------------------------------------------------------------------------- /lib/providers/statistics_provider.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import '../models/weekly_data.dart'; 3 | import 'package:firebase_auth/firebase_auth.dart'; 4 | import 'package:cloud_firestore/cloud_firestore.dart'; 5 | 6 | class StatisticsProvider extends ChangeNotifier { 7 | FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance; 8 | String _uid; 9 | CollectionReference _weeksRef; 10 | 11 | List _weeklyData = []; 12 | 13 | List get weeklyData => [..._weeklyData]; 14 | 15 | void update(User user){ 16 | if(user!=null){ 17 | _uid = user.uid; 18 | _weeksRef = _firebaseFirestore.collection('users').doc(_uid).collection('weeks'); 19 | }else{ 20 | _uid = null; 21 | _weeksRef = null; 22 | _weeklyData.clear(); 23 | } 24 | } 25 | 26 | Future init() async { 27 | try { 28 | _weeklyData.clear(); 29 | QuerySnapshot snapshot = await _weeksRef.orderBy('id',descending: true).limit(4).get(); 30 | List docsSnap = snapshot.docs; 31 | docsSnap.forEach((docSnap) { 32 | _weeklyData.add(new WeeklyData.fromDoc(docSnap.data())); 33 | }); 34 | }catch(e){ 35 | print(e); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /lib/root.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:firebase_auth/firebase_auth.dart'; 4 | 5 | // providers 6 | import './providers/auth_provider.dart'; 7 | 8 | // screens 9 | import './screens/auth_screen.dart'; 10 | 11 | // widgets 12 | import './widgets/custom_drawer.dart'; 13 | 14 | class Root extends StatelessWidget { 15 | @override 16 | Widget build(BuildContext context) { 17 | return Consumer( 18 | builder: (context, authProvider, child) { 19 | User user = authProvider.user; 20 | if(user==null){ 21 | return AuthScreen(); 22 | } 23 | return CustomDrawer(); 24 | }, 25 | ); 26 | } 27 | } -------------------------------------------------------------------------------- /lib/screens/auth_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:google_sign_in/google_sign_in.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:google_fonts/google_fonts.dart'; 5 | import 'package:flutter/services.dart'; 6 | 7 | // providers 8 | import '../providers/auth_provider.dart'; 9 | 10 | // screens 11 | import '../screens/data_entry_screen.dart'; 12 | 13 | // widgets 14 | import '../widgets/custom_progress_indicator.dart'; 15 | 16 | 17 | class AuthScreen extends StatefulWidget { 18 | static const routeName = 'auth-screen'; 19 | 20 | @override 21 | _AuthScreenState createState() => _AuthScreenState(); 22 | } 23 | 24 | class _AuthScreenState extends State { 25 | bool _loading = false; 26 | 27 | @override 28 | void initState() { 29 | super.initState(); 30 | SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( 31 | statusBarColor: Colors.transparent, 32 | statusBarIconBrightness: Brightness.dark, 33 | )); 34 | } 35 | 36 | void toggleLoading(){ 37 | setState(() { 38 | _loading = !_loading; 39 | }); 40 | } 41 | 42 | void selectAccount(BuildContext ctx) async { 43 | toggleLoading(); 44 | bool newuser = await Provider.of(ctx,listen: false).selectGoogleAcount(); 45 | if(!newuser){ 46 | await Provider.of(ctx,listen: false).signIn(); 47 | }else{ 48 | toggleLoading(); 49 | } 50 | } 51 | 52 | @override 53 | Widget build(BuildContext context) { 54 | return Scaffold( 55 | body: Container( 56 | padding: EdgeInsets.fromLTRB(30, 0, 30, 30), 57 | child: Column( 58 | children: [ 59 | Expanded( 60 | child: Center( 61 | child: Column( 62 | mainAxisSize: MainAxisSize.min, 63 | children: [ 64 | Image.asset('assets/images/big_logo.png',height: 90,), 65 | SizedBox(height: 10,), 66 | Text( 67 | 'drinkable', 68 | style: GoogleFonts.pacifico( 69 | fontWeight: FontWeight.w500, 70 | fontSize: 26, 71 | color: Color.fromARGB(255, 0, 60, 192), 72 | ), 73 | ), 74 | SizedBox(height: 15,), 75 | Container( 76 | constraints: BoxConstraints( 77 | maxWidth: 250 78 | ), 79 | child: Text( 80 | 'Drinkable keeps track your daily water intake and reminds you to drink water by sending notification in intervals', 81 | textAlign: TextAlign.center, 82 | style: GoogleFonts.poppins( 83 | fontSize: 14, 84 | color: Colors.black.withOpacity(0.60) 85 | ) 86 | ), 87 | ), 88 | ], 89 | ), 90 | ), 91 | ), 92 | Column( 93 | mainAxisSize: MainAxisSize.min, 94 | children: [ 95 | _loading ? CustomProgressIndicatior() : Consumer( 96 | builder: (ctx, authProvider, child) { 97 | GoogleSignInAccount googleAccount = authProvider.googleAcount; 98 | return googleAccount!=null ? 99 | Row( 100 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 101 | children: [ 102 | CircleAvatar( 103 | backgroundImage: NetworkImage(googleAccount.photoUrl), 104 | ), 105 | FlatButton( 106 | child: Text('Continue as ${googleAccount.displayName}'), 107 | onPressed: (){ 108 | Navigator.of(context).pushNamed(DataEntryScreen.routeName); 109 | }, 110 | ), 111 | InkWell( 112 | splashColor: Colors.transparent, 113 | highlightColor: Colors.transparent, 114 | onTap: (){ 115 | Provider.of(ctx,listen: false).clearGoogleAccount(); 116 | }, 117 | child: Padding( 118 | padding: EdgeInsets.fromLTRB(10, 10, 0, 10), 119 | child: Icon(Icons.clear), 120 | ), 121 | ), 122 | ], 123 | ) : GestureDetector( 124 | onTap: (){ 125 | selectAccount(context); 126 | }, 127 | child: Card( 128 | elevation: 3, 129 | shape: RoundedRectangleBorder( 130 | borderRadius: BorderRadius.circular(10) 131 | ), 132 | color: Colors.blueAccent, 133 | child: Padding( 134 | padding: const EdgeInsets.symmetric(vertical: 8), 135 | child: Row( 136 | mainAxisAlignment: MainAxisAlignment.spaceAround, 137 | children: [ 138 | Container( 139 | padding: EdgeInsets.all(3), 140 | decoration: BoxDecoration( 141 | color: Colors.white, 142 | borderRadius: BorderRadius.circular(8) 143 | ), 144 | child: Image.asset('assets/icons/google.png',height: 20,) 145 | ), 146 | Text( 147 | 'Continue with Google', 148 | style:GoogleFonts.poppins( 149 | color: Colors.white, 150 | fontSize: 16, 151 | fontWeight: FontWeight.w500 152 | ), 153 | ) 154 | ], 155 | ), 156 | ), 157 | ), 158 | ); 159 | 160 | }, 161 | ), 162 | Container( 163 | padding: EdgeInsets.fromLTRB(20, 10, 20, 0), 164 | child: RichText( 165 | textAlign: TextAlign.center, 166 | text: TextSpan( 167 | style: GoogleFonts.poppins( 168 | color: Colors.black, 169 | fontSize: 11 170 | ), 171 | children: [ 172 | TextSpan( 173 | text: 'By signing up you accept the ', 174 | ), 175 | TextSpan( 176 | text: 'Terms of Service and Privacy Policy.', 177 | style: GoogleFonts.poppins( 178 | fontWeight: FontWeight.w500 179 | ) 180 | ) 181 | ] 182 | ), 183 | ) 184 | ) 185 | ], 186 | ) 187 | ], 188 | ), 189 | ), 190 | ); 191 | } 192 | } -------------------------------------------------------------------------------- /lib/screens/data_entry_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:google_sign_in/google_sign_in.dart'; 4 | import 'package:intl/intl.dart'; 5 | import 'package:google_fonts/google_fonts.dart'; 6 | 7 | // providers 8 | import '../providers/auth_provider.dart'; 9 | 10 | // utils 11 | import '../utils/time_converter.dart'; 12 | 13 | // widgets 14 | import '../widgets/custom_form_field.dart'; 15 | import '../widgets/custom_progress_indicator.dart'; 16 | 17 | 18 | 19 | class DataEntryScreen extends StatelessWidget { 20 | static const routeName = 'data-entry-screen'; 21 | @override 22 | Widget build(BuildContext context) { 23 | return Scaffold( 24 | body: Container( 25 | padding: EdgeInsets.fromLTRB(30,30, 30, 0), 26 | child: SingleChildScrollView( 27 | child: Column( 28 | children: [ 29 | Row( 30 | mainAxisAlignment: MainAxisAlignment.start, 31 | children: [ 32 | InkWell( 33 | onTap: (){ 34 | Navigator.of(context).pop(); 35 | }, 36 | child: Icon(Icons.arrow_back_ios) 37 | ) 38 | ], 39 | ), 40 | SizedBox(height: 20,), 41 | Column( 42 | children: [ 43 | Icon(Icons.date_range), 44 | SizedBox(height: 10,), 45 | Text('About you',style: GoogleFonts.poppins(fontSize: 22,fontWeight: FontWeight.w500),), 46 | SizedBox(height: 20,), 47 | Container( 48 | constraints: BoxConstraints( 49 | maxWidth: 270 50 | ), 51 | child: Text( 52 | 'This information will let us help to calculate your daily recommended water intake amount and remind you to drink water in intervals.', 53 | textAlign: TextAlign.center, 54 | style: GoogleFonts.poppins( 55 | fontSize: 14, 56 | color: Colors.black.withOpacity(0.60), 57 | height: 1.4, 58 | fontWeight: FontWeight.w400 59 | ), 60 | ), 61 | ), 62 | SizedBox(height: 30,), 63 | Consumer( 64 | builder: (context, authProvider, child) { 65 | GoogleSignInAccount googleAccount = authProvider.googleAcount; 66 | return Column( 67 | mainAxisSize: MainAxisSize.min, 68 | children: [ 69 | CircleAvatar( 70 | backgroundImage: NetworkImage(googleAccount.photoUrl), 71 | ), 72 | SizedBox(height: 15,), 73 | Text( 74 | '${googleAccount.email}', 75 | style: GoogleFonts.poppins( 76 | fontSize: 13 77 | ), 78 | ), 79 | ], 80 | ); 81 | }, 82 | ), 83 | ], 84 | ), 85 | SizedBox(height: 50,), 86 | DataEntryForm(), 87 | ], 88 | ), 89 | ), 90 | ), 91 | ); 92 | } 93 | } 94 | 95 | class DataEntryForm extends StatefulWidget { 96 | @override 97 | _DataEntryFormState createState() => _DataEntryFormState(); 98 | } 99 | 100 | class _DataEntryFormState extends State { 101 | bool _loading = false; 102 | GlobalKey _formKey = GlobalKey(); 103 | 104 | void toggleLoading(){ 105 | setState(() { 106 | _loading = !_loading; 107 | }); 108 | } 109 | 110 | // data 111 | String _gender = 'male'; 112 | DateTime _birthday = DateTime(1997,4,1); 113 | double _weight; 114 | TimeOfDay _wakeUpTime = TimeOfDay(hour: 8, minute: 0); 115 | int _water = 3200; 116 | 117 | 118 | void submit()async{ 119 | if(!_formKey.currentState.validate()){ 120 | return; 121 | } 122 | _formKey.currentState.save(); 123 | toggleLoading(); 124 | try{ 125 | await Provider.of(context,listen: false).signUp( 126 | _gender, 127 | _birthday, 128 | _weight, 129 | _wakeUpTime, 130 | _water 131 | ); 132 | Navigator.of(context).pop(); 133 | return; 134 | }catch(e){ 135 | print(e); 136 | } 137 | toggleLoading(); 138 | } 139 | 140 | void setWater({double weight}){ 141 | if(_weight!=null || weight!=null){ 142 | double calWater = weight!=null ? weight*2.205 : _weight*2.205; 143 | calWater = calWater/2.2; 144 | int age = DateTime.now().year-_birthday.year; 145 | if(age<30){ 146 | calWater = calWater*40; 147 | }else if(age>=30 && age<=55){ 148 | calWater = calWater*35; 149 | }else{ 150 | calWater = calWater*30; 151 | } 152 | calWater = calWater/28.3; 153 | calWater = calWater*29.574; 154 | setState(() { 155 | _water = calWater.toInt(); 156 | _weight = weight==null? _weight : weight; 157 | }); 158 | } 159 | } 160 | 161 | @override 162 | Widget build(BuildContext context) { 163 | return Form( 164 | key: _formKey, 165 | child: Column( 166 | mainAxisSize: MainAxisSize.min, 167 | children: [ 168 | Row( 169 | children: [ 170 | Expanded( 171 | flex: 47, 172 | child: CustomFormField( 173 | label: 'Gender', 174 | child: DropdownButtonFormField( 175 | value: _gender, 176 | items: >[ 177 | DropdownMenuItem( 178 | child: Text('Male',style: GoogleFonts.poppins( 179 | fontSize: 15, 180 | fontWeight: FontWeight.w500 181 | ),), 182 | value: 'male', 183 | ), 184 | DropdownMenuItem( 185 | child: Text('Female',style: GoogleFonts.poppins( 186 | fontSize: 15, 187 | fontWeight: FontWeight.w500 188 | ),), 189 | value: 'female', 190 | ), 191 | ], 192 | decoration: InputDecoration( 193 | border: InputBorder.none 194 | ), 195 | onChanged: (String gender){ 196 | setState(() { 197 | _gender = gender; 198 | }); 199 | }, 200 | ), 201 | ) 202 | ), 203 | Expanded( 204 | flex: 6, 205 | child: SizedBox(width: 20,) 206 | ), 207 | Expanded( 208 | flex: 47, 209 | child: GestureDetector( 210 | onTap: ()async{ 211 | DateTime date = await showDatePicker( 212 | context: context, 213 | initialDate:DateTime(1997,4,1), 214 | firstDate: DateTime(1960), 215 | lastDate: DateTime(DateTime.now().year-12,12,31), 216 | ); 217 | if(date!=null){ 218 | setState(() { 219 | _birthday = date; 220 | }); 221 | setWater(); 222 | } 223 | }, 224 | child: CustomFormField( 225 | label: 'Birthday', 226 | child: Row( 227 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 228 | children: [ 229 | Text( 230 | DateFormat.yMMMd('en_US').format(_birthday), 231 | style: GoogleFonts.poppins( 232 | fontSize: 15, 233 | fontWeight: FontWeight.w500 234 | ), 235 | ), 236 | Icon(Icons.arrow_drop_down) 237 | ], 238 | ) 239 | ), 240 | ) 241 | ), 242 | ], 243 | ), 244 | SizedBox(height: 15,), 245 | Row( 246 | children: [ 247 | Expanded( 248 | flex: 47, 249 | child: CustomFormField( 250 | label: 'Weight', 251 | child: TextFormField( 252 | decoration: InputDecoration( 253 | border: InputBorder.none, 254 | hintText: '60 kg', 255 | suffixText: 'kg', 256 | ), 257 | style: GoogleFonts.poppins( 258 | fontSize: 15, 259 | fontWeight: FontWeight.w500 260 | ), 261 | keyboardType: TextInputType.number, 262 | textInputAction: TextInputAction.done, 263 | validator: (String value){ 264 | if(value.isEmpty){ 265 | return 'Enter weight'; 266 | } 267 | if(double.parse(value)<40){ 268 | return 'You are underweight'; 269 | } 270 | return null; 271 | }, 272 | onChanged: (String value){ 273 | setWater(weight: double.parse(value)); 274 | }, 275 | ), 276 | ) 277 | ), 278 | Expanded( 279 | flex: 6, 280 | child: SizedBox(width: 20,), 281 | ), 282 | Expanded( 283 | flex: 47, 284 | child: GestureDetector( 285 | onTap: ()async{ 286 | TimeOfDay time = await showTimePicker( 287 | context: context, 288 | initialTime: TimeOfDay(hour: 8, minute: 0), 289 | ); 290 | if(time!=null){ 291 | setState(() { 292 | _wakeUpTime = time; 293 | }); 294 | } 295 | }, 296 | child: CustomFormField( 297 | label: 'Wakes Up', 298 | child: Row( 299 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 300 | children: [ 301 | Text( 302 | timeConverter(_wakeUpTime), 303 | style: GoogleFonts.poppins( 304 | fontSize: 15, 305 | fontWeight: FontWeight.w500 306 | ), 307 | ), 308 | Icon(Icons.arrow_drop_down) 309 | ], 310 | ) 311 | ), 312 | ) 313 | ), 314 | ], 315 | ), 316 | SizedBox(height: 15,), 317 | Row( 318 | mainAxisAlignment: MainAxisAlignment.end, 319 | children: [ 320 | Expanded( 321 | flex: 2, 322 | child: CustomFormField( 323 | label: 'Water', 324 | child: TextFormField( 325 | controller: TextEditingController(text: '$_water'), 326 | decoration: InputDecoration( 327 | border: InputBorder.none, 328 | hintText: '3200 mL', 329 | suffixText: 'mL', 330 | ), 331 | style: GoogleFonts.poppins( 332 | fontSize: 15, 333 | fontWeight: FontWeight.w500 334 | ), 335 | keyboardType: TextInputType.number, 336 | textInputAction: TextInputAction.done, 337 | validator: (String value){ 338 | if(value.isEmpty){ 339 | return 'Enter water amount'; 340 | } 341 | if(double.parse(value)<1600){ 342 | return 'Less than min water'; 343 | } 344 | return null; 345 | }, 346 | onSaved: (String value){ 347 | setState(() { 348 | _water = int.parse(value); 349 | }); 350 | }, 351 | ), 352 | ) 353 | ), 354 | Expanded( 355 | child: SizedBox(width: 0,), 356 | ), 357 | RaisedButton( 358 | elevation: 1, 359 | color: Color.fromARGB(255, 0, 60, 192), 360 | child: _loading ? SizedBox( 361 | height: 22,width: 22, 362 | child: CustomProgressIndicatior() 363 | ) : Text( 364 | 'Let\'t go', 365 | style: GoogleFonts.poppins( 366 | color: Colors.white, 367 | fontWeight: FontWeight.w500, 368 | fontSize: 13 369 | ), 370 | ), 371 | 372 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(3)), 373 | onPressed: (){ 374 | //toggleLoading(); 375 | submit(); 376 | }, 377 | ) 378 | ], 379 | ) 380 | ], 381 | ), 382 | ); 383 | } 384 | } -------------------------------------------------------------------------------- /lib/screens/home_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:firebase_auth/firebase_auth.dart'; 4 | import 'package:google_fonts/google_fonts.dart'; 5 | import 'package:intl/intl.dart'; 6 | 7 | // widgets 8 | import '../widgets/custom_app_bar.dart'; 9 | import '../widgets/goal_and_add.dart'; 10 | import '../widgets/weather_suggestion.dart'; 11 | import '../widgets/loading_screen.dart'; 12 | 13 | // providers 14 | import '../providers/home_provider.dart'; 15 | import '../providers/auth_provider.dart'; 16 | 17 | // models 18 | import '../models/app_user.dart'; 19 | 20 | // widgets 21 | import '../widgets/custom_progress_indicator.dart'; 22 | import '../widgets/custom_form_field.dart'; 23 | 24 | class HomeScreen extends StatefulWidget { 25 | final Function openDrawer; 26 | HomeScreen({ 27 | this.openDrawer 28 | }); 29 | @override 30 | _HomeScreenState createState() => _HomeScreenState(); 31 | } 32 | 33 | class _HomeScreenState extends State { 34 | bool _isLoading = false; 35 | @override 36 | void initState() { 37 | super.initState(); 38 | init(); 39 | } 40 | 41 | void toggleLoading(){ 42 | setState(() { 43 | _isLoading = !_isLoading; 44 | }); 45 | } 46 | 47 | void init() async { 48 | toggleLoading(); 49 | await Provider.of(context,listen: false).init(); 50 | toggleLoading(); 51 | } 52 | 53 | @override 54 | Widget build(BuildContext context) { 55 | return _isLoading ? LoadingScreen() : Scaffold( 56 | body: Container( 57 | padding: EdgeInsets.only(top: 30), 58 | child: SingleChildScrollView( 59 | child: Column( 60 | children: [ 61 | CustomAppBar( 62 | openDrawer: widget.openDrawer, 63 | trailing: Consumer( 64 | builder: (context, authProvider, child) { 65 | User user = authProvider.user; 66 | return CircleAvatar( 67 | radius: 19, 68 | backgroundImage: NetworkImage(user.photoURL), 69 | ); 70 | }, 71 | 72 | ), 73 | ), 74 | SizedBox(height: 40,), 75 | GoalAndAdd(), 76 | SizedBox(height: 15,), 77 | Padding( 78 | padding: const EdgeInsets.fromLTRB(30,0,30,20), 79 | child: WeatherSuggestion() 80 | ) 81 | ], 82 | ), 83 | ), 84 | ), 85 | floatingActionButton: FloatingActionButton( 86 | elevation: 3, 87 | backgroundColor: Color.fromARGB(255, 0, 60, 192), 88 | child: Icon(Icons.add,size: 30,), 89 | onPressed: (){ 90 | //Navigator.of(context).pushNamed(AddWaterScreen.routeName); 91 | showDialog( 92 | context: context, 93 | builder: (BuildContext ctx){ 94 | return AddWaterWidget(); 95 | } 96 | ); 97 | } 98 | ), 99 | ); 100 | } 101 | } 102 | 103 | class AddWaterWidget extends StatefulWidget { 104 | @override 105 | _AddWaterWidgetState createState() => _AddWaterWidgetState(); 106 | } 107 | 108 | class _AddWaterWidgetState extends State { 109 | bool _loading = false; 110 | GlobalKey _formKey = GlobalKey(); 111 | 112 | // data 113 | DateTime _time = DateTime.now(); 114 | int _water; 115 | 116 | void toggleLoading(){ 117 | setState(() { 118 | _loading = !_loading; 119 | }); 120 | } 121 | 122 | void submit()async{ 123 | if(!_formKey.currentState.validate()){ 124 | return; 125 | } 126 | _formKey.currentState.save(); 127 | toggleLoading(); 128 | try{ 129 | await Provider.of(context,listen: false).addWater(_water,_time); 130 | Navigator.of(context).pop(); 131 | return; 132 | }catch(e){ 133 | print(e); 134 | } 135 | toggleLoading(); 136 | } 137 | 138 | 139 | 140 | @override 141 | Widget build(BuildContext context) { 142 | AppUser appUser = Provider.of(context).appUser; 143 | return AlertDialog( 144 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), 145 | content: Column( 146 | mainAxisSize: MainAxisSize.min, 147 | children: [ 148 | SizedBox(height: 15,), 149 | Text('Add Water', 150 | style: GoogleFonts.poppins( 151 | fontSize: 14 152 | ), 153 | ), 154 | SizedBox(height: 20,), 155 | Form( 156 | key: _formKey, 157 | child: Column( 158 | mainAxisSize: MainAxisSize.min, 159 | children: [ 160 | GestureDetector( 161 | onTap: ()async{ 162 | DateTime date = await showDatePicker( 163 | context: context, 164 | initialDate:_time, 165 | firstDate: DateTime(1960), 166 | lastDate: _time, 167 | ); 168 | if(date!=null && date.isBefore(DateTime.now())){ 169 | setState(() { 170 | _time = date; 171 | }); 172 | } 173 | }, 174 | child: CustomFormField( 175 | label: 'Date', 176 | child: Row( 177 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 178 | children: [ 179 | Text( 180 | DateFormat.yMMMd('en_US').format(_time), 181 | style: GoogleFonts.poppins( 182 | fontSize: 15, 183 | fontWeight: FontWeight.w500 184 | ), 185 | ), 186 | Icon(Icons.arrow_drop_down) 187 | ], 188 | ) 189 | ), 190 | ), 191 | SizedBox(height: 10,), 192 | CustomFormField( 193 | label: 'Water', 194 | child: TextFormField( 195 | decoration: InputDecoration( 196 | border: InputBorder.none, 197 | hintText: '240 mL', 198 | suffixText: 'mL', 199 | ), 200 | style: GoogleFonts.poppins( 201 | fontSize: 15, 202 | fontWeight: FontWeight.w500 203 | ), 204 | keyboardType: TextInputType.number, 205 | textInputAction: TextInputAction.done, 206 | validator: (String value){ 207 | if(value.isEmpty){ 208 | return 'Enter water amount'; 209 | } 210 | if(double.parse(value)<=0){ 211 | return 'Wrong value'; 212 | } 213 | if(double.parse(value)>appUser.dailyTarget){ 214 | return 'Daily limit exceed'; 215 | } 216 | return null; 217 | }, 218 | onSaved: (String value){ 219 | setState(() { 220 | _water = int.parse(value); 221 | }); 222 | }, 223 | ), 224 | ), 225 | ], 226 | ), 227 | ) 228 | 229 | ], 230 | ), 231 | contentPadding: EdgeInsets.symmetric(horizontal: 15,vertical: 5), 232 | actions: [ 233 | FlatButton( 234 | textColor: Color.fromARGB(255, 0, 60, 192), 235 | child: Text('Cancel', 236 | style: GoogleFonts.poppins( 237 | fontSize: 13, 238 | fontWeight: FontWeight.w500 239 | ) 240 | ), 241 | onPressed: (){ 242 | Navigator.of(context).pop(); 243 | }, 244 | ), 245 | FlatButton( 246 | color: Color.fromARGB(255, 0, 60, 192), 247 | child: _loading ? SizedBox( 248 | height: 22,width: 22, 249 | child: CustomProgressIndicatior() 250 | ) : Text('Add', 251 | style: GoogleFonts.poppins( 252 | fontSize: 13, 253 | fontWeight: FontWeight.w500 254 | ) 255 | ), 256 | onPressed: submit, 257 | ), 258 | ], 259 | ); 260 | } 261 | } 262 | 263 | -------------------------------------------------------------------------------- /lib/screens/profile_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:firebase_auth/firebase_auth.dart'; 4 | import 'package:intl/intl.dart'; 5 | import 'package:google_fonts/google_fonts.dart'; 6 | 7 | // providers 8 | import '../providers/auth_provider.dart'; 9 | import '../providers/home_provider.dart'; 10 | 11 | // models 12 | import '../models/app_user.dart'; 13 | 14 | // widgets 15 | import '../widgets/custom_app_bar.dart'; 16 | import '../widgets/custom_form_field.dart'; 17 | import '../widgets/custom_progress_indicator.dart'; 18 | 19 | // utils 20 | import '../utils/time_converter.dart'; 21 | 22 | 23 | 24 | class ProfileScreen extends StatelessWidget { 25 | final Function openDrawer; 26 | ProfileScreen({ 27 | this.openDrawer 28 | }); 29 | @override 30 | Widget build(BuildContext context) { 31 | return Scaffold( 32 | body: Container( 33 | padding: EdgeInsets.only(top: 30), 34 | child: SingleChildScrollView( 35 | child: Column( 36 | children: [ 37 | CustomAppBar(openDrawer: openDrawer), 38 | Consumer( 39 | builder: (context, homeProvider, child) { 40 | AppUser appUser = homeProvider.appUser; 41 | return Padding( 42 | padding: const EdgeInsets.symmetric(horizontal: 30,vertical: 20), 43 | child: Column( 44 | children: [ 45 | Row( 46 | crossAxisAlignment: CrossAxisAlignment.center, 47 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 48 | children: [ 49 | Column( 50 | crossAxisAlignment: CrossAxisAlignment.start, 51 | children: [ 52 | Text( 53 | appUser.name, 54 | style: GoogleFonts.poppins( 55 | fontSize: 19, 56 | fontWeight: FontWeight.w500 57 | ), 58 | ), 59 | SizedBox(height: 5,), 60 | Text( 61 | appUser.email, 62 | style: GoogleFonts.poppins( 63 | fontSize: 14, 64 | ), 65 | ) 66 | ], 67 | ), 68 | Consumer( 69 | builder: (context, authProvider, child) { 70 | User user = authProvider.user; 71 | return CircleAvatar( 72 | radius: 35, 73 | backgroundImage: NetworkImage(user.photoURL), 74 | ); 75 | }, 76 | ), 77 | ], 78 | ), 79 | SizedBox(height: 50,), 80 | DataEntryForm(appUser) 81 | ], 82 | ), 83 | ); 84 | }, 85 | ) 86 | ], 87 | ), 88 | ), 89 | ), 90 | ); 91 | } 92 | } 93 | 94 | class DataEntryForm extends StatefulWidget { 95 | final AppUser appUser; 96 | DataEntryForm(this.appUser); 97 | @override 98 | _DataEntryFormState createState() => _DataEntryFormState(); 99 | } 100 | 101 | class _DataEntryFormState extends State { 102 | TextEditingController _textEditingController; 103 | AppUser _appUser; 104 | bool _loading = false; 105 | GlobalKey _formKey = GlobalKey(); 106 | 107 | @override 108 | void initState() { 109 | super.initState(); 110 | _appUser = AppUser.fromDoc(widget.appUser.toDoc()); 111 | _textEditingController = TextEditingController(text: _appUser.dailyTarget.toString()); 112 | } 113 | 114 | void toggleLoading(){ 115 | setState(() { 116 | _loading = !_loading; 117 | }); 118 | } 119 | 120 | void submit()async{ 121 | if(!_formKey.currentState.validate()){ 122 | return; 123 | } 124 | _formKey.currentState.save(); 125 | toggleLoading(); 126 | try{ 127 | await Provider.of(context,listen: false).updateUser(_appUser); 128 | }catch(e){ 129 | print(e); 130 | } 131 | toggleLoading(); 132 | } 133 | 134 | void setWater({double weight}){ 135 | if(_appUser.weight!=null || weight!=null){ 136 | double calWater = weight!=null ? weight*2.205 : _appUser.weight*2.205; 137 | calWater = calWater/2.2; 138 | int age = DateTime.now().year-_appUser.birthday.year; 139 | if(age<30){ 140 | calWater = calWater*40; 141 | }else if(age>=30 && age<=55){ 142 | calWater = calWater*35; 143 | }else{ 144 | calWater = calWater*30; 145 | } 146 | calWater = calWater/28.3; 147 | calWater = calWater*29.574; 148 | setState(() { 149 | _appUser.dailyTarget= calWater.toInt(); 150 | _appUser.weight = weight==null? _appUser.weight : weight; 151 | _textEditingController.text = _appUser.dailyTarget.toString(); 152 | }); 153 | } 154 | } 155 | 156 | @override 157 | Widget build(BuildContext context) { 158 | return Form( 159 | key: _formKey, 160 | child: Column( 161 | mainAxisSize: MainAxisSize.min, 162 | children: [ 163 | Row( 164 | children: [ 165 | Expanded( 166 | flex: 47, 167 | child: CustomFormField( 168 | label: 'Gender', 169 | child: DropdownButtonFormField( 170 | value: _appUser.gender, 171 | items: >[ 172 | DropdownMenuItem( 173 | child: Text('Male',style: GoogleFonts.poppins( 174 | fontSize: 15, 175 | fontWeight: FontWeight.w500 176 | ),), 177 | value: 'male', 178 | ), 179 | DropdownMenuItem( 180 | child: Text('Female',style: GoogleFonts.poppins( 181 | fontSize: 15, 182 | fontWeight: FontWeight.w500 183 | ),), 184 | value: 'female', 185 | ), 186 | ], 187 | decoration: InputDecoration( 188 | border: InputBorder.none 189 | ), 190 | onChanged: (String gender){ 191 | setState(() { 192 | _appUser.gender = gender; 193 | }); 194 | }, 195 | ), 196 | ) 197 | ), 198 | Expanded( 199 | flex: 6, 200 | child: SizedBox(width: 20,) 201 | ), 202 | Expanded( 203 | flex: 47, 204 | child: GestureDetector( 205 | onTap: ()async{ 206 | DateTime date = await showDatePicker( 207 | context: context, 208 | initialDate:_appUser.birthday, 209 | firstDate: DateTime(1960), 210 | lastDate: DateTime(DateTime.now().year-12,12,31), 211 | ); 212 | if(date!=null){ 213 | setState(() { 214 | _appUser.birthday = date; 215 | }); 216 | setWater(); 217 | } 218 | }, 219 | child: CustomFormField( 220 | label: 'Birthday', 221 | child: Row( 222 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 223 | children: [ 224 | Text( 225 | DateFormat.yMMMd('en_US').format(_appUser.birthday), 226 | style: GoogleFonts.poppins( 227 | fontSize: 15, 228 | fontWeight: FontWeight.w500 229 | ), 230 | ), 231 | Icon(Icons.arrow_drop_down) 232 | ], 233 | ) 234 | ), 235 | ) 236 | ), 237 | ], 238 | ), 239 | SizedBox(height: 15,), 240 | Row( 241 | children: [ 242 | Expanded( 243 | flex: 47, 244 | child: CustomFormField( 245 | label: 'Weight', 246 | child: TextFormField( 247 | initialValue: _appUser.weight.toString(), 248 | decoration: InputDecoration( 249 | border: InputBorder.none, 250 | hintText: '60 kg', 251 | suffixText: 'kg', 252 | ), 253 | style: GoogleFonts.poppins( 254 | fontSize: 15, 255 | fontWeight: FontWeight.w500 256 | ), 257 | keyboardType: TextInputType.number, 258 | textInputAction: TextInputAction.done, 259 | validator: (String value){ 260 | if(value.isEmpty){ 261 | return 'Enter weight'; 262 | } 263 | if(double.parse(value)<40){ 264 | return 'You are underweight'; 265 | } 266 | return null; 267 | }, 268 | onChanged: (String value){ 269 | setWater(weight: double.parse(value)); 270 | }, 271 | ), 272 | ) 273 | ), 274 | Expanded( 275 | flex: 6, 276 | child: SizedBox(width: 20,), 277 | ), 278 | Expanded( 279 | flex: 47, 280 | child: GestureDetector( 281 | onTap: ()async{ 282 | TimeOfDay time = await showTimePicker( 283 | context: context, 284 | initialTime: TimeOfDay(hour: 8, minute: 0), 285 | ); 286 | if(time!=null){ 287 | setState(() { 288 | _appUser.wakeUpTime = time; 289 | }); 290 | } 291 | }, 292 | child: CustomFormField( 293 | label: 'Wakes Up', 294 | child: Row( 295 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 296 | children: [ 297 | Text( 298 | timeConverter(_appUser.wakeUpTime), 299 | style: GoogleFonts.poppins( 300 | fontSize: 15, 301 | fontWeight: FontWeight.w500 302 | ), 303 | ), 304 | Icon(Icons.arrow_drop_down) 305 | ], 306 | ) 307 | ), 308 | ) 309 | ), 310 | ], 311 | ), 312 | SizedBox(height: 15,), 313 | Row( 314 | mainAxisAlignment: MainAxisAlignment.end, 315 | children: [ 316 | Expanded( 317 | flex: 2, 318 | child: CustomFormField( 319 | label: 'Water', 320 | child: TextFormField( 321 | controller: _textEditingController, 322 | decoration: InputDecoration( 323 | border: InputBorder.none, 324 | hintText: '3200 mL', 325 | suffixText: 'mL', 326 | ), 327 | style: GoogleFonts.poppins( 328 | fontSize: 15, 329 | fontWeight: FontWeight.w500 330 | ), 331 | keyboardType: TextInputType.number, 332 | textInputAction: TextInputAction.done, 333 | validator: (String value){ 334 | if(value.isEmpty){ 335 | return 'Enter water amount'; 336 | } 337 | if(double.parse(value)<1600){ 338 | return 'Less than min water'; 339 | } 340 | return null; 341 | }, 342 | onChanged: (String value){ 343 | setState(() { 344 | _appUser.dailyTarget = int.parse(value); 345 | }); 346 | }, 347 | ), 348 | ) 349 | ), 350 | Expanded( 351 | child: SizedBox(width: 0,), 352 | ), 353 | RaisedButton( 354 | elevation: 1, 355 | color: Color.fromARGB(255, 0, 60, 192), 356 | 357 | child: _loading ? SizedBox( 358 | height: 22,width: 22, 359 | child: CustomProgressIndicatior() 360 | ) : Text( 361 | 'Update', 362 | style: GoogleFonts.poppins( 363 | color: Colors.white, 364 | fontWeight: FontWeight.w400, 365 | fontSize: 12 366 | ), 367 | ), 368 | 369 | shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(3)), 370 | onPressed: (){ 371 | //toggleLoading(); 372 | submit(); 373 | }, 374 | ) 375 | ], 376 | ) 377 | ], 378 | ), 379 | ); 380 | } 381 | } -------------------------------------------------------------------------------- /lib/screens/scatistics_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:firebase_auth/firebase_auth.dart'; 4 | import 'package:google_fonts/google_fonts.dart'; 5 | 6 | 7 | // providers 8 | import '../providers/auth_provider.dart'; 9 | import '../providers/statistics_provider.dart'; 10 | 11 | // models 12 | import '../models/weekly_data.dart'; 13 | 14 | // widgets 15 | import '../widgets/custom_app_bar.dart'; 16 | import '../widgets/weekly_statistics_graph.dart'; 17 | import '../widgets/custom_progress_indicator.dart'; 18 | import '../widgets/three_layer_background.dart'; 19 | 20 | 21 | 22 | class StatisticsScreen extends StatefulWidget { 23 | final Function openDrawer; 24 | StatisticsScreen({ 25 | this.openDrawer 26 | }); 27 | 28 | @override 29 | _StatisticsScreenState createState() => _StatisticsScreenState(); 30 | } 31 | 32 | class _StatisticsScreenState extends State { 33 | bool _loading = false; 34 | 35 | @override 36 | void initState() { 37 | super.initState(); 38 | init(); 39 | } 40 | 41 | void toggleLoading(){ 42 | setState(() { 43 | _loading = !_loading; 44 | }); 45 | } 46 | 47 | void init() async { 48 | toggleLoading(); 49 | await Provider.of(context,listen: false).init(); 50 | toggleLoading(); 51 | } 52 | 53 | @override 54 | Widget build(BuildContext context) { 55 | return Scaffold( 56 | body: Container( 57 | padding: EdgeInsets.only(top: 30), 58 | child: _loading ? Center(child: CustomProgressIndicatior(),) : Column( 59 | children: [ 60 | CustomAppBar( 61 | openDrawer: widget.openDrawer, 62 | trailing: Consumer( 63 | builder: (context, authProvider, child) { 64 | User user = authProvider.user; 65 | return CircleAvatar( 66 | radius: 19, 67 | backgroundImage: NetworkImage(user.photoURL), 68 | ); 69 | }, 70 | 71 | ), 72 | ), 73 | Container( 74 | padding: EdgeInsets.fromLTRB(30, 25, 30, 30), 75 | alignment: Alignment.centerLeft, 76 | child: Text( 77 | 'Statistics', 78 | textAlign: TextAlign.left, 79 | style: GoogleFonts.poppins( 80 | color: Color.fromARGB(255, 0, 60, 192), 81 | fontSize: 25, 82 | letterSpacing: 1, 83 | fontWeight: FontWeight.w500 84 | ), 85 | ), 86 | ), 87 | //SizedBox(height: 30,), 88 | Expanded( 89 | child: Stack( 90 | children: [ 91 | ThreeLayerBackground(), 92 | Consumer( 93 | builder: (context, statisticsProvider, child) { 94 | List weeklyData = statisticsProvider.weeklyData; 95 | return ListView.separated( 96 | padding: EdgeInsets.fromLTRB(30, 40, 30, 40), 97 | itemCount: weeklyData.length, 98 | itemBuilder: (context, index) { 99 | return WeeklyStatisticsGraph(weeklyData[index]); 100 | }, 101 | separatorBuilder: (context, index) { 102 | return SizedBox(height: 20,); 103 | }, 104 | ); 105 | }, 106 | ), 107 | ], 108 | ), 109 | ) 110 | ], 111 | ), 112 | ), 113 | ); 114 | } 115 | } -------------------------------------------------------------------------------- /lib/utils/get_week.dart: -------------------------------------------------------------------------------- 1 | int getWeek(DateTime date){ 2 | int year = date.year; 3 | DateTime stateDate = DateTime(year,1,1); 4 | int weekday = stateDate.weekday; 5 | int days = date.difference(stateDate).inDays; 6 | int week = ((weekday+days)/7).ceil(); 7 | return week; 8 | } -------------------------------------------------------------------------------- /lib/utils/notification_utils.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_local_notifications/flutter_local_notifications.dart'; 3 | import 'dart:typed_data'; 4 | 5 | NotificationDetails getNotificationDetails(){ 6 | AndroidNotificationDetails android = AndroidNotificationDetails( 7 | 'channel_id', 8 | 'channel_name', 9 | 'channel_description', 10 | 11 | visibility: NotificationVisibility.Public, 12 | priority: Priority.Max, 13 | importance: Importance.Max, 14 | 15 | ledColor: const Color.fromARGB(255,0, 200, 255), 16 | ledOffMs: 500, 17 | ledOnMs: 300, 18 | 19 | enableLights: true, 20 | 21 | color: Colors.blue, 22 | 23 | additionalFlags: Int32List.fromList([8]), 24 | category: 'reminder', 25 | 26 | playSound: true, 27 | sound: RawResourceAndroidNotificationSound('notification_sound'), 28 | 29 | enableVibration: true, 30 | vibrationPattern: Int64List.fromList([0,1000,1000,1000]), 31 | ); 32 | IOSNotificationDetails ios = IOSNotificationDetails(); 33 | NotificationDetails details = NotificationDetails(android, ios); 34 | return details; 35 | } 36 | 37 | Future setDailyStartNotification(TimeOfDay time, String user)async{ 38 | try{ 39 | FlutterLocalNotificationsPlugin plugin = FlutterLocalNotificationsPlugin(); 40 | NotificationDetails notificationDetails = getNotificationDetails(); 41 | await plugin.cancel(0); 42 | await plugin.showDailyAtTime( 43 | 0, 44 | "Good morning, $user", 45 | "Don't forget to dring enough water today", 46 | Time(time.hour,time.minute), 47 | notificationDetails 48 | ); 49 | }catch(e){ 50 | print(e); 51 | } 52 | } 53 | 54 | Future waterNotification(int left)async { 55 | try{ 56 | FlutterLocalNotificationsPlugin plugin = FlutterLocalNotificationsPlugin(); 57 | NotificationDetails notificationDetails = getNotificationDetails(); 58 | await plugin.cancel(1); 59 | await plugin.schedule( 60 | 1, 61 | "Hey, it's time to drink water", 62 | "$left mL water left to drink today", 63 | DateTime.now().add(Duration(hours: 1,minutes: 30)), 64 | notificationDetails 65 | ); 66 | }catch(e){ 67 | print(e); 68 | } 69 | } 70 | 71 | 72 | Future cancelAllNotifications() async{ 73 | try{ 74 | FlutterLocalNotificationsPlugin plugin = FlutterLocalNotificationsPlugin(); 75 | await plugin.cancelAll(); 76 | }catch(e){ 77 | print(e); 78 | } 79 | } -------------------------------------------------------------------------------- /lib/utils/time_converter.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | String timeConverter(TimeOfDay time) { 4 | int hour = time.hourOfPeriod == 0 ? 12 : time.hourOfPeriod; 5 | int min = time.minute; 6 | DayPeriod period = time.period; 7 | String formatedTime = ''; 8 | if(hour<10){ 9 | formatedTime += '0$hour:'; 10 | }else{ 11 | formatedTime += '$hour:'; 12 | } 13 | 14 | if(min<9){ 15 | formatedTime += '0$min '; 16 | }else{ 17 | formatedTime += '$min '; 18 | } 19 | 20 | if(period==DayPeriod.am){ 21 | formatedTime += 'AM'; 22 | }else{ 23 | formatedTime += 'PM'; 24 | } 25 | return formatedTime; 26 | } -------------------------------------------------------------------------------- /lib/values/months.dart: -------------------------------------------------------------------------------- 1 | Map months = { 2 | DateTime.january : 'Jan', 3 | DateTime.february : 'Feb', 4 | DateTime.march : 'Mar', 5 | DateTime.april : 'Apr', 6 | DateTime.may : 'May', 7 | DateTime.june : 'Jun', 8 | DateTime.july : 'Jul', 9 | DateTime.august : 'Aug', 10 | DateTime.september : 'Sep', 11 | DateTime.october : 'Oct', 12 | DateTime.november : 'Nov', 13 | DateTime.december : 'Dec', 14 | }; -------------------------------------------------------------------------------- /lib/values/weather_icons.dart: -------------------------------------------------------------------------------- 1 | Map weatherIcons = { 2 | '01' : 'assets/icons/01.png', 3 | '02' : 'assets/icons/02.png', 4 | '03' : 'assets/icons/03.png', 5 | '04' : 'assets/icons/04.png', 6 | '09' : 'assets/icons/09.png', 7 | '10' : 'assets/icons/10.png', 8 | '11' : 'assets/icons/11.png', 9 | '13' : 'assets/icons/13.png', 10 | '50' : 'assets/icons/50.png', 11 | }; -------------------------------------------------------------------------------- /lib/values/weekdays.dart: -------------------------------------------------------------------------------- 1 | Map weekdays = { 2 | DateTime.monday : 'Mon', 3 | DateTime.tuesday : 'Tue', 4 | DateTime.wednesday : 'Wed', 5 | DateTime.thursday : 'Thu', 6 | DateTime.friday : 'Fri', 7 | DateTime.saturday : 'Sat', 8 | DateTime.sunday : 'Sun', 9 | }; 10 | 11 | // Map weekdays = { 12 | // DateTime.monday : 'Monday', 13 | // DateTime.tuesday : 'Tuesday', 14 | // DateTime.wednesday : 'Wednesday', 15 | // DateTime.thursday : 'Thursday', 16 | // DateTime.friday : 'Friday', 17 | // DateTime.saturday : 'Saturday', 18 | // DateTime.sunday : 'Sunday', 19 | // }; -------------------------------------------------------------------------------- /lib/widgets/custom_app_bar.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:google_fonts/google_fonts.dart'; 3 | 4 | class CustomAppBar extends StatelessWidget { 5 | final Function openDrawer; 6 | final Widget trailing; 7 | CustomAppBar({this.openDrawer,this.trailing}); 8 | @override 9 | Widget build(BuildContext context) { 10 | 11 | return Padding( 12 | padding: const EdgeInsets.symmetric(horizontal: 30), 13 | child: Row( 14 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 15 | children: [ 16 | MenuButton(openDrawer), 17 | Row( 18 | mainAxisSize: MainAxisSize.min, 19 | children: [ 20 | Image.asset('assets/icons/logo.png',height: 20,), 21 | SizedBox(width: 12,), 22 | //Text('Drinkable',style: GoogleFonts.poppins(fontWeight: FontWeight.w600,fontSize: 17),) 23 | Text( 24 | 'drinkable', 25 | style: GoogleFonts.pacifico( 26 | fontWeight: FontWeight.w500, 27 | fontSize: 18, 28 | color: Color.fromARGB(255, 0, 60, 192), 29 | ), 30 | ) 31 | ], 32 | ), 33 | trailing==null ? CircleAvatar(radius: 19,backgroundColor: Colors.transparent,) : trailing 34 | ], 35 | ), 36 | ); 37 | } 38 | } 39 | 40 | class MenuButton extends StatelessWidget { 41 | final Function onTap; 42 | MenuButton(this.onTap); 43 | @override 44 | Widget build(BuildContext context) { 45 | return InkWell( 46 | borderRadius: BorderRadius.circular(4), 47 | onTap: onTap, 48 | child: Container( 49 | width: 40, 50 | height: 40, 51 | alignment: Alignment.center, 52 | decoration: BoxDecoration( 53 | border: Border.all( 54 | color: Colors.grey[300], 55 | width: 1.1, 56 | ), 57 | borderRadius: BorderRadius.circular(4) 58 | ), 59 | child: Column( 60 | crossAxisAlignment: CrossAxisAlignment.start, 61 | mainAxisSize: MainAxisSize.min, 62 | children: [ 63 | Container( 64 | width: 11, 65 | height: 2, 66 | decoration: BoxDecoration( 67 | color: Colors.black, 68 | borderRadius: BorderRadius.circular(2) 69 | ), 70 | ), 71 | SizedBox(height: 4,), 72 | Container( 73 | width: 16, 74 | height: 2, 75 | decoration: BoxDecoration( 76 | color: Colors.black, 77 | borderRadius: BorderRadius.circular(2) 78 | ), 79 | ), 80 | ], 81 | ), 82 | ), 83 | ); 84 | } 85 | } -------------------------------------------------------------------------------- /lib/widgets/custom_drawer.dart: -------------------------------------------------------------------------------- 1 | import 'package:google_fonts/google_fonts.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:provider/provider.dart'; 4 | import 'package:flutter/services.dart'; 5 | import 'package:firebase_auth/firebase_auth.dart'; 6 | 7 | // providers 8 | import '../providers/auth_provider.dart'; 9 | 10 | // screens 11 | import '../screens/profile_screen.dart'; 12 | import '../screens/home_screen.dart'; 13 | import '../screens/scatistics_screen.dart'; 14 | 15 | class CustomDrawer extends StatefulWidget { 16 | static const routeName = 'drawer'; 17 | @override 18 | _CustomDrawerState createState() => _CustomDrawerState(); 19 | } 20 | 21 | class _CustomDrawerState extends State with SingleTickerProviderStateMixin { 22 | bool _isDrawerOpened = false; 23 | int screen = 0; 24 | AnimationController _animationController; 25 | @override 26 | void initState() { 27 | super.initState(); 28 | _animationController = AnimationController( 29 | vsync: this, 30 | duration: Duration(milliseconds: 350), 31 | ); 32 | changeStatusBar(false); 33 | } 34 | 35 | void changeStatusBar(bool isOpened){ 36 | if(isOpened){ 37 | SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( 38 | statusBarColor: Colors.transparent, 39 | statusBarIconBrightness: Brightness.light 40 | )); 41 | }else{ 42 | SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( 43 | statusBarColor: Colors.transparent, 44 | statusBarIconBrightness: Brightness.dark, 45 | )); 46 | } 47 | } 48 | 49 | void open(){ 50 | changeStatusBar(true); 51 | _animationController.forward(); 52 | setState(() { 53 | _isDrawerOpened = true; 54 | }); 55 | } 56 | 57 | void close()async{ 58 | await _animationController.reverse(); 59 | changeStatusBar(false); 60 | setState(() { 61 | _isDrawerOpened = false; 62 | }); 63 | } 64 | 65 | void selectItem(int index){ 66 | if(index!=screen){ 67 | setState(() { 68 | screen = index; 69 | }); 70 | } 71 | close(); 72 | } 73 | 74 | 75 | @override 76 | Widget build(BuildContext context) { 77 | List screens = [ 78 | HomeScreen(openDrawer: open,), 79 | StatisticsScreen(openDrawer: open,), 80 | ProfileScreen(openDrawer: open,) 81 | ]; 82 | Size size = MediaQuery.of(context).size; 83 | return Scaffold( 84 | backgroundColor: Color.fromARGB(255,0, 11, 33), 85 | body: Stack( 86 | children: [ 87 | Container( 88 | padding: EdgeInsets.symmetric( 89 | vertical: 35 90 | ), 91 | child: Column( 92 | children: [ 93 | Padding( 94 | padding: const EdgeInsets.symmetric(horizontal: 25), 95 | child: Row( 96 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 97 | children: [ 98 | Consumer( 99 | builder: (context, value, child) { 100 | User user = value.user; 101 | return Row( 102 | mainAxisSize: MainAxisSize.min, 103 | children: [ 104 | CircleAvatar( 105 | radius: 20, 106 | backgroundImage: NetworkImage(user.photoURL), 107 | ), 108 | SizedBox(width: 10,), 109 | Column( 110 | crossAxisAlignment: CrossAxisAlignment.start, 111 | children: [ 112 | Text('Hello',style: GoogleFonts.poppins(color: Colors.white54,fontSize: 14),), 113 | SizedBox(height: 1,), 114 | Text(user.displayName.split(' ')[0],style: GoogleFonts.poppins(color: Colors.white,fontSize: 17,fontWeight: FontWeight.w500)) 115 | ], 116 | ) 117 | ], 118 | ); 119 | }, 120 | ), 121 | IconButton( 122 | icon: Icon(Icons.close,color: Colors.white60,size: 20,), 123 | onPressed: close, 124 | ) 125 | ], 126 | ), 127 | ), 128 | Expanded( 129 | child: ListView( 130 | padding: EdgeInsets.only(top: 40), 131 | children: [ 132 | MenuItem( 133 | icon: Icons.home, 134 | title: 'Home', 135 | onTap: (){ 136 | selectItem(0); 137 | }, 138 | ), 139 | MenuItem( 140 | icon: Icons.show_chart, 141 | title: 'Statistics', 142 | onTap: (){ 143 | selectItem(1); 144 | }, 145 | ), 146 | MenuItem( 147 | icon: Icons.account_circle, 148 | title: 'Profile', 149 | onTap: (){ 150 | selectItem(2); 151 | }, 152 | ), 153 | 154 | MenuItem( 155 | icon: Icons.exit_to_app, 156 | title: 'Log Out', 157 | onTap: (){ 158 | Provider.of(context,listen: false).signOut(); 159 | }, 160 | ), 161 | ], 162 | ), 163 | ) 164 | ], 165 | ), 166 | ), 167 | AnimatedBuilder( 168 | animation: _animationController, 169 | builder: (context, child) { 170 | return Transform( 171 | transform: Matrix4.identity() 172 | ..scale(1.0-(0.2*_animationController.value)) 173 | ..translate(0.0,size.height*0.80*_animationController.value,0.0) 174 | ..setEntry(3, 2, 0.002) 175 | ..rotateX(0.15*_animationController.value), 176 | origin: Offset(0,0), 177 | alignment: Alignment.center, 178 | 179 | // comment the child and uncomment the commented child to get the curved app drawer 180 | child: child, 181 | // child: ClipRRect( 182 | // borderRadius: BorderRadius.circular(20*_animationController.value), 183 | // child: AbsorbPointer( 184 | // absorbing: _isDrawerOpened, 185 | // child: screens[screen], 186 | // ), 187 | // ) 188 | ); 189 | }, 190 | child: AbsorbPointer( 191 | absorbing: _isDrawerOpened, 192 | child: screens[screen], 193 | ) 194 | ) 195 | ] 196 | ), 197 | ); 198 | } 199 | } 200 | 201 | class MenuItem extends StatelessWidget { 202 | final IconData icon; 203 | final String title; 204 | final Function onTap; 205 | MenuItem({this.icon,this.title,this.onTap}); 206 | @override 207 | Widget build(BuildContext context) { 208 | return InkWell( 209 | onTap: this.onTap, 210 | child: Container( 211 | padding: const EdgeInsets.symmetric(vertical: 13,horizontal: 35), 212 | child: Row( 213 | children: [ 214 | Icon(this.icon,color: Colors.white,size: 21,), 215 | SizedBox(width: 15,), 216 | Text(this.title,style: GoogleFonts.poppins(color: Colors.white,fontSize: 14),), 217 | ], 218 | ), 219 | ), 220 | ); 221 | } 222 | } -------------------------------------------------------------------------------- /lib/widgets/custom_form_field.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:google_fonts/google_fonts.dart'; 3 | 4 | 5 | class CustomFormField extends StatelessWidget { 6 | final String label; 7 | final Widget child; 8 | CustomFormField({this.child,this.label}); 9 | @override 10 | Widget build(BuildContext context) { 11 | return Container( 12 | height: 60, 13 | child: Stack( 14 | children: [ 15 | Container( 16 | width: double.infinity, 17 | height: double.infinity, 18 | margin: EdgeInsets.only(top: 6), 19 | padding: EdgeInsets.symmetric(horizontal: 12), 20 | decoration: BoxDecoration( 21 | border: Border.all(color: Colors.black.withOpacity(0.3),width: 1.1), 22 | borderRadius: BorderRadius.circular(4) 23 | ), 24 | alignment: Alignment.centerLeft, 25 | child: child 26 | ), 27 | Positioned( 28 | left: 14, 29 | child: Container( 30 | color: Colors.white, 31 | padding: EdgeInsets.symmetric(horizontal: 3), 32 | child: Text( 33 | label, 34 | style: GoogleFonts.poppins( 35 | fontSize: 12, 36 | fontWeight: FontWeight.w500 37 | ), 38 | ) 39 | ), 40 | ) 41 | ], 42 | ), 43 | ); 44 | } 45 | } -------------------------------------------------------------------------------- /lib/widgets/custom_progress_indicator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class CustomProgressIndicatior extends StatefulWidget { 4 | @override 5 | _CustomProgressIndicatiorState createState() => _CustomProgressIndicatiorState(); 6 | } 7 | 8 | class _CustomProgressIndicatiorState extends State with SingleTickerProviderStateMixin { 9 | AnimationController _animationController; 10 | 11 | @override 12 | void initState() { 13 | super.initState(); 14 | _animationController = AnimationController( 15 | vsync: this, 16 | duration: Duration(milliseconds: (3*0.5*2222).toInt()) 17 | ); 18 | 19 | _animationController.repeat(); 20 | } 21 | 22 | @override 23 | void dispose() { 24 | _animationController.dispose(); 25 | super.dispose(); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return CircularProgressIndicator( 31 | valueColor: TweenSequence( 32 | >[ 33 | TweenSequenceItem( 34 | tween: ConstantTween(Color.fromARGB(255, 0, 60, 192)), 35 | weight: 33.33, 36 | ), 37 | TweenSequenceItem( 38 | tween: ConstantTween(Color.fromARGB(255, 0, 140, 238)), 39 | weight: 33.33, 40 | ), 41 | TweenSequenceItem( 42 | tween: ConstantTween(Color.fromARGB(255,11, 209, 252)), 43 | weight: 33.33, 44 | ), 45 | ], 46 | ).animate(_animationController), 47 | ); 48 | } 49 | } -------------------------------------------------------------------------------- /lib/widgets/daily_amout_dial.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:math'; 3 | import 'package:google_fonts/google_fonts.dart'; 4 | import 'package:provider/provider.dart'; 5 | 6 | // providers 7 | import '../providers/home_provider.dart'; 8 | 9 | 10 | class DailyAmountDial extends StatelessWidget { 11 | @override 12 | Widget build(BuildContext context) { 13 | return Consumer( 14 | builder: (context, provider, child) { 15 | return Stack( 16 | alignment: Alignment.center, 17 | children: [ 18 | Transform.rotate( 19 | angle: -pi/2, 20 | child: Container( 21 | width: 170, 22 | height: 170, 23 | child: CustomPaint( 24 | painter: DialPainter(provider.targetReached), 25 | ), 26 | ), 27 | ), 28 | provider.leftAmount<=0 ? Text( 29 | 'Goal Reached', 30 | style: GoogleFonts.poppins(fontSize: 16,fontWeight: FontWeight.w500,color: Colors.white,) 31 | ):RichText( 32 | textAlign: TextAlign.center, 33 | text: TextSpan( 34 | children: [ 35 | TextSpan( 36 | text: provider.leftAmount<1000? '${provider.leftAmount} mL': '${(provider.leftAmount/1000).toStringAsFixed(1)} L' , 37 | style: GoogleFonts.poppins(fontSize: 30,fontWeight: FontWeight.w600) 38 | ), 39 | TextSpan(text:'\n'), 40 | TextSpan( 41 | text: 'left to drink', 42 | style: GoogleFonts.poppins(fontSize: 12,fontWeight: FontWeight.w300) 43 | ), 44 | ] 45 | ), 46 | ) 47 | ], 48 | ); 49 | }, 50 | ); 51 | } 52 | } 53 | 54 | class DialPainter extends CustomPainter{ 55 | double percent; 56 | DialPainter(this.percent); 57 | @override 58 | void paint(Canvas canvas, Size size) { 59 | Offset center = Offset(size.height/2,size.width/2); 60 | double fullRadius = (size.height/2); 61 | Paint circle = Paint()..color=Colors.white.withOpacity(0.2)..strokeWidth=6..style=PaintingStyle.stroke; 62 | Paint arc = Paint()..color = Colors.white..strokeCap=StrokeCap.round..style=PaintingStyle.stroke..strokeWidth=10; 63 | canvas.drawCircle(Offset(size.width/2,size.height/2), fullRadius-2,circle); 64 | canvas..drawArc(Rect.fromCircle(center: center,radius: fullRadius-2), 0, 2*pi*percent, false, arc); 65 | } 66 | 67 | @override 68 | bool shouldRepaint(CustomPainter oldDelegate) { 69 | return true; 70 | } 71 | } -------------------------------------------------------------------------------- /lib/widgets/daily_goal_amount.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:google_fonts/google_fonts.dart'; 4 | 5 | // providers 6 | import '../providers/home_provider.dart'; 7 | 8 | class DailyGoalAmount extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | return ClipRRect( 12 | borderRadius: BorderRadius.circular(2), 13 | child: Container( 14 | padding: EdgeInsets.symmetric( 15 | horizontal: 15, 16 | vertical: 12 17 | ), 18 | decoration: BoxDecoration( 19 | color: Colors.white.withOpacity(0.2), 20 | border: Border(left: BorderSide(color: Colors.white,width: 2)), 21 | ), 22 | child: Row( 23 | children: [ 24 | Text( 25 | 'Goal', 26 | style: GoogleFonts.poppins( 27 | color: Colors.white.withOpacity(0.8), 28 | fontSize: 19, 29 | fontWeight: FontWeight.w300 30 | ), 31 | ), 32 | SizedBox(width: 15,), 33 | Consumer( 34 | builder: (context, provider, child) { 35 | return Text( 36 | provider.dailyTarget.toString(), 37 | style: GoogleFonts.poppins( 38 | color: Colors.white, 39 | fontSize: 19, 40 | fontWeight: FontWeight.w700 41 | ) 42 | ); 43 | }, 44 | ) 45 | ], 46 | ), 47 | ), 48 | ); 49 | } 50 | } -------------------------------------------------------------------------------- /lib/widgets/goal_and_add.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | // widgets 4 | import './daily_amout_dial.dart'; 5 | import './daily_goal_amount.dart'; 6 | import './water_effect.dart'; 7 | 8 | class GoalAndAdd extends StatelessWidget { 9 | @override 10 | Widget build(BuildContext context) { 11 | return LayoutBuilder( 12 | builder: (context, constraints) { 13 | return Container( 14 | constraints: constraints, 15 | child: Stack( 16 | alignment: Alignment.center, 17 | children: [ 18 | WaterEffect(), 19 | Padding( 20 | padding: const EdgeInsets.symmetric(horizontal:20), 21 | child: Row( 22 | mainAxisAlignment: MainAxisAlignment.center, 23 | children: [ 24 | Column( 25 | mainAxisSize: MainAxisSize.min, 26 | crossAxisAlignment: CrossAxisAlignment.center, 27 | children: [ 28 | DailyGoalAmount(), 29 | SizedBox(height: 25,), 30 | DailyAmountDial() 31 | ], 32 | ), 33 | ], 34 | ), 35 | ) 36 | ], 37 | ) 38 | ); 39 | }, 40 | ); 41 | } 42 | } -------------------------------------------------------------------------------- /lib/widgets/loading_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | // widgets 4 | import './custom_progress_indicator.dart'; 5 | 6 | class LoadingScreen extends StatelessWidget { 7 | @override 8 | Widget build(BuildContext context) { 9 | return Scaffold( 10 | body: Center( 11 | child: CustomProgressIndicatior() 12 | ), 13 | ); 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /lib/widgets/three_layer_background.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ThreeLayerBackground extends StatelessWidget { 4 | @override 5 | Widget build(BuildContext context) { 6 | return LayoutBuilder( 7 | builder: (context, constraints) { 8 | return Stack( 9 | children: [ 10 | Align( 11 | alignment: Alignment.bottomCenter, 12 | child: ClipPath( 13 | clipper: MyClipper(), 14 | child: Container( 15 | height: constraints.maxHeight, 16 | color: Color.fromARGB(255,11, 209, 252), 17 | ), 18 | ), 19 | ), 20 | Align( 21 | alignment: Alignment.bottomCenter, 22 | child: ClipPath( 23 | clipper: MyClipper(), 24 | child: Container( 25 | height: constraints.maxHeight*0.75, 26 | color: Color.fromARGB(255, 0, 140, 238), 27 | ), 28 | ), 29 | ), 30 | Align( 31 | alignment: Alignment.bottomCenter, 32 | child: ClipPath( 33 | clipper: MyClipper(), 34 | child: Container( 35 | height: constraints.maxHeight*0.50, 36 | color: Color.fromARGB(255, 0, 60, 192), 37 | ), 38 | ), 39 | ) 40 | ], 41 | ); 42 | }, 43 | ); 44 | } 45 | } 46 | 47 | class MyClipper extends CustomClipper{ 48 | @override 49 | Path getClip(Size size) { 50 | Path path = Path(); 51 | path.lineTo(0,size.height); 52 | path.lineTo(size.width, size.height); 53 | path.lineTo(size.width, 30); 54 | path.quadraticBezierTo(size.width/2, -1, 0, 0); 55 | path.close(); 56 | return path; 57 | } 58 | 59 | @override 60 | bool shouldReclip(CustomClipper oldClipper) => false; 61 | } -------------------------------------------------------------------------------- /lib/widgets/water_effect.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'dart:math'; 3 | 4 | class WaterEffect extends StatefulWidget { 5 | @override 6 | _WaterEffectState createState() => _WaterEffectState(); 7 | } 8 | 9 | class _WaterEffectState extends State with SingleTickerProviderStateMixin { 10 | AnimationController _animationController; 11 | 12 | @override 13 | void initState() { 14 | super.initState(); 15 | _animationController = AnimationController( 16 | vsync: this, 17 | duration: Duration(seconds: 5), 18 | ); 19 | _animationController.repeat(); 20 | } 21 | 22 | @override 23 | void dispose() { 24 | _animationController.dispose(); 25 | super.dispose(); 26 | } 27 | 28 | @override 29 | Widget build(BuildContext context) { 30 | return LayoutBuilder( 31 | builder: (context, constraints) { 32 | return AnimatedBuilder( 33 | animation: _animationController, 34 | builder: (context, child) { 35 | List points1 = []; 36 | List points2 = []; 37 | for(double i=0;i<=constraints.maxWidth;i++){ 38 | double val = 15*sin(2*pi*(_animationController.value + (i/constraints.maxWidth))); 39 | double val2 = 15*sin(2*pi*(_animationController.value + (1-(i/constraints.maxWidth)))); 40 | points1.add(Offset(i,constraints.maxWidth-15+val)); 41 | points2.add(Offset(constraints.maxWidth - i,15+val2)); 42 | } 43 | return ClipPath( 44 | clipper: WaveClipper(points1,points2), 45 | child: Container( 46 | constraints: constraints, 47 | child: Stack( 48 | alignment: Alignment.topCenter, 49 | children: [ 50 | Container( 51 | width: constraints.maxWidth, 52 | height: constraints.maxWidth, 53 | color: Color.fromARGB(255, 0, 60, 192), 54 | ), 55 | ], 56 | ), 57 | ), 58 | ); 59 | }, 60 | ); 61 | }, 62 | ); 63 | } 64 | } 65 | 66 | class WaveClipper extends CustomClipper { 67 | List offsets1; 68 | List offsets2; 69 | WaveClipper(this.offsets1,this.offsets2); 70 | @override 71 | Path getClip(Size size) { 72 | Path path = Path(); 73 | path.lineTo(offsets1[0].dx,offsets1[0].dy); 74 | path.addPolygon(offsets1, false); 75 | path.lineTo(offsets2[0].dx,offsets2[0].dy); 76 | path.addPolygon(offsets2, false); 77 | path.lineTo(offsets2[offsets2.length-1].dx,offsets2[offsets2.length-1].dy); 78 | path.lineTo(offsets1[0].dx,offsets1[0].dy); 79 | path.close(); 80 | return path; 81 | } 82 | 83 | @override 84 | bool shouldReclip(CustomClipper oldClipper) => true; 85 | } -------------------------------------------------------------------------------- /lib/widgets/weather_suggestion.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:provider/provider.dart'; 3 | import 'package:google_fonts/google_fonts.dart'; 4 | 5 | // providers 6 | import '../providers/home_provider.dart'; 7 | 8 | // values 9 | import '../values/weather_icons.dart'; 10 | 11 | 12 | class WeatherSuggestion extends StatelessWidget { 13 | @override 14 | Widget build(BuildContext context) { 15 | return Column( 16 | mainAxisSize: MainAxisSize.min, 17 | crossAxisAlignment: CrossAxisAlignment.start, 18 | children: [ 19 | Text( 20 | 'Weather', 21 | style: GoogleFonts.poppins(fontSize: 20), 22 | ), 23 | SizedBox(height: 18,), 24 | Consumer( 25 | builder: (context, value, child) { 26 | Map weather = value.weather; 27 | return Row( 28 | children: [ 29 | Container( 30 | padding: EdgeInsets.all(25), 31 | decoration: BoxDecoration( 32 | color: Color.fromARGB(255, 37, 90, 210), 33 | borderRadius: BorderRadius.circular(8) 34 | ), 35 | child: Image.asset( 36 | weatherIcons[ 37 | weather['icon'].toString().split('')[0] 38 | +weather['icon'].toString().split('')[1] 39 | ], 40 | width: 40, 41 | ), 42 | ), 43 | SizedBox(width: 20,), 44 | Container( 45 | width: 140, 46 | child: Column( 47 | crossAxisAlignment: CrossAxisAlignment.start, 48 | children: [ 49 | RichText( 50 | text: TextSpan( 51 | style: GoogleFonts.poppins( 52 | color: Colors.black,fontSize: 17, 53 | ), 54 | children: [ 55 | TextSpan(text: 'It\'s ',style: GoogleFonts.poppins(fontWeight: FontWeight.w300)), 56 | TextSpan(text: weather['description'],style: GoogleFonts.poppins(fontWeight: FontWeight.w700)), 57 | TextSpan(text: ' today!',style: GoogleFonts.poppins(fontWeight: FontWeight.w300)), 58 | ] 59 | ), 60 | ), 61 | SizedBox(height: 11,), 62 | Text( 63 | 'Dont\'t forget to take the water bottle with you.', 64 | style: GoogleFonts.poppins( 65 | height: 1.5, 66 | color: Colors.black.withOpacity(0.6), 67 | fontSize: 12 68 | ), 69 | ) 70 | ], 71 | ), 72 | ) 73 | ], 74 | ); 75 | }, 76 | ), 77 | ], 78 | ); 79 | } 80 | } -------------------------------------------------------------------------------- /lib/widgets/weekly_statistics_graph.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:google_fonts/google_fonts.dart'; 3 | 4 | 5 | // models 6 | import '../models/weekly_data.dart'; 7 | 8 | // values 9 | import '../values/months.dart'; 10 | import '../values/weekdays.dart'; 11 | 12 | class WeeklyStatisticsGraph extends StatelessWidget { 13 | final WeeklyData weeklyData; 14 | WeeklyStatisticsGraph(this.weeklyData); 15 | 16 | @override 17 | Widget build(BuildContext context) { 18 | List bars = []; 19 | int max = 0; 20 | int maxH = 150; 21 | Map intakes = weeklyData.amounts; 22 | for(int i=1;i<=7;i++){ 23 | if(intakes[i.toString()]>max){ 24 | max = intakes[i.toString()]; 25 | } 26 | } 27 | for(int i=1;i<=7;i++){ 28 | double h = max==0 ? 0 : maxH*(intakes[i.toString()]/max); 29 | bars.add( 30 | Column( 31 | mainAxisSize: MainAxisSize.min, 32 | children: [ 33 | Container( 34 | width: 8,height: h, 35 | decoration: BoxDecoration( 36 | color: Color.fromARGB(255, 0, 140, 238), 37 | borderRadius: BorderRadius.circular(4) 38 | ), 39 | ), 40 | SizedBox(height: 5,), 41 | Text( 42 | weekdays[i], 43 | style: GoogleFonts.poppins( 44 | color: Colors.black.withOpacity(0.5), 45 | fontSize: 12, 46 | fontWeight: FontWeight.w400 47 | ), 48 | ) 49 | ], 50 | ), 51 | ); 52 | } 53 | return Card( 54 | shape: RoundedRectangleBorder( 55 | borderRadius: BorderRadius.circular(8) 56 | ), 57 | child: Container( 58 | width: 300, 59 | height: 270, 60 | decoration: BoxDecoration( 61 | color: Colors.white, 62 | borderRadius: BorderRadius.circular(8) 63 | ), 64 | child: Column( 65 | children: [ 66 | Expanded( 67 | child: Container( 68 | alignment: Alignment.bottomCenter, 69 | width: 300, 70 | child: Row( 71 | crossAxisAlignment: CrossAxisAlignment.end, 72 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 73 | children: bars, 74 | ) 75 | ), 76 | ), 77 | Padding( 78 | padding: const EdgeInsets.fromLTRB(25, 10, 25, 30), 79 | child: Row( 80 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 81 | children: [ 82 | Row( 83 | mainAxisSize: MainAxisSize.min, 84 | children: [ 85 | Row( 86 | crossAxisAlignment: CrossAxisAlignment.center, 87 | mainAxisSize: MainAxisSize.min, 88 | children: [ 89 | Container( 90 | width: 3, 91 | height: 32, 92 | decoration: BoxDecoration( 93 | borderRadius: BorderRadius.circular(3), 94 | gradient: LinearGradient( 95 | begin: Alignment.topCenter, 96 | end: Alignment.bottomCenter, 97 | colors: [ 98 | Colors.blue[300], 99 | Colors.red[200] 100 | ] 101 | ) 102 | ), 103 | ), 104 | SizedBox(width: 10,), 105 | Column( 106 | crossAxisAlignment: CrossAxisAlignment.start, 107 | mainAxisAlignment: MainAxisAlignment.center, 108 | mainAxisSize: MainAxisSize.min, 109 | children: [ 110 | Text( 111 | 'Hydration', 112 | style: GoogleFonts.poppins( 113 | color: Colors.black.withOpacity(0.5), 114 | fontSize: 12, 115 | ), 116 | ), 117 | SizedBox(height: 5,), 118 | Text( 119 | '${weeklyData.percentThisWeek()} %', 120 | style: GoogleFonts.poppins( 121 | color: Colors.black, 122 | fontSize: 20, 123 | fontWeight: FontWeight.w500 124 | ), 125 | ) 126 | ], 127 | ), 128 | ], 129 | ), 130 | SizedBox(width: 20,), 131 | Row( 132 | mainAxisSize: MainAxisSize.min, 133 | children: [ 134 | Container( 135 | width: 3, 136 | height: 32, 137 | decoration: BoxDecoration( 138 | borderRadius: BorderRadius.circular(3), 139 | gradient: LinearGradient( 140 | begin: Alignment.topCenter, 141 | end: Alignment.bottomCenter, 142 | colors: [ 143 | Colors.blue[300], 144 | Colors.blue[100] 145 | ] 146 | ) 147 | ), 148 | ), 149 | SizedBox(width: 10,), 150 | Column( 151 | crossAxisAlignment: CrossAxisAlignment.start, 152 | mainAxisSize: MainAxisSize.min, 153 | children: [ 154 | Text( 155 | 'Intake', 156 | style: GoogleFonts.poppins( 157 | color: Colors.black.withOpacity(0.5), 158 | fontSize: 12 159 | ), 160 | ), 161 | SizedBox(height: 5,), 162 | Text( 163 | '${(weeklyData.totalThisWeek()/1000).toStringAsFixed(1)} L', 164 | style: GoogleFonts.poppins( 165 | color: Colors.black, 166 | fontSize: 20, 167 | fontWeight: FontWeight.w500 168 | ), 169 | ) 170 | ], 171 | ), 172 | ], 173 | ), 174 | ], 175 | ), 176 | 177 | Column( 178 | crossAxisAlignment: CrossAxisAlignment.start, 179 | mainAxisSize: MainAxisSize.min, 180 | children: [ 181 | Text( 182 | 'Week ${weeklyData.week}', 183 | style: GoogleFonts.poppins( 184 | color: Colors.black.withOpacity(0.5), 185 | fontSize: 14 186 | ), 187 | ), 188 | 189 | Text( 190 | '${months[weeklyData.month]}, ${weeklyData.year.toString()}', 191 | style: GoogleFonts.poppins( 192 | color: Colors.black.withOpacity(0.5), 193 | fontSize: 14 194 | ), 195 | ), 196 | ], 197 | ) 198 | ], 199 | ), 200 | ) 201 | ], 202 | ), 203 | ), 204 | ); 205 | } 206 | } -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.4.2" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.0.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.0.0" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.1.3" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.0.1" 39 | cloud_firestore: 40 | dependency: "direct main" 41 | description: 42 | name: cloud_firestore 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "0.14.0+2" 46 | cloud_firestore_platform_interface: 47 | dependency: transitive 48 | description: 49 | name: cloud_firestore_platform_interface 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "2.0.1" 53 | cloud_firestore_web: 54 | dependency: transitive 55 | description: 56 | name: cloud_firestore_web 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "0.2.0+1" 60 | collection: 61 | dependency: transitive 62 | description: 63 | name: collection 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.14.13" 67 | convert: 68 | dependency: transitive 69 | description: 70 | name: convert 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "2.1.1" 74 | crypto: 75 | dependency: transitive 76 | description: 77 | name: crypto 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "2.1.5" 81 | cupertino_icons: 82 | dependency: "direct main" 83 | description: 84 | name: cupertino_icons 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "0.1.3" 88 | fake_async: 89 | dependency: transitive 90 | description: 91 | name: fake_async 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "1.1.0" 95 | file: 96 | dependency: transitive 97 | description: 98 | name: file 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "5.2.1" 102 | firebase: 103 | dependency: transitive 104 | description: 105 | name: firebase 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "7.3.0" 109 | firebase_auth: 110 | dependency: "direct main" 111 | description: 112 | name: firebase_auth 113 | url: "https://pub.dartlang.org" 114 | source: hosted 115 | version: "0.18.0+1" 116 | firebase_auth_platform_interface: 117 | dependency: transitive 118 | description: 119 | name: firebase_auth_platform_interface 120 | url: "https://pub.dartlang.org" 121 | source: hosted 122 | version: "2.0.1" 123 | firebase_auth_web: 124 | dependency: transitive 125 | description: 126 | name: firebase_auth_web 127 | url: "https://pub.dartlang.org" 128 | source: hosted 129 | version: "0.3.0+1" 130 | firebase_core: 131 | dependency: "direct main" 132 | description: 133 | name: firebase_core 134 | url: "https://pub.dartlang.org" 135 | source: hosted 136 | version: "0.5.0" 137 | firebase_core_platform_interface: 138 | dependency: transitive 139 | description: 140 | name: firebase_core_platform_interface 141 | url: "https://pub.dartlang.org" 142 | source: hosted 143 | version: "2.0.0" 144 | firebase_core_web: 145 | dependency: transitive 146 | description: 147 | name: firebase_core_web 148 | url: "https://pub.dartlang.org" 149 | source: hosted 150 | version: "0.2.0" 151 | flutter: 152 | dependency: "direct main" 153 | description: flutter 154 | source: sdk 155 | version: "0.0.0" 156 | flutter_local_notifications: 157 | dependency: "direct main" 158 | description: 159 | name: flutter_local_notifications 160 | url: "https://pub.dartlang.org" 161 | source: hosted 162 | version: "1.4.4+4" 163 | flutter_local_notifications_platform_interface: 164 | dependency: transitive 165 | description: 166 | name: flutter_local_notifications_platform_interface 167 | url: "https://pub.dartlang.org" 168 | source: hosted 169 | version: "1.0.1" 170 | flutter_test: 171 | dependency: "direct dev" 172 | description: flutter 173 | source: sdk 174 | version: "0.0.0" 175 | flutter_web_plugins: 176 | dependency: transitive 177 | description: flutter 178 | source: sdk 179 | version: "0.0.0" 180 | google_fonts: 181 | dependency: "direct main" 182 | description: 183 | name: google_fonts 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "1.1.0" 187 | google_sign_in: 188 | dependency: "direct main" 189 | description: 190 | name: google_sign_in 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "4.5.3" 194 | google_sign_in_platform_interface: 195 | dependency: transitive 196 | description: 197 | name: google_sign_in_platform_interface 198 | url: "https://pub.dartlang.org" 199 | source: hosted 200 | version: "1.1.2" 201 | google_sign_in_web: 202 | dependency: transitive 203 | description: 204 | name: google_sign_in_web 205 | url: "https://pub.dartlang.org" 206 | source: hosted 207 | version: "0.9.1+1" 208 | http: 209 | dependency: "direct main" 210 | description: 211 | name: http 212 | url: "https://pub.dartlang.org" 213 | source: hosted 214 | version: "0.12.2" 215 | http_parser: 216 | dependency: transitive 217 | description: 218 | name: http_parser 219 | url: "https://pub.dartlang.org" 220 | source: hosted 221 | version: "3.1.4" 222 | intl: 223 | dependency: "direct main" 224 | description: 225 | name: intl 226 | url: "https://pub.dartlang.org" 227 | source: hosted 228 | version: "0.16.1" 229 | js: 230 | dependency: transitive 231 | description: 232 | name: js 233 | url: "https://pub.dartlang.org" 234 | source: hosted 235 | version: "0.6.2" 236 | location: 237 | dependency: "direct main" 238 | description: 239 | name: location 240 | url: "https://pub.dartlang.org" 241 | source: hosted 242 | version: "3.0.2" 243 | location_platform_interface: 244 | dependency: transitive 245 | description: 246 | name: location_platform_interface 247 | url: "https://pub.dartlang.org" 248 | source: hosted 249 | version: "1.0.0" 250 | location_web: 251 | dependency: transitive 252 | description: 253 | name: location_web 254 | url: "https://pub.dartlang.org" 255 | source: hosted 256 | version: "1.0.0" 257 | matcher: 258 | dependency: transitive 259 | description: 260 | name: matcher 261 | url: "https://pub.dartlang.org" 262 | source: hosted 263 | version: "0.12.8" 264 | meta: 265 | dependency: transitive 266 | description: 267 | name: meta 268 | url: "https://pub.dartlang.org" 269 | source: hosted 270 | version: "1.1.8" 271 | nested: 272 | dependency: transitive 273 | description: 274 | name: nested 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "0.0.4" 278 | path: 279 | dependency: transitive 280 | description: 281 | name: path 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "1.7.0" 285 | path_provider: 286 | dependency: transitive 287 | description: 288 | name: path_provider 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "1.6.14" 292 | path_provider_linux: 293 | dependency: transitive 294 | description: 295 | name: path_provider_linux 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "0.0.1+2" 299 | path_provider_macos: 300 | dependency: transitive 301 | description: 302 | name: path_provider_macos 303 | url: "https://pub.dartlang.org" 304 | source: hosted 305 | version: "0.0.4+3" 306 | path_provider_platform_interface: 307 | dependency: transitive 308 | description: 309 | name: path_provider_platform_interface 310 | url: "https://pub.dartlang.org" 311 | source: hosted 312 | version: "1.0.3" 313 | pedantic: 314 | dependency: transitive 315 | description: 316 | name: pedantic 317 | url: "https://pub.dartlang.org" 318 | source: hosted 319 | version: "1.9.0" 320 | platform: 321 | dependency: transitive 322 | description: 323 | name: platform 324 | url: "https://pub.dartlang.org" 325 | source: hosted 326 | version: "2.2.1" 327 | plugin_platform_interface: 328 | dependency: transitive 329 | description: 330 | name: plugin_platform_interface 331 | url: "https://pub.dartlang.org" 332 | source: hosted 333 | version: "1.0.2" 334 | process: 335 | dependency: transitive 336 | description: 337 | name: process 338 | url: "https://pub.dartlang.org" 339 | source: hosted 340 | version: "3.0.13" 341 | provider: 342 | dependency: "direct main" 343 | description: 344 | name: provider 345 | url: "https://pub.dartlang.org" 346 | source: hosted 347 | version: "4.3.2+1" 348 | quiver: 349 | dependency: transitive 350 | description: 351 | name: quiver 352 | url: "https://pub.dartlang.org" 353 | source: hosted 354 | version: "2.1.3" 355 | sky_engine: 356 | dependency: transitive 357 | description: flutter 358 | source: sdk 359 | version: "0.0.99" 360 | source_span: 361 | dependency: transitive 362 | description: 363 | name: source_span 364 | url: "https://pub.dartlang.org" 365 | source: hosted 366 | version: "1.7.0" 367 | stack_trace: 368 | dependency: transitive 369 | description: 370 | name: stack_trace 371 | url: "https://pub.dartlang.org" 372 | source: hosted 373 | version: "1.9.5" 374 | stream_channel: 375 | dependency: transitive 376 | description: 377 | name: stream_channel 378 | url: "https://pub.dartlang.org" 379 | source: hosted 380 | version: "2.0.0" 381 | string_scanner: 382 | dependency: transitive 383 | description: 384 | name: string_scanner 385 | url: "https://pub.dartlang.org" 386 | source: hosted 387 | version: "1.0.5" 388 | term_glyph: 389 | dependency: transitive 390 | description: 391 | name: term_glyph 392 | url: "https://pub.dartlang.org" 393 | source: hosted 394 | version: "1.1.0" 395 | test_api: 396 | dependency: transitive 397 | description: 398 | name: test_api 399 | url: "https://pub.dartlang.org" 400 | source: hosted 401 | version: "0.2.17" 402 | typed_data: 403 | dependency: transitive 404 | description: 405 | name: typed_data 406 | url: "https://pub.dartlang.org" 407 | source: hosted 408 | version: "1.2.0" 409 | vector_math: 410 | dependency: transitive 411 | description: 412 | name: vector_math 413 | url: "https://pub.dartlang.org" 414 | source: hosted 415 | version: "2.0.8" 416 | xdg_directories: 417 | dependency: transitive 418 | description: 419 | name: xdg_directories 420 | url: "https://pub.dartlang.org" 421 | source: hosted 422 | version: "0.1.0" 423 | sdks: 424 | dart: ">=2.9.0-14.0.dev <3.0.0" 425 | flutter: ">=1.17.0 <2.0.0" 426 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: drinkable 2 | description: A Flutter application which keeps track your water intake and remind you to drink water by sending notification. 3 | 4 | publish_to: 'none' 5 | 6 | version: 2.0.0 7 | 8 | environment: 9 | sdk: ">=2.7.0 <3.0.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | cupertino_icons: ^0.1.3 15 | 16 | intl: ^0.16.1 17 | google_fonts: ^1.1.0 18 | provider: ^4.3.2+1 19 | firebase_core: ^0.5.0 20 | firebase_auth: ^0.18.0+1 21 | cloud_firestore: ^0.14.0+2 22 | google_sign_in: ^4.5.3 23 | location: ^3.0.2 24 | http: ^0.12.2 25 | flutter_local_notifications: ^1.4.4+4 26 | 27 | dev_dependencies: 28 | flutter_test: 29 | sdk: flutter 30 | 31 | flutter: 32 | uses-material-design: true 33 | 34 | assets : 35 | - assets/icons/ 36 | - assets/images/ -------------------------------------------------------------------------------- /screenshot/flutter_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/screenshot/flutter_01.png -------------------------------------------------------------------------------- /screenshot/flutter_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/screenshot/flutter_02.png -------------------------------------------------------------------------------- /screenshot/flutter_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/screenshot/flutter_03.png -------------------------------------------------------------------------------- /screenshot/flutter_04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/screenshot/flutter_04.png -------------------------------------------------------------------------------- /screenshot/flutter_05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/screenshot/flutter_05.png -------------------------------------------------------------------------------- /screenshot/flutter_06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/screenshot/flutter_06.png -------------------------------------------------------------------------------- /screenshot/flutter_07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/screenshot/flutter_07.png -------------------------------------------------------------------------------- /screenshot/flutter_08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/noobcoder17/drinkable/b8ca2e00853ddddc2c53537358fe18e2b3d5b028/screenshot/flutter_08.png -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:drinkable/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | --------------------------------------------------------------------------------