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