├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── android ├── .gradle │ └── buildOutputCleanup │ │ ├── cache.properties │ │ └── outputFiles.bin ├── app │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ ├── com │ │ │ └── andrioussolutions │ │ │ │ └── weathercast │ │ │ │ └── MainActivity.java │ │ └── io │ │ │ └── flutter │ │ │ └── plugins │ │ │ └── GeneratedPluginRegistrant.java │ │ └── res │ │ ├── drawable │ │ └── launch_background.xml │ │ ├── mipmap-hdpi │ │ ├── andrioussolutions.png │ │ └── ic_launcher.png │ │ ├── mipmap-ldpi │ │ └── andrioussolutions.png │ │ ├── mipmap-mdpi │ │ ├── andrioussolutions.png │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ ├── andrioussolutions.png │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ ├── andrioussolutions.png │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ ├── andrioussolutions.png │ │ └── ic_launcher.png │ │ └── values │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── local.properties └── settings.gradle ├── assets ├── clear.png ├── cloudy.png ├── rainy.png ├── snow.png └── thunderstorm.png ├── ios ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ ├── Generated.xcconfig │ └── Release.xcconfig ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ └── contents.xcworkspacedata └── Runner │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-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 │ ├── GeneratedPluginRegistrant.h │ ├── GeneratedPluginRegistrant.m │ ├── Info.plist │ └── main.m ├── lib ├── main.dart └── src │ ├── app │ ├── controller │ │ └── weatherapp.dart │ └── view │ │ ├── utils │ │ └── gradient_container.dart │ │ └── weatherapp.dart │ ├── controller.dart │ ├── home │ ├── controller │ │ ├── home.dart │ │ ├── settings.dart │ │ ├── theme.dart │ │ ├── weather_conditions.dart │ │ └── weather_repository.dart │ ├── model │ │ ├── repositories │ │ │ └── weather_api_client.dart │ │ └── weather_model.dart │ └── view │ │ ├── child │ │ ├── city_selection.dart │ │ ├── last_updated.dart │ │ ├── temperature.dart │ │ └── weather_temperature.dart │ │ ├── drawer │ │ ├── settings_drawer.dart │ │ └── weather_locations │ │ │ ├── controller │ │ │ └── weather_locations.dart │ │ │ ├── model │ │ │ └── weather_locations.dart │ │ │ ├── mvc.dart │ │ │ └── view │ │ │ └── weather_locations.dart │ │ ├── home.dart │ │ └── location.dart │ ├── model.dart │ └── view.dart ├── pubspec.yaml └── test └── widget_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Good to keep this file with the code. 2 | #.gitignore 3 | /.DS_Store 4 | /.atom/ 5 | /.idea/ 6 | /.vscode/ 7 | /.packages 8 | /.pub/ 9 | /build/ 10 | 11 | /.flutter-plugins 12 | /doc/api/ 13 | /.dart_tool/ 14 | 15 | # Android Studio 16 | /*.iml 17 | 18 | # Except for application packages 19 | pubspec.lock 20 | 21 | # Don't need the Android stuff 22 | /android/ 23 | 24 | # Ignore App signing files 25 | /*.jks 26 | 27 | # Don't need the iOS stuff 28 | /ios/ 29 | 30 | # Avoid committing generated JavaScript files: 31 | /*.dart.js 32 | /*.info.json # Produced by the --dump-info flag. 33 | /*.js # When generated by dart2js. Don't specify *.js if your 34 | # project includes source files written in JavaScript. 35 | /*.js_ 36 | /*.js.deps 37 | /*.js.map 38 | 39 | ### Eclipse ### 40 | /*.pydevproject 41 | /.project 42 | /.metadata 43 | /bin/** 44 | /tmp/** 45 | /tmp/**/* 46 | /*.tmp 47 | /*.bak 48 | /*.swp 49 | /*~.nib 50 | 51 | /.classpath 52 | /.settings/ 53 | /.loadpath 54 | 55 | a 56 | # Miscellaneous 57 | #*.lock 58 | *.log 59 | *.pyc 60 | *.swp 61 | .DS_Store 62 | .atom/ 63 | .buildlog/ 64 | .history 65 | .svn/ 66 | 67 | # IntelliJ related 68 | *.ipr 69 | *.iws 70 | 71 | # Visual Studio Code related 72 | .vscode/ 73 | 74 | # Flutter/Dart/Pub related 75 | **/doc/api/ 76 | .dart_tool/ 77 | .pub-cache/ 78 | .pub/ 79 | 80 | 81 | # Android related 82 | **/android/captures/ 83 | 84 | 85 | # iOS/XCode related 86 | **/ios/**/*.mode1v3 87 | **/ios/**/*.mode2v3 88 | **/ios/**/*.moved-aside 89 | **/ios/**/*.pbxuser 90 | **/ios/**/*.perspectivev3 91 | **/ios/**/*sync/ 92 | **/ios/**/.sconsign.dblite 93 | **/ios/**/.tags* 94 | **/ios/**/.vagrant/ 95 | **/ios/**/DerivedData/ 96 | **/ios/**/Icon? 97 | **/ios/**/Pods/ 98 | **/ios/**/.symlinks/ 99 | **/ios/**/profile 100 | **/ios/**/xcuserdata 101 | **/ios/.generated/ 102 | **/ios/Flutter/App.framework 103 | **/ios/Flutter/Flutter.framework 104 | **/ios/Flutter/app.flx 105 | **/ios/Flutter/app.zip 106 | **/ios/Flutter/flutter_assets/ 107 | **/ios/ServiceDefinitions.json 108 | 109 | # Exceptions to above rules. 110 | !**/ios/**/default.mode1v3 111 | !**/ios/**/default.mode2v3 112 | !**/ios/**/default.pbxuser 113 | !**/ios/**/default.perspectivev3 114 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 115 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.1.0 2 | March 23, 2020 3 | - sdk: ">=2.6.0 <3.0.0" 4 | - compileSdkVersion 28 5 | - androidx 6 | - multiDexEnabled true 7 | - class LocationMod extends SQLiteDB 8 | 9 | ## 1.0.3 10 | July 21, 2019 11 | - Add export 'package:sqflite/sqflite.dart'; to src/model.dart 12 | - Add mvc_application: ^1.0.3 to pubspec.yaml 13 | 14 | ## 1.0.2 15 | July 18, 2019 16 | - Moved location.dart to home/ directory. 17 | 18 | ## 1.0.1 19 | July 17, 2019 20 | - Removed 'package:mvc_application/mvc.dart' 21 | 22 | ## 1.0.0 23 | July 17, 2019 24 | - Migrated to MVC design pattern in mvc_application Dart Package. 25 | 26 | ## 0.6.0 27 | 2019-04-12 28 | - Update codebase 29 | 30 | ## 0.5.7 31 | 2019-03-06: 32 | - Comment out keystore reference in build.gradle 33 | 34 | ## 0.5.6 35 | 2019-03-04 36 | - directory renamed from secondary to child 37 | 38 | ## 0.5.5 39 | 2019-02-26 40 | - mod.Weather to Weather factory WeatherApp(){ 41 | 42 | ## 0.5.4 43 | 2019-02-25 44 | - renamed file to home.dart 45 | 46 | ## 0.5.3 47 | 2019-02-25 48 | - main directory renamed home 49 | 50 | ## 0.5.2 51 | 2019-02-25 52 | - url: git://github.com/AndriousSolutions/mvc_application.git 53 | 54 | ## 0.5.1 55 | 2019-02-25 56 | - andrioussolutions.png 57 | 58 | ## 0.5.0 59 | 2019-02-25 60 | - main directory 61 | 62 | ## 0.4.0 63 | 2019-02-24 64 | - class LocationTimer { Future getWeather(String city) 65 | 66 | ## 0.3.0 67 | 2019-02-23 68 | - class WeatherApp extends AppController { 69 | - class LocationCon extends ControllerMVC { 70 | 71 | ## 0.2.1 72 | 2019-02-21 73 | - class WeatherApp extends AppState { 74 | - class WeatherAppMenu { 75 | - Future initFetch() async { 76 | - ThemeCon extends AppController { 77 | - settings_drawer.dart 78 | - runApp(MVC(WeatherApp())); 79 | 80 | ## 0.1.1 81 | 2019-02-16 82 | - if(city == null) return _weather; 83 | 84 | ## 0.1.0 85 | 2019-02-15 86 | - Initial Commit 87 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 5 | 6 | 1. Definitions. 7 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 8 | 9 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 10 | 11 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with 12 | that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such 13 | entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 14 | 15 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 16 | 17 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 18 | 19 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, 20 | generated documentation, and conversions to other media types. 21 | 22 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or 23 | attached to the work (an example is provided in the Appendix below). 24 | 25 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, 26 | elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works 27 | that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 28 | 29 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, 30 | that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. 31 | For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, 32 | including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, 33 | the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing 34 | by the copyright owner as "Not a Contribution." 35 | 36 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 37 | 38 | 2. Grant of Copyright License. 39 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, 40 | no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, 41 | sublicense, and distribute the Work and such Derivative Works in Source or Object form. 42 | 43 | 3. Grant of Patent License. 44 | Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, 45 | royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, 46 | and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily 47 | infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. 48 | If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or 49 | a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted 50 | to You under this License for that Work shall terminate as of the date such litigation is filed. 51 | 52 | 4. Redistribution. 53 | You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, 54 | and in Source or Object form, provided that You meet the following conditions: 55 | 56 | 1.You must give any other recipients of the Work or Derivative Works a copy of this License; and 57 | 58 | 2.You must cause any modified files to carry prominent notices stating that You changed the files; and 59 | 60 | 3.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, 61 | and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 62 | 63 | 4.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include 64 | a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part 65 | of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; 66 | within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, 67 | if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 68 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, 69 | reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, 70 | and distribution of the Work otherwise complies with the conditions stated in this License. 71 | 72 | 5. Submission of Contributions. 73 | Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms 74 | and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms 75 | of any separate license agreement you may have executed with Licensor regarding such Contributions. 76 | 77 | 6. Trademarks. 78 | This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, 79 | except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 80 | 81 | 7. Disclaimer of Warranty. 82 | Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) 83 | on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, 84 | any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. 85 | You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with 86 | Your exercise of permissions under this License. 87 | 88 | 8. Limitation of Liability. 89 | In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law 90 | (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, 91 | including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or 92 | out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, 93 | or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 94 | 95 | 9. Accepting Warranty or Additional Liability. 96 | While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, 97 | indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, 98 | You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if 99 | You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, 100 | such Contributor by reason of your accepting any such warranty or additional liability. 101 | 102 | END OF TERMS AND CONDITIONS 103 | 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # weather 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/.gradle/buildOutputCleanup/cache.properties: -------------------------------------------------------------------------------- 1 | #Fri Sep 13 13:22:45 CDT 2019 2 | gradle.version=4.10.2 3 | -------------------------------------------------------------------------------- /android/.gradle/buildOutputCleanup/outputFiles.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/.gradle/buildOutputCleanup/outputFiles.bin -------------------------------------------------------------------------------- /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 = '3' 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 from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | // Initialize a new Properties() object called keystoreProperties. 28 | def keystoreProperties = new Properties() 29 | def keystorePropertiesFile = rootProject.file('C:/Users/gtfpe/KeyStore/weathercast.properties') 30 | if (keystorePropertiesFile.exists()) { 31 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 32 | } 33 | 34 | android { 35 | compileSdkVersion 28 36 | 37 | lintOptions { 38 | disable 'InvalidPackage' 39 | } 40 | 41 | signingConfigs { 42 | release{ 43 | // keyAlias keystoreProperties['keyAlias'] 44 | // keyPassword keystoreProperties['keyPassword'] 45 | // storeFile file(keystoreProperties['storeFile']) 46 | // storePassword keystoreProperties['storePassword'] 47 | v2SigningEnabled false 48 | } 49 | } 50 | 51 | defaultConfig { 52 | applicationId "com.andrioussolutions.weathercast" 53 | minSdkVersion 19 54 | targetSdkVersion 28 55 | versionCode flutterVersionCode.toInteger() 56 | versionName flutterVersionName 57 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 58 | ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64' 59 | multiDexEnabled true 60 | } 61 | 62 | buildTypes { 63 | 64 | release { 65 | 66 | signingConfig signingConfigs.release 67 | debuggable false 68 | minifyEnabled true 69 | shrinkResources true 70 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 71 | } 72 | 73 | debug { 74 | 75 | debuggable true 76 | minifyEnabled false 77 | // With minifyEnabled set to true, this uses an experimental code shrinker which doesn't obfuscate or optimize your code 78 | // (so you should enable this shrinker only for your "debug" build type). 79 | shrinkResources false 80 | useProguard false 81 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 82 | testCoverageEnabled false 83 | } 84 | } 85 | } 86 | 87 | flutter { 88 | source '../..' 89 | } 90 | 91 | dependencies { 92 | testImplementation 'junit:junit:4.12' 93 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 94 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' 95 | } 96 | -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # This is a configuration file for ProGuard. 2 | # https://www.guardsquare.com/en/proguard/manual/introduction 3 | 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in C:\Programs\Tools\AndroidSDK/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the proguardFiles 8 | # directive in build.gradle. 9 | # 10 | # For more details, jsee 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | #Flutter Wrapper 16 | -keep class io.flutter.app.** { *; } 17 | -keep class io.flutter.plugin.** { *; } 18 | -keep class io.flutter.util.** { *; } 19 | -keep class io.flutter.view.** { *; } 20 | -keep class io.flutter.** { *; } 21 | -keep class io.flutter.plugins.** { *; } 22 | 23 | #-keep class com.gtfp.errorhandler.** { *; } 24 | 25 | # 27 warnings seemed to be ignored ok. 26 | -dontwarn com.google.common.cache.** 27 | -dontwarn com.google.common.primitives.UnsignedBytes$** 28 | 29 | ## Try a little more passes for kicks. 30 | -optimizationpasses 5 31 | 32 | # Keep everything written in the app. 33 | #-keep class com.gtfp.** { *; } 34 | 35 | # use this option to remove logging code. 36 | -assumenosideeffects class android.util.Log { 37 | public static boolean isLoggable(java.lang.String, int); 38 | public static int v(...); 39 | public static int i(...); 40 | public static int w(...); 41 | public static int d(...); 42 | public static int e(...); 43 | } 44 | 45 | # It's being sought but doesn't need to be. 46 | -dontwarn org.joda.convert.** 47 | 48 | # It's included as a jar file so don't worry, right? 49 | #-dontwarn com.example.exceptionhandler.** 50 | 51 | # Necessary since adding compile files('../../../libs/opencsv/opencsv-3.3.jar') 52 | -dontwarn org.apache.commons.collections.BeanMap 53 | -dontwarn java.beans.** 54 | 55 | ##---------------Begin: proguard configuration common for all Android apps ---------- 56 | -dontskipnonpubliclibraryclassmembers 57 | 58 | -dump class_files.txt 59 | -printseeds seeds.txt 60 | -printusage unused.txt 61 | -printmapping mapping.txt 62 | 63 | ## Removes package names making the code even smaller and less comprehensible. 64 | -repackageclasses '' 65 | 66 | 67 | ##------------- Lets obfuscated code produce stack traces that can still be deciphered later on 68 | -renamesourcefileattribute SourceFile 69 | -keepattributes SourceFile,LineNumberTable 70 | 71 | 72 | # Keep because these classes can be declared in the AndrodiManifest.xml. 73 | #-keep public class * extends android.app.Activity 74 | #-keep public class * extends android.app.Application 75 | #-keep public class * extends android.app.Service 76 | #-keep public class * extends android.content.BroadcastReceiver 77 | 78 | #-keep public class * extends android.content.ContentProvider 79 | #-keep public class * extends android.app.backup.BackupAgent 80 | #-keep public class * extends android.app.backup.BackupAgentHelper 81 | 82 | #-keep public class * extends android.preference.Preference 83 | 84 | #-keep public class * extends android.support.v4.app.Fragment 85 | #-keep public class * extends android.support.v4.app.DialogFragment 86 | 87 | #-keep class com.google.android.gms.internal.* 88 | #-keep class com.google.android.gms.maps.** { *; } 89 | #-keep interface com.google.android.gms.maps.** { *; } 90 | 91 | # Explicitly preserve all serialization members. The Serializable interface 92 | # is only a marker interface, so it wouldn't save them. 93 | -keepclassmembers class * implements java.io.Serializable { 94 | static final long serialVersionUID; 95 | static final java.io.ObjectStreamField[] serialPersistentFields; 96 | private static final java.io.ObjectStreamField[] serialPersistentFields; 97 | private void writeObject(java.io.ObjectOutputStream); 98 | private void readObject(java.io.ObjectInputStream); 99 | java.lang.Object writeReplace(); 100 | java.lang.Object readResolve(); 101 | } 102 | 103 | ### Keep custom views since they are probably referenced only from layout XML instead of application code 104 | #-keepclassmembers !abstract class !com.google.ads.** extends android.view.View { 105 | # public (android.content.Context); 106 | # public (android.content.Context, android.util.AttributeSet); 107 | # public (android.content.Context, android.util.AttributeSet, int); 108 | # public void set*(...); 109 | #} 110 | # 111 | #-keepclassmembers !abstract class * { 112 | # public (android.content.Context, android.util.AttributeSet); 113 | # public (android.content.Context, android.util.AttributeSet, int); 114 | #} 115 | # 116 | #-keepclassmembers class * extends android.content.Context { 117 | # public void *(android.view.View); 118 | #} 119 | ###----------------- End of Keep Custom Views 120 | 121 | 122 | ## Saves any public class YOU THEN DON'T OBFUSCATE ANYTHING?? 123 | #-keep public class * { 124 | # public protected *; 125 | #} 126 | 127 | 128 | #-keepclassmembers class * implements android.os.Parcelable { 129 | # static *** CREATOR; 130 | # } 131 | 132 | 133 | ##---------------End: proguard configuration common for all Android apps 134 | 135 | ##---------------Begin: proguard configuration for support library 136 | #-keep class android.support.v4.app.** { *; } 137 | #-keep interface android.support.v4.app.** { *; } 138 | #-keep class com.actionbarsherlock.** { *; } 139 | #-keep interface com.actionbarsherlock.** { *; } 140 | # 141 | ## The support library contains references to newer platform versions. 142 | ## Don't warn about those in case this app is linking against an older 143 | ## platform version. We know about them, and they are safe. 144 | #-dontwarn android.support.** 145 | #-dontwarn com.google.ads.** 146 | ###---------------End: proguard configuration for support library 147 | 148 | 149 | ###---------------Begin: proguard configuration for Gson 150 | ## Gson uses generic type information stored in a class file when working with fields. Proguard 151 | ## removes such information by default, so configure it to keep all of it. 152 | #-keepattributes Signature 153 | # 154 | ## For using GSON @Expose annotation 155 | ## Gson specific classes 156 | #-keep class sun.misc.Unsafe { *; } 157 | #-keep class com.google.gson.stream.** { *; } 158 | # 159 | ## Application classes that will be serialized/deserialized over Gson 160 | #-keep class com.example.model.** { *; } 161 | # ##---------------End: proguard configuration for Gson ---------- 162 | 163 | # If your project uses WebView with JS, uncomment the following 164 | #and specify the fully qualified class name to the JavaScript interface 165 | # class: 166 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 167 | # public *; 168 | #} 169 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 15 | 19 | 22 | 29 | 33 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/andrioussolutions/weathercast/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.andrioussolutions.weathercast; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java: -------------------------------------------------------------------------------- 1 | package io.flutter.plugins; 2 | 3 | import io.flutter.plugin.common.PluginRegistry; 4 | import io.flutter.plugins.androidalarmmanager.AndroidAlarmManagerPlugin; 5 | import io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin; 6 | import io.flutter.plugins.connectivity.ConnectivityPlugin; 7 | import io.flutter.plugins.deviceinfo.DeviceInfoPlugin; 8 | import io.flutter.plugins.firebaseadmob.FirebaseAdMobPlugin; 9 | import io.flutter.plugins.firebaseauth.FirebaseAuthPlugin; 10 | import io.flutter.plugins.firebase.core.FirebaseCorePlugin; 11 | import io.flutter.plugins.firebase.database.FirebaseDatabasePlugin; 12 | import io.flutter.plugins.firebase.firebaseremoteconfig.FirebaseRemoteConfigPlugin; 13 | import com.github.sroddy.flutterstringencryption.FlutterStringEncryptionPlugin; 14 | import io.flutter.plugins.packageinfo.PackageInfoPlugin; 15 | import io.flutter.plugins.pathprovider.PathProviderPlugin; 16 | import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin; 17 | import com.tekartik.sqflite.SqflitePlugin; 18 | import io.flutter.plugins.urllauncher.UrlLauncherPlugin; 19 | 20 | /** 21 | * Generated file. Do not edit. 22 | */ 23 | public final class GeneratedPluginRegistrant { 24 | public static void registerWith(PluginRegistry registry) { 25 | if (alreadyRegisteredWith(registry)) { 26 | return; 27 | } 28 | AndroidAlarmManagerPlugin.registerWith(registry.registrarFor("io.flutter.plugins.androidalarmmanager.AndroidAlarmManagerPlugin")); 29 | CloudFirestorePlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin")); 30 | ConnectivityPlugin.registerWith(registry.registrarFor("io.flutter.plugins.connectivity.ConnectivityPlugin")); 31 | DeviceInfoPlugin.registerWith(registry.registrarFor("io.flutter.plugins.deviceinfo.DeviceInfoPlugin")); 32 | FirebaseAdMobPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebaseadmob.FirebaseAdMobPlugin")); 33 | FirebaseAuthPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebaseauth.FirebaseAuthPlugin")); 34 | FirebaseCorePlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebase.core.FirebaseCorePlugin")); 35 | FirebaseDatabasePlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebase.database.FirebaseDatabasePlugin")); 36 | FirebaseRemoteConfigPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebase.firebaseremoteconfig.FirebaseRemoteConfigPlugin")); 37 | FlutterStringEncryptionPlugin.registerWith(registry.registrarFor("com.github.sroddy.flutterstringencryption.FlutterStringEncryptionPlugin")); 38 | PackageInfoPlugin.registerWith(registry.registrarFor("io.flutter.plugins.packageinfo.PackageInfoPlugin")); 39 | PathProviderPlugin.registerWith(registry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin")); 40 | SharedPreferencesPlugin.registerWith(registry.registrarFor("io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin")); 41 | SqflitePlugin.registerWith(registry.registrarFor("com.tekartik.sqflite.SqflitePlugin")); 42 | UrlLauncherPlugin.registerWith(registry.registrarFor("io.flutter.plugins.urllauncher.UrlLauncherPlugin")); 43 | } 44 | 45 | private static boolean alreadyRegisteredWith(PluginRegistry registry) { 46 | final String key = GeneratedPluginRegistrant.class.getCanonicalName(); 47 | if (registry.hasPlugin(key)) { 48 | return true; 49 | } 50 | registry.registrarFor(key); 51 | return false; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/andrioussolutions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/app/src/main/res/mipmap-hdpi/andrioussolutions.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-ldpi/andrioussolutions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/app/src/main/res/mipmap-ldpi/andrioussolutions.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/andrioussolutions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/app/src/main/res/mipmap-mdpi/andrioussolutions.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/andrioussolutions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/app/src/main/res/mipmap-xhdpi/andrioussolutions.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/andrioussolutions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/app/src/main/res/mipmap-xxhdpi/andrioussolutions.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/andrioussolutions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/app/src/main/res/mipmap-xxxhdpi/andrioussolutions.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.3.1' 9 | 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.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /android/local.properties: -------------------------------------------------------------------------------- 1 | sdk.dir=C:/Programs/Tools/Android/SDK 2 | flutter.sdk=C:\\Programs\\Tools\\flutter 3 | flutter.versionName=1.0.3 4 | flutter.buildMode=debug -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /assets/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/assets/clear.png -------------------------------------------------------------------------------- /assets/cloudy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/assets/cloudy.png -------------------------------------------------------------------------------- /assets/rainy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/assets/rainy.png -------------------------------------------------------------------------------- /assets/snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/assets/snow.png -------------------------------------------------------------------------------- /assets/thunderstorm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/assets/thunderstorm.png -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Generated.xcconfig: -------------------------------------------------------------------------------- 1 | // This is a generated file; do not edit or check into version control. 2 | FLUTTER_ROOT=C:\Programs\Tools\flutter 3 | FLUTTER_APPLICATION_PATH=C:\Programs\Tools\Projects\Flutter\apps\weather_cast 4 | FLUTTER_TARGET=lib\main.dart 5 | FLUTTER_BUILD_DIR=build 6 | SYMROOT=${SOURCE_ROOT}/../build\ios 7 | FLUTTER_FRAMEWORK_DIR=C:\Programs\Tools\flutter\bin\cache\artifacts\engine\ios 8 | FLUTTER_BUILD_NAME=1.0.3 9 | FLUTTER_BUILD_NUMBER=1.0.3 10 | -------------------------------------------------------------------------------- /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 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; }; 12 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 13 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 14 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 15 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 16 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 17 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 18 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 19 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 20 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 21 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 22 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXCopyFilesBuildPhase section */ 26 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 27 | isa = PBXCopyFilesBuildPhase; 28 | buildActionMask = 2147483647; 29 | dstPath = ""; 30 | dstSubfolderSpec = 10; 31 | files = ( 32 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 33 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 34 | ); 35 | name = "Embed Frameworks"; 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXCopyFilesBuildPhase section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 42 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 43 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; }; 44 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 45 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 46 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 47 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 48 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 49 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 50 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 51 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 52 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 54 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 55 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 56 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 57 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 66 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | /* End PBXFrameworksBuildPhase section */ 71 | 72 | /* Begin PBXGroup section */ 73 | 9740EEB11CF90186004384FC /* Flutter */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 2D5378251FAA1A9400D5DBA9 /* flutter_assets */, 77 | 3B80C3931E831B6300D905FE /* App.framework */, 78 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 79 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 80 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 81 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 82 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 83 | ); 84 | name = Flutter; 85 | sourceTree = ""; 86 | }; 87 | 97C146E51CF9000F007C117D = { 88 | isa = PBXGroup; 89 | children = ( 90 | 9740EEB11CF90186004384FC /* Flutter */, 91 | 97C146F01CF9000F007C117D /* Runner */, 92 | 97C146EF1CF9000F007C117D /* Products */, 93 | CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, 94 | ); 95 | sourceTree = ""; 96 | }; 97 | 97C146EF1CF9000F007C117D /* Products */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 97C146EE1CF9000F007C117D /* Runner.app */, 101 | ); 102 | name = Products; 103 | sourceTree = ""; 104 | }; 105 | 97C146F01CF9000F007C117D /* Runner */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 109 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 110 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 111 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 112 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 113 | 97C147021CF9000F007C117D /* Info.plist */, 114 | 97C146F11CF9000F007C117D /* Supporting Files */, 115 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 116 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 117 | ); 118 | path = Runner; 119 | sourceTree = ""; 120 | }; 121 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 122 | isa = PBXGroup; 123 | children = ( 124 | 97C146F21CF9000F007C117D /* main.m */, 125 | ); 126 | name = "Supporting Files"; 127 | sourceTree = ""; 128 | }; 129 | /* End PBXGroup section */ 130 | 131 | /* Begin PBXNativeTarget section */ 132 | 97C146ED1CF9000F007C117D /* Runner */ = { 133 | isa = PBXNativeTarget; 134 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 135 | buildPhases = ( 136 | 9740EEB61CF901F6004384FC /* Run Script */, 137 | 97C146EA1CF9000F007C117D /* Sources */, 138 | 97C146EB1CF9000F007C117D /* Frameworks */, 139 | 97C146EC1CF9000F007C117D /* Resources */, 140 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 141 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 142 | ); 143 | buildRules = ( 144 | ); 145 | dependencies = ( 146 | ); 147 | name = Runner; 148 | productName = Runner; 149 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 150 | productType = "com.apple.product-type.application"; 151 | }; 152 | /* End PBXNativeTarget section */ 153 | 154 | /* Begin PBXProject section */ 155 | 97C146E61CF9000F007C117D /* Project object */ = { 156 | isa = PBXProject; 157 | attributes = { 158 | LastUpgradeCheck = 0910; 159 | ORGANIZATIONNAME = "The Chromium Authors"; 160 | TargetAttributes = { 161 | 97C146ED1CF9000F007C117D = { 162 | CreatedOnToolsVersion = 7.3.1; 163 | }; 164 | }; 165 | }; 166 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 167 | compatibilityVersion = "Xcode 3.2"; 168 | developmentRegion = English; 169 | hasScannedForEncodings = 0; 170 | knownRegions = ( 171 | en, 172 | Base, 173 | ); 174 | mainGroup = 97C146E51CF9000F007C117D; 175 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 176 | projectDirPath = ""; 177 | projectRoot = ""; 178 | targets = ( 179 | 97C146ED1CF9000F007C117D /* Runner */, 180 | ); 181 | }; 182 | /* End PBXProject section */ 183 | 184 | /* Begin PBXResourcesBuildPhase section */ 185 | 97C146EC1CF9000F007C117D /* Resources */ = { 186 | isa = PBXResourcesBuildPhase; 187 | buildActionMask = 2147483647; 188 | files = ( 189 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 190 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 191 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 192 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 193 | 2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */, 194 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | }; 198 | /* End PBXResourcesBuildPhase section */ 199 | 200 | /* Begin PBXShellScriptBuildPhase section */ 201 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 202 | isa = PBXShellScriptBuildPhase; 203 | buildActionMask = 2147483647; 204 | files = ( 205 | ); 206 | inputPaths = ( 207 | ); 208 | name = "Thin Binary"; 209 | outputPaths = ( 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | shellPath = /bin/sh; 213 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 214 | }; 215 | 9740EEB61CF901F6004384FC /* Run Script */ = { 216 | isa = PBXShellScriptBuildPhase; 217 | buildActionMask = 2147483647; 218 | files = ( 219 | ); 220 | inputPaths = ( 221 | ); 222 | name = "Run Script"; 223 | outputPaths = ( 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | shellPath = /bin/sh; 227 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 228 | }; 229 | /* End PBXShellScriptBuildPhase section */ 230 | 231 | /* Begin PBXSourcesBuildPhase section */ 232 | 97C146EA1CF9000F007C117D /* Sources */ = { 233 | isa = PBXSourcesBuildPhase; 234 | buildActionMask = 2147483647; 235 | files = ( 236 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 237 | 97C146F31CF9000F007C117D /* main.m in Sources */, 238 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 239 | ); 240 | runOnlyForDeploymentPostprocessing = 0; 241 | }; 242 | /* End PBXSourcesBuildPhase section */ 243 | 244 | /* Begin PBXVariantGroup section */ 245 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 246 | isa = PBXVariantGroup; 247 | children = ( 248 | 97C146FB1CF9000F007C117D /* Base */, 249 | ); 250 | name = Main.storyboard; 251 | sourceTree = ""; 252 | }; 253 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 254 | isa = PBXVariantGroup; 255 | children = ( 256 | 97C147001CF9000F007C117D /* Base */, 257 | ); 258 | name = LaunchScreen.storyboard; 259 | sourceTree = ""; 260 | }; 261 | /* End PBXVariantGroup section */ 262 | 263 | /* Begin XCBuildConfiguration section */ 264 | 97C147031CF9000F007C117D /* Debug */ = { 265 | isa = XCBuildConfiguration; 266 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 267 | buildSettings = { 268 | ALWAYS_SEARCH_USER_PATHS = NO; 269 | CLANG_ANALYZER_NONNULL = YES; 270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 271 | CLANG_CXX_LIBRARY = "libc++"; 272 | CLANG_ENABLE_MODULES = YES; 273 | CLANG_ENABLE_OBJC_ARC = YES; 274 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 275 | CLANG_WARN_BOOL_CONVERSION = YES; 276 | CLANG_WARN_COMMA = YES; 277 | CLANG_WARN_CONSTANT_CONVERSION = YES; 278 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 279 | CLANG_WARN_EMPTY_BODY = YES; 280 | CLANG_WARN_ENUM_CONVERSION = YES; 281 | CLANG_WARN_INFINITE_RECURSION = YES; 282 | CLANG_WARN_INT_CONVERSION = YES; 283 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 284 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 286 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 287 | CLANG_WARN_STRICT_PROTOTYPES = YES; 288 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 289 | CLANG_WARN_UNREACHABLE_CODE = YES; 290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 291 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 292 | COPY_PHASE_STRIP = NO; 293 | DEBUG_INFORMATION_FORMAT = dwarf; 294 | ENABLE_STRICT_OBJC_MSGSEND = YES; 295 | ENABLE_TESTABILITY = YES; 296 | GCC_C_LANGUAGE_STANDARD = gnu99; 297 | GCC_DYNAMIC_NO_PIC = NO; 298 | GCC_NO_COMMON_BLOCKS = YES; 299 | GCC_OPTIMIZATION_LEVEL = 0; 300 | GCC_PREPROCESSOR_DEFINITIONS = ( 301 | "DEBUG=1", 302 | "$(inherited)", 303 | ); 304 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 305 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 306 | GCC_WARN_UNDECLARED_SELECTOR = YES; 307 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 308 | GCC_WARN_UNUSED_FUNCTION = YES; 309 | GCC_WARN_UNUSED_VARIABLE = YES; 310 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 311 | MTL_ENABLE_DEBUG_INFO = YES; 312 | ONLY_ACTIVE_ARCH = YES; 313 | SDKROOT = iphoneos; 314 | TARGETED_DEVICE_FAMILY = "1,2"; 315 | }; 316 | name = Debug; 317 | }; 318 | 97C147041CF9000F007C117D /* Release */ = { 319 | isa = XCBuildConfiguration; 320 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 321 | buildSettings = { 322 | ALWAYS_SEARCH_USER_PATHS = NO; 323 | CLANG_ANALYZER_NONNULL = YES; 324 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 325 | CLANG_CXX_LIBRARY = "libc++"; 326 | CLANG_ENABLE_MODULES = YES; 327 | CLANG_ENABLE_OBJC_ARC = YES; 328 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 329 | CLANG_WARN_BOOL_CONVERSION = YES; 330 | CLANG_WARN_COMMA = YES; 331 | CLANG_WARN_CONSTANT_CONVERSION = YES; 332 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 333 | CLANG_WARN_EMPTY_BODY = YES; 334 | CLANG_WARN_ENUM_CONVERSION = YES; 335 | CLANG_WARN_INFINITE_RECURSION = YES; 336 | CLANG_WARN_INT_CONVERSION = YES; 337 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 338 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 339 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 340 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 341 | CLANG_WARN_STRICT_PROTOTYPES = YES; 342 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 343 | CLANG_WARN_UNREACHABLE_CODE = YES; 344 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 345 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 346 | COPY_PHASE_STRIP = NO; 347 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 348 | ENABLE_NS_ASSERTIONS = NO; 349 | ENABLE_STRICT_OBJC_MSGSEND = YES; 350 | GCC_C_LANGUAGE_STANDARD = gnu99; 351 | GCC_NO_COMMON_BLOCKS = YES; 352 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 353 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 354 | GCC_WARN_UNDECLARED_SELECTOR = YES; 355 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 356 | GCC_WARN_UNUSED_FUNCTION = YES; 357 | GCC_WARN_UNUSED_VARIABLE = YES; 358 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 359 | MTL_ENABLE_DEBUG_INFO = NO; 360 | SDKROOT = iphoneos; 361 | TARGETED_DEVICE_FAMILY = "1,2"; 362 | VALIDATE_PRODUCT = YES; 363 | }; 364 | name = Release; 365 | }; 366 | 97C147061CF9000F007C117D /* Debug */ = { 367 | isa = XCBuildConfiguration; 368 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 369 | buildSettings = { 370 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 371 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 372 | ENABLE_BITCODE = NO; 373 | FRAMEWORK_SEARCH_PATHS = ( 374 | "$(inherited)", 375 | "$(PROJECT_DIR)/Flutter", 376 | ); 377 | INFOPLIST_FILE = Runner/Info.plist; 378 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 379 | LIBRARY_SEARCH_PATHS = ( 380 | "$(inherited)", 381 | "$(PROJECT_DIR)/Flutter", 382 | ); 383 | PRODUCT_BUNDLE_IDENTIFIER = com.andrioussolutions.weatherCast; 384 | PRODUCT_NAME = "$(TARGET_NAME)"; 385 | VERSIONING_SYSTEM = "apple-generic"; 386 | }; 387 | name = Debug; 388 | }; 389 | 97C147071CF9000F007C117D /* Release */ = { 390 | isa = XCBuildConfiguration; 391 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 392 | buildSettings = { 393 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 394 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 395 | ENABLE_BITCODE = NO; 396 | FRAMEWORK_SEARCH_PATHS = ( 397 | "$(inherited)", 398 | "$(PROJECT_DIR)/Flutter", 399 | ); 400 | INFOPLIST_FILE = Runner/Info.plist; 401 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 402 | LIBRARY_SEARCH_PATHS = ( 403 | "$(inherited)", 404 | "$(PROJECT_DIR)/Flutter", 405 | ); 406 | PRODUCT_BUNDLE_IDENTIFIER = com.andrioussolutions.weatherCast; 407 | PRODUCT_NAME = "$(TARGET_NAME)"; 408 | VERSIONING_SYSTEM = "apple-generic"; 409 | }; 410 | name = Release; 411 | }; 412 | /* End XCBuildConfiguration section */ 413 | 414 | /* Begin XCConfigurationList section */ 415 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 416 | isa = XCConfigurationList; 417 | buildConfigurations = ( 418 | 97C147031CF9000F007C117D /* Debug */, 419 | 97C147041CF9000F007C117D /* Release */, 420 | ); 421 | defaultConfigurationIsVisible = 0; 422 | defaultConfigurationName = Release; 423 | }; 424 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 425 | isa = XCConfigurationList; 426 | buildConfigurations = ( 427 | 97C147061CF9000F007C117D /* Debug */, 428 | 97C147071CF9000F007C117D /* Release */, 429 | ); 430 | defaultConfigurationIsVisible = 0; 431 | defaultConfigurationName = Release; 432 | }; 433 | /* End XCConfigurationList section */ 434 | }; 435 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 436 | } 437 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Andrious/weathercast/2e50f606d46ab67dea65308b134e84b284d7fed7/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/GeneratedPluginRegistrant.h: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #ifndef GeneratedPluginRegistrant_h 6 | #define GeneratedPluginRegistrant_h 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface GeneratedPluginRegistrant : NSObject 13 | + (void)registerWithRegistry:(NSObject*)registry; 14 | @end 15 | 16 | NS_ASSUME_NONNULL_END 17 | #endif /* GeneratedPluginRegistrant_h */ 18 | -------------------------------------------------------------------------------- /ios/Runner/GeneratedPluginRegistrant.m: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | #import "GeneratedPluginRegistrant.h" 6 | 7 | #if __has_include() 8 | #import 9 | #else 10 | @import cloud_firestore; 11 | #endif 12 | 13 | #if __has_include() 14 | #import 15 | #else 16 | @import connectivity; 17 | #endif 18 | 19 | #if __has_include() 20 | #import 21 | #else 22 | @import device_info; 23 | #endif 24 | 25 | #if __has_include() 26 | #import 27 | #else 28 | @import firebase_admob; 29 | #endif 30 | 31 | #if __has_include() 32 | #import 33 | #else 34 | @import firebase_auth; 35 | #endif 36 | 37 | #if __has_include() 38 | #import 39 | #else 40 | @import firebase_core; 41 | #endif 42 | 43 | #if __has_include() 44 | #import 45 | #else 46 | @import firebase_database; 47 | #endif 48 | 49 | #if __has_include() 50 | #import 51 | #else 52 | @import firebase_remote_config; 53 | #endif 54 | 55 | #if __has_include() 56 | #import 57 | #else 58 | @import flutter_string_encryption; 59 | #endif 60 | 61 | #if __has_include() 62 | #import 63 | #else 64 | @import package_info; 65 | #endif 66 | 67 | #if __has_include() 68 | #import 69 | #else 70 | @import path_provider; 71 | #endif 72 | 73 | #if __has_include() 74 | #import 75 | #else 76 | @import shared_preferences; 77 | #endif 78 | 79 | #if __has_include() 80 | #import 81 | #else 82 | @import sqflite; 83 | #endif 84 | 85 | #if __has_include() 86 | #import 87 | #else 88 | @import url_launcher; 89 | #endif 90 | 91 | @implementation GeneratedPluginRegistrant 92 | 93 | + (void)registerWithRegistry:(NSObject*)registry { 94 | [FLTCloudFirestorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTCloudFirestorePlugin"]]; 95 | [FLTConnectivityPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTConnectivityPlugin"]]; 96 | [FLTDeviceInfoPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTDeviceInfoPlugin"]]; 97 | [FLTFirebaseAdMobPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAdMobPlugin"]]; 98 | [FLTFirebaseAuthPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAuthPlugin"]]; 99 | [FLTFirebaseCorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseCorePlugin"]]; 100 | [FLTFirebaseDatabasePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseDatabasePlugin"]]; 101 | [FirebaseRemoteConfigPlugin registerWithRegistrar:[registry registrarForPlugin:@"FirebaseRemoteConfigPlugin"]]; 102 | [FlutterStringEncryptionPlugin registerWithRegistrar:[registry registrarForPlugin:@"FlutterStringEncryptionPlugin"]]; 103 | [FLTPackageInfoPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTPackageInfoPlugin"]]; 104 | [FLTPathProviderPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTPathProviderPlugin"]]; 105 | [FLTSharedPreferencesPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTSharedPreferencesPlugin"]]; 106 | [SqflitePlugin registerWithRegistrar:[registry registrarForPlugin:@"SqflitePlugin"]]; 107 | [FLTURLLauncherPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTURLLauncherPlugin"]]; 108 | } 109 | 110 | @end 111 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | weather_cast 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/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:flutter/material.dart' show runApp; 25 | 26 | import 'package:weathercast/src/view.dart' show App, WeatherApp; 27 | 28 | void main() => runApp(MyApp()); 29 | 30 | class MyApp extends App{ 31 | @override 32 | createView() => WeatherApp(); 33 | } 34 | 35 | 36 | -------------------------------------------------------------------------------- /lib/src/app/controller/weatherapp.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 22 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:weathercast/src/controller.dart' 25 | show Ads, AppController, Platform, ThemeCon; 26 | 27 | import 'package:weathercast/src/home/view/drawer/weather_locations/mvc.dart' 28 | show LocationCon, LocationMod, LocationTimer; 29 | 30 | import 'package:firebase_admob/firebase_admob.dart'; 31 | 32 | class WeatherApp extends AppController { 33 | factory WeatherApp() { 34 | _this ??= WeatherApp._(); 35 | return _this; 36 | } 37 | static WeatherApp _this; 38 | Ads _ads; 39 | 40 | WeatherApp._() : super(){ 41 | _ads = Ads( 42 | Platform.isAndroid 43 | ? 'ca-app-pub-3940256099942544~3347511713' 44 | : 'ca-app-pub-3940256099942544~1458002511', 45 | bannerUnitId: Platform.isAndroid 46 | ? 'ca-app-pub-3940256099942544/6300978111' 47 | : 'ca-app-pub-3940256099942544/2934735716', 48 | screenUnitId: Platform.isAndroid 49 | ? 'ca-app-pub-3940256099942544/1033173712' 50 | : 'ca-app-pub-3940256099942544/4411468910', 51 | videoUnitId: Platform.isAndroid 52 | ? 'ca-app-pub-3940256099942544/5224354917' 53 | : 'ca-app-pub-3940256099942544/1712485313', 54 | keywords: ['weather', 'weather forecast'], 55 | contentUrl: 'http://www.weathernetwork.com', 56 | testing: false, 57 | ); 58 | } 59 | 60 | @override 61 | void initApp() { 62 | stateMVC.add(ThemeCon()); 63 | } 64 | 65 | @override 66 | Future init() async { 67 | bool init = await super.init(); 68 | if (init) init = await LocationCon().init(); 69 | if (init) init = await LocationTimer.init(); 70 | return init; 71 | } 72 | 73 | @override 74 | void initState() { 75 | super.initState(); 76 | _ads.showBannerAd(state: this.stateMVC); 77 | } 78 | 79 | void dispose() { 80 | /// Close the Location database. 81 | LocationMod.dispose(); 82 | _ads.dispose(); 83 | super.dispose(); 84 | } 85 | } 86 | 87 | class FireBaseAds { 88 | 89 | MobileAdTargetingInfo targetingInfo; 90 | BannerAd myBanner; 91 | InterstitialAd myInterstitial; 92 | 93 | FireBaseAds() { 94 | 95 | targetingInfo = MobileAdTargetingInfo( 96 | keywords: ['flutterio', 'beautiful apps'], 97 | contentUrl: 'https://flutter.io', 98 | childDirected: false, 99 | // or MobileAdGender.female, MobileAdGender.unknown 100 | testDevices: [], // Android emulators are considered test devices 101 | ); 102 | 103 | myBanner = BannerAd( 104 | // Replace the testAdUnitId with an ad unit id from the AdMob dash. 105 | // https://developers.google.com/admob/android/test-ads 106 | // https://developers.google.com/admob/ios/test-ads 107 | adUnitId: BannerAd.testAdUnitId, 108 | size: AdSize.smartBanner, 109 | targetingInfo: targetingInfo, 110 | listener: (MobileAdEvent event) { 111 | print("BannerAd event is $event"); 112 | }, 113 | ); 114 | 115 | myInterstitial = InterstitialAd( 116 | // Replace the testAdUnitId with an ad unit id from the AdMob dash. 117 | // https://developers.google.com/admob/android/test-ads 118 | // https://developers.google.com/admob/ios/test-ads 119 | adUnitId: InterstitialAd.testAdUnitId, 120 | targetingInfo: targetingInfo, 121 | listener: (MobileAdEvent event) { 122 | print("InterstitialAd event is $event"); 123 | }, 124 | ); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /lib/src/app/view/utils/gradient_container.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Felix Angelov of Skokie, Illinois 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:flutter/material.dart' 25 | show 26 | Alignment, 27 | BoxDecoration, 28 | BuildContext, 29 | Container, 30 | Key, 31 | LinearGradient, 32 | MaterialColor, 33 | StatelessWidget, 34 | Widget, 35 | required; 36 | 37 | import 'package:meta/meta.dart' show required; 38 | 39 | class GradientContainer extends StatelessWidget { 40 | final Widget child; 41 | final MaterialColor color; 42 | 43 | const GradientContainer({ 44 | Key key, 45 | @required this.color, 46 | @required this.child, 47 | }) : assert(color != null, child != null), 48 | super(key: key); 49 | 50 | @override 51 | Widget build(BuildContext context) { 52 | return Container( 53 | decoration: BoxDecoration( 54 | gradient: LinearGradient( 55 | begin: Alignment.topCenter, 56 | end: Alignment.bottomCenter, 57 | stops: [0.6, 0.8, 1.0], 58 | colors: [ 59 | color[700], 60 | color[500], 61 | color[300], 62 | ], 63 | ), 64 | ), 65 | child: child, 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/src/app/view/weatherapp.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:flutter/material.dart' show ThemeData; 25 | 26 | 27 | import 'package:weathercast/src/view.dart' show AppView, Weather; 28 | 29 | import 'package:weathercast/src/controller.dart' as con; 30 | 31 | class WeatherApp extends AppView { 32 | WeatherApp() 33 | : super( 34 | title: 'Flutter Demo', 35 | con: con.WeatherApp(), 36 | home: Weather(), 37 | ); 38 | 39 | @override 40 | ThemeData onTheme() => con.ThemeCon.theme; 41 | } -------------------------------------------------------------------------------- /lib/src/controller.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | export 'package:mvc_application/controller.dart'; 25 | 26 | export 'package:weathercast/src/app/controller/weatherapp.dart'; 27 | 28 | export 'package:weathercast/src/home/controller/home.dart'; 29 | 30 | export 'package:weathercast/src/home/controller/theme.dart'; 31 | 32 | export 'package:weathercast/src/home/controller/settings.dart'; 33 | 34 | export 'package:weathercast/src/home/controller/weather_repository.dart'; 35 | 36 | export 'package:weathercast/src/home/controller/weather_conditions.dart'; 37 | 38 | export 'package:weathercast/src/home/view/drawer/weather_locations/controller/weather_locations.dart'; 39 | 40 | export 'package:ads/ads.dart' show Ads; 41 | 42 | export 'dart:io' show Platform; 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /lib/src/home/controller/home.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:flutter/material.dart'; 25 | 26 | import 'package:weathercast/src/model.dart' show Weather; 27 | 28 | import 'package:weathercast/src/view.dart' show Switcher; 29 | 30 | import 'package:weathercast/src/controller.dart' 31 | show 32 | ControllerMVC, 33 | LocationCon, 34 | LocationTimer, 35 | Prefs, 36 | Settings, 37 | ThemeCon, 38 | WeatherRepository; 39 | 40 | class WeatherCon extends ControllerMVC { 41 | static WeatherCon _this; 42 | 43 | factory WeatherCon() { 44 | _this ??= WeatherCon._(); 45 | return _this; 46 | } 47 | WeatherCon._(); 48 | 49 | final WeatherRepository weatherRepository = WeatherRepository(); 50 | 51 | String get city => _city; 52 | String _city; 53 | 54 | Weather get weather => _weather; 55 | Weather _weather; 56 | 57 | Future get future => Future.value(_weather); 58 | 59 | bool get error => _error; 60 | bool _error = false; 61 | 62 | @override 63 | void initState() => initFetch(); 64 | 65 | /// Initially retrieve 'the last' city forecast. 66 | Future initFetch() async { 67 | _city = Prefs.getString('city'); 68 | await getWeather(_city); 69 | } 70 | 71 | /// Fetch the data from the database. 72 | Future fetchWeather({String city}) async { 73 | if (city == null) return _weather; 74 | _city = city; 75 | _weather = null; 76 | _error = false; 77 | try { 78 | _weather = await weatherRepository.getWeather(city); 79 | Prefs.setString('city', _city); 80 | LocationCon().save(_city); 81 | } catch (_) { 82 | _error = true; 83 | } 84 | return _weather; 85 | } 86 | 87 | Future getWeather(String city) => 88 | fetchWeather(city: city).then((weather) => rebuild()); 89 | 90 | /// Rebuild the Widget tree. 91 | void rebuild() { 92 | ThemeCon.weatherChanged(condition: weather?.condition).refresh(); 93 | refresh(); 94 | } 95 | 96 | Future refreshWeather({String city}) async { 97 | try { 98 | var weather = await weatherRepository.getWeather(city); 99 | // If there's no error. Record the response. 100 | _weather = weather; 101 | } catch (_) {} 102 | return _weather; 103 | } 104 | 105 | Switcher settingsDrawer(BuildContext context) => Switcher( 106 | temperatureUnits: Settings.temperatureUnits, 107 | onChanged: (bool set) { 108 | Settings.temperatureUnitsToggled(); 109 | WeatherCon().refresh(); 110 | Navigator.pop(context); 111 | }); 112 | 113 | /// Called by the View's onPressed() function. 114 | void onPressed(String city) => getWeather(city); 115 | 116 | void onRefresh() { 117 | refreshWeather(city: city).then((weather) { 118 | rebuild(); 119 | }); 120 | } 121 | 122 | void weatherInterval({int seconds}) { 123 | LocationTimer.setTimer(seconds: seconds); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /lib/src/home/controller/settings.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 14 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:weathercast/src/view.dart' 25 | show TemperatureUnits; 26 | 27 | class Settings { 28 | factory Settings() { 29 | _this ??= Settings._(); 30 | return _this; 31 | } 32 | static Settings _this; 33 | Settings._(); 34 | 35 | static TemperatureUnits _units = TemperatureUnits.celsius; 36 | 37 | static TemperatureUnits get temperatureUnits => _units; 38 | 39 | static temperatureUnitsToggled() { 40 | _units = _units == TemperatureUnits.celsius 41 | ? TemperatureUnits.fahrenheit 42 | : TemperatureUnits.celsius; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/src/home/controller/theme.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:flutter/material.dart' show Colors, MaterialColor, ThemeData; 25 | 26 | import 'package:weathercast/src/model.dart' show WeatherCondition; 27 | 28 | import 'package:weathercast/src/controller.dart' show ControllerMVC; 29 | 30 | class ThemeCon extends ControllerMVC { 31 | factory ThemeCon() => _this; 32 | static final ThemeCon _this = ThemeCon._(); 33 | ThemeCon._(); 34 | 35 | static ThemeData get theme => _theme; 36 | static ThemeData _theme; 37 | 38 | static MaterialColor get color => _color; 39 | static MaterialColor _color; 40 | 41 | static ThemeCon weatherChanged({WeatherCondition condition}) { 42 | switch (condition) { 43 | case WeatherCondition.clear: 44 | case WeatherCondition.lightCloud: 45 | _theme = ThemeData( 46 | primaryColor: Colors.orangeAccent, 47 | ); 48 | _color = Colors.yellow; 49 | break; 50 | case WeatherCondition.hail: 51 | case WeatherCondition.snow: 52 | case WeatherCondition.sleet: 53 | _theme = ThemeData( 54 | primaryColor: Colors.lightBlueAccent, 55 | ); 56 | _color = Colors.lightBlue; 57 | break; 58 | case WeatherCondition.heavyCloud: 59 | _theme = ThemeData( 60 | primaryColor: Colors.blueGrey, 61 | ); 62 | _color = Colors.grey; 63 | 64 | break; 65 | case WeatherCondition.heavyRain: 66 | case WeatherCondition.lightRain: 67 | case WeatherCondition.showers: 68 | _theme = ThemeData( 69 | primaryColor: Colors.indigoAccent, 70 | ); 71 | _color = Colors.indigo; 72 | 73 | break; 74 | case WeatherCondition.thunderstorm: 75 | _theme = ThemeData( 76 | primaryColor: Colors.deepPurpleAccent, 77 | ); 78 | _color = Colors.deepPurple; 79 | break; 80 | case WeatherCondition.unknown: 81 | _theme = ThemeData.light(); 82 | _color = Colors.lightBlue; 83 | break; 84 | } 85 | return _this; 86 | } 87 | } 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /lib/src/home/controller/weather_conditions.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// Original Contributor Felix Angelov of Skokie, Illinois 5 | /// 6 | /// This program is free software; you can redistribute it and/or 7 | /// modify it under the terms of the GNU General Public License 8 | /// as published by the Free Software Foundation; either version 3 9 | /// of the License, or any later version. 10 | /// 11 | /// You may obtain a copy of the License at 12 | /// 13 | /// http://www.apache.org/licenses/LICENSE-2.0 14 | /// 15 | /// 16 | /// Unless required by applicable law or agreed to in writing, software 17 | /// distributed under the License is distributed on an "AS IS" BASIS, 18 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | /// See the License for the specific language governing permissions and 20 | /// limitations under the License. 21 | /// 22 | /// Created 13 Feb 2019 23 | /// 24 | /// 25 | 26 | 27 | import 'package:flutter/material.dart' show BuildContext, Image, Key, StatelessWidget, Widget, required; 28 | 29 | import 'package:meta/meta.dart' show required; 30 | 31 | import 'package:weathercast/src/model.dart' show WeatherCondition; 32 | 33 | class WeatherConditions extends StatelessWidget { 34 | final WeatherCondition condition; 35 | 36 | WeatherConditions({Key key, @required this.condition}) 37 | : assert(condition != null), 38 | super(key: key); 39 | 40 | @override 41 | Widget build(BuildContext context) => _mapConditionToImage(condition); 42 | 43 | Image _mapConditionToImage(WeatherCondition condition) { 44 | Image image; 45 | switch (condition) { 46 | case WeatherCondition.clear: 47 | case WeatherCondition.lightCloud: 48 | image = Image.asset('assets/clear.png'); 49 | break; 50 | case WeatherCondition.hail: 51 | case WeatherCondition.snow: 52 | case WeatherCondition.sleet: 53 | image = Image.asset('assets/snow.png'); 54 | break; 55 | case WeatherCondition.heavyCloud: 56 | image = Image.asset('assets/cloudy.png'); 57 | break; 58 | case WeatherCondition.heavyRain: 59 | case WeatherCondition.lightRain: 60 | case WeatherCondition.showers: 61 | image = Image.asset('assets/rainy.png'); 62 | break; 63 | case WeatherCondition.thunderstorm: 64 | image = Image.asset('assets/thunderstorm.png'); 65 | break; 66 | case WeatherCondition.unknown: 67 | image = Image.asset('assets/clear.png'); 68 | break; 69 | } 70 | return image; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /lib/src/home/controller/weather_repository.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// Original Contributor Felix Angelov of Skokie, Illinois 5 | /// 6 | /// This program is free software; you can redistribute it and/or 7 | /// modify it under the terms of the GNU General Public License 8 | /// as published by the Free Software Foundation; either version 3 9 | /// of the License, or any later version. 10 | /// 11 | /// You may obtain a copy of the License at 12 | /// 13 | /// http://www.apache.org/licenses/LICENSE-2.0 14 | /// 15 | /// 16 | /// Unless required by applicable law or agreed to in writing, software 17 | /// distributed under the License is distributed on an "AS IS" BASIS, 18 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | /// See the License for the specific language governing permissions and 20 | /// limitations under the License. 21 | /// 22 | /// Created 13 Feb 2019 23 | /// 24 | /// 25 | 26 | import 'package:http/http.dart' show Client; 27 | 28 | import 'package:weathercast/src/model.dart' show Weather, WeatherApiClient; 29 | 30 | 31 | class WeatherRepository { 32 | 33 | final WeatherApiClient weatherApiClient = WeatherApiClient( 34 | httpClient: Client(), 35 | ); 36 | 37 | WeatherRepository(); 38 | 39 | Future getWeather(String city) async { 40 | final int locationId = await weatherApiClient.getLocationId(city); 41 | return weatherApiClient.fetchWeather(locationId); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/src/home/model/repositories/weather_api_client.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// Original Contributor Felix Angelov of Skokie, Illinois 5 | /// 6 | /// This program is free software; you can redistribute it and/or 7 | /// modify it under the terms of the GNU General Public License 8 | /// as published by the Free Software Foundation; either version 3 9 | /// of the License, or any later version. 10 | /// 11 | /// You may obtain a copy of the License at 12 | /// 13 | /// http://www.apache.org/licenses/LICENSE-2.0 14 | /// 15 | /// 16 | /// Unless required by applicable law or agreed to in writing, software 17 | /// distributed under the License is distributed on an "AS IS" BASIS, 18 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 19 | /// See the License for the specific language governing permissions and 20 | /// limitations under the License. 21 | /// 22 | /// Created 13 Feb 2019 23 | /// 24 | /// 25 | 26 | 27 | import 'dart:convert' show jsonDecode; 28 | 29 | import 'package:meta/meta.dart' show required; 30 | 31 | import 'package:http/http.dart' show Client; 32 | 33 | import 'package:weathercast/src/model.dart' show Weather; 34 | 35 | class WeatherApiClient { 36 | static const baseUrl = 'https://www.metaweather.com'; 37 | final Client httpClient; 38 | 39 | WeatherApiClient({@required this.httpClient}) : assert(httpClient != null); 40 | 41 | Future getLocationId(String city) async { 42 | final locationUrl = '$baseUrl/api/location/search/?query=$city'; 43 | final locationResponse = await this.httpClient.get(locationUrl); 44 | if (locationResponse.statusCode != 200) { 45 | throw Exception('error getting locationId for city'); 46 | } 47 | 48 | final locationJson = jsonDecode(locationResponse.body) as List; 49 | return (locationJson.first)['woeid']; 50 | } 51 | 52 | Future fetchWeather(int locationId) async { 53 | final weatherUrl = '$baseUrl/api/location/$locationId'; 54 | final weatherResponse = await this.httpClient.get(weatherUrl); 55 | 56 | if (weatherResponse.statusCode != 200) { 57 | throw Exception('error getting weather for location'); 58 | } 59 | 60 | final weatherJson = jsonDecode(weatherResponse.body); 61 | return Weather.fromJson(weatherJson); 62 | } 63 | } -------------------------------------------------------------------------------- /lib/src/home/model/weather_model.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Felix Angelov of Skokie, Illinois 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:equatable/equatable.dart' show Equatable; 25 | 26 | enum WeatherCondition { 27 | snow, 28 | sleet, 29 | hail, 30 | thunderstorm, 31 | heavyRain, 32 | lightRain, 33 | showers, 34 | heavyCloud, 35 | lightCloud, 36 | clear, 37 | unknown 38 | } 39 | 40 | class Weather extends Equatable { 41 | final WeatherCondition condition; 42 | final String formattedCondition; 43 | final double minTemp; 44 | final double temp; 45 | final double maxTemp; 46 | final int locationId; 47 | final String created; 48 | final DateTime lastUpdated; 49 | final String location; 50 | 51 | const Weather({ 52 | this.condition, 53 | this.formattedCondition, 54 | this.minTemp, 55 | this.temp, 56 | this.maxTemp, 57 | this.locationId, 58 | this.created, 59 | this.lastUpdated, 60 | this.location, 61 | }); 62 | 63 | /// @override 64 | List get props => [ 65 | condition, 66 | formattedCondition, 67 | minTemp, 68 | temp, 69 | maxTemp, 70 | locationId, 71 | created, 72 | lastUpdated, 73 | location, 74 | ]; 75 | 76 | static Weather fromJson(dynamic json) { 77 | final consolidatedWeather = json['consolidated_weather'][0]; 78 | return Weather( 79 | condition: _mapStringToWeatherCondition( 80 | consolidatedWeather['weather_state_abbr']), 81 | formattedCondition: consolidatedWeather['weather_state_name'], 82 | minTemp: consolidatedWeather['min_temp'] as double, 83 | temp: consolidatedWeather['the_temp'] as double, 84 | maxTemp: consolidatedWeather['max_temp'] as double, 85 | locationId: json['woeid'] as int, 86 | created: consolidatedWeather['created'], 87 | lastUpdated: DateTime.now(), 88 | location: json['title'], 89 | ); 90 | } 91 | 92 | static WeatherCondition _mapStringToWeatherCondition(String input) { 93 | WeatherCondition state; 94 | switch (input) { 95 | case 'sn': 96 | state = WeatherCondition.snow; 97 | break; 98 | case 'sl': 99 | state = WeatherCondition.sleet; 100 | break; 101 | case 'h': 102 | state = WeatherCondition.hail; 103 | break; 104 | case 't': 105 | state = WeatherCondition.thunderstorm; 106 | break; 107 | case 'hr': 108 | state = WeatherCondition.heavyRain; 109 | break; 110 | case 'lr': 111 | state = WeatherCondition.lightRain; 112 | break; 113 | case 's': 114 | state = WeatherCondition.showers; 115 | break; 116 | case 'hc': 117 | state = WeatherCondition.heavyCloud; 118 | break; 119 | case 'lc': 120 | state = WeatherCondition.lightCloud; 121 | break; 122 | case 'c': 123 | state = WeatherCondition.clear; 124 | break; 125 | default: 126 | state = WeatherCondition.unknown; 127 | } 128 | return state; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /lib/src/home/view/child/city_selection.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Felix Angelov of Skokie, Illinois 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:flutter/material.dart' 25 | show 26 | AppBar, 27 | BuildContext, 28 | EdgeInsets, 29 | Expanded, 30 | Form, 31 | Icon, 32 | IconButton, 33 | Icons, 34 | InputDecoration, 35 | Navigator, 36 | Padding, 37 | Row, 38 | Scaffold, 39 | State, 40 | StatefulWidget, 41 | Text, 42 | TextEditingController, 43 | TextFormField, 44 | Widget; 45 | 46 | import 'package:weathercast/src/home/view/drawer/weather_locations/mvc.dart' show LocationTimer; 47 | 48 | class CitySelection extends StatefulWidget { 49 | @override 50 | State createState() => _CitySelectionState(); 51 | } 52 | 53 | class _CitySelectionState extends State { 54 | final TextEditingController _textController = TextEditingController(); 55 | 56 | @override 57 | void initState(){ 58 | super.initState(); 59 | LocationTimer.initState(); 60 | } 61 | 62 | @override 63 | void dispose(){ 64 | LocationTimer.dispose(); 65 | super.dispose(); 66 | } 67 | 68 | @override 69 | Widget build(BuildContext context) { 70 | return Scaffold( 71 | appBar: AppBar( 72 | title: Text('City'), 73 | ), 74 | body: Form( 75 | child: Row( 76 | children: [ 77 | Expanded( 78 | child: Padding( 79 | padding: EdgeInsets.only(left: 10.0), 80 | child: TextFormField( 81 | controller: _textController, 82 | decoration: InputDecoration( 83 | labelText: 'City', 84 | hintText: 'Chicago', 85 | ), 86 | ), 87 | ), 88 | ), 89 | IconButton( 90 | icon: Icon(Icons.search), 91 | onPressed: () { 92 | Navigator.pop(context, _textController.text); 93 | }, 94 | ) 95 | ], 96 | ), 97 | ), 98 | ); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /lib/src/home/view/child/last_updated.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Felix Angelov of Skokie, Illinois 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:flutter/material.dart' 25 | show 26 | BuildContext, 27 | Colors, 28 | FontWeight, 29 | Key, 30 | StatelessWidget, 31 | Text, 32 | TextStyle, 33 | TimeOfDay, 34 | Widget, 35 | required; 36 | 37 | import 'package:meta/meta.dart' show required; 38 | 39 | class LastUpdated extends StatelessWidget { 40 | final DateTime dateTime; 41 | 42 | LastUpdated({Key key, @required this.dateTime}) 43 | : assert(dateTime != null), 44 | super(key: key); 45 | 46 | @override 47 | Widget build(BuildContext context) { 48 | return Text( 49 | 'Updated: ${TimeOfDay.fromDateTime(dateTime).format(context)}', 50 | style: TextStyle( 51 | fontSize: 18.0, 52 | fontWeight: FontWeight.w200, 53 | color: Colors.white, 54 | ), 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /lib/src/home/view/child/temperature.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Felix Angelov of Skokie, Illinois 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:flutter/material.dart' 25 | show 26 | BuildContext, 27 | Colors, 28 | Column, 29 | EdgeInsets, 30 | FontWeight, 31 | Key, 32 | Padding, 33 | Row, 34 | StatelessWidget, 35 | Text, 36 | TextStyle, 37 | Widget; 38 | 39 | enum TemperatureUnits { fahrenheit, celsius } 40 | 41 | class Temperature extends StatelessWidget { 42 | final double temperature; 43 | final double low; 44 | final double high; 45 | final TemperatureUnits units; 46 | 47 | Temperature({ 48 | Key key, 49 | this.temperature, 50 | this.low, 51 | this.high, 52 | this.units, 53 | }) : super(key: key); 54 | 55 | @override 56 | Widget build(BuildContext context) { 57 | return Row( 58 | children: [ 59 | Padding( 60 | padding: EdgeInsets.only(right: 20.0), 61 | child: Text( 62 | '${_formattedTemperature(temperature)}°', 63 | style: TextStyle( 64 | fontSize: 32.0, 65 | fontWeight: FontWeight.w600, 66 | color: Colors.white, 67 | ), 68 | ), 69 | ), 70 | Column( 71 | children: [ 72 | Text( 73 | 'max: ${_formattedTemperature(high)}°', 74 | style: TextStyle( 75 | fontSize: 16.0, 76 | fontWeight: FontWeight.w100, 77 | color: Colors.white, 78 | ), 79 | ), 80 | Text( 81 | 'min: ${_formattedTemperature(low)}°', 82 | style: TextStyle( 83 | fontSize: 16.0, 84 | fontWeight: FontWeight.w100, 85 | color: Colors.white, 86 | ), 87 | ) 88 | ], 89 | ) 90 | ], 91 | ); 92 | } 93 | 94 | int _toFahrenheit(double celsius) => ((celsius * 9 / 5) + 32).round(); 95 | 96 | int _formattedTemperature(double t) => 97 | units == TemperatureUnits.fahrenheit ? _toFahrenheit(t) : t.round(); 98 | } 99 | -------------------------------------------------------------------------------- /lib/src/home/view/child/weather_temperature.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Felix Angelov of Skokie, Illinois 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:flutter/material.dart' 25 | show 26 | BuildContext, 27 | Center, 28 | Colors, 29 | Column, 30 | EdgeInsets, 31 | FontWeight, 32 | Key, 33 | MainAxisAlignment, 34 | Padding, 35 | Row, 36 | StatelessWidget, 37 | Text, 38 | TextStyle, 39 | Widget, 40 | required; 41 | 42 | import 'package:meta/meta.dart' show required; 43 | 44 | import 'package:weathercast/src/model.dart' show Weather; 45 | 46 | import 'package:weathercast/src/view.dart' show Temperature; 47 | 48 | import 'package:weathercast/src/controller.dart' 49 | show Settings, WeatherConditions; 50 | 51 | class WeatherTemperature extends StatelessWidget { 52 | final Weather weather; 53 | 54 | WeatherTemperature({ 55 | Key key, 56 | @required this.weather, 57 | }) : assert(weather != null), 58 | super(key: key); 59 | 60 | @override 61 | Widget build(BuildContext context) { 62 | return Column( 63 | children: [ 64 | Row( 65 | mainAxisAlignment: MainAxisAlignment.center, 66 | children: [ 67 | Padding( 68 | padding: EdgeInsets.all(20.0), 69 | child: WeatherConditions(condition: weather.condition), 70 | ), 71 | Padding( 72 | padding: EdgeInsets.all(20.0), 73 | child: Temperature( 74 | temperature: weather.temp, 75 | high: weather.maxTemp, 76 | low: weather.minTemp, 77 | units: Settings.temperatureUnits, 78 | ), 79 | ), 80 | ], 81 | ), 82 | Center( 83 | child: Text( 84 | weather.formattedCondition, 85 | style: TextStyle( 86 | fontSize: 30.0, 87 | fontWeight: FontWeight.w200, 88 | color: Colors.white, 89 | ), 90 | ), 91 | ), 92 | ], 93 | ); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /lib/src/home/view/drawer/settings_drawer.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2018 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 10 Sep 2018 21 | /// 22 | 23 | import 'package:flutter/material.dart'; 24 | 25 | import 'package:weathercast/src/view.dart' show StateMVC, TemperatureUnits; 26 | 27 | import 'package:weathercast/src/controller.dart' 28 | show LocationCon, LocationTimer, WeatherCon; 29 | 30 | import 'package:weathercast/src/home/view/drawer/weather_locations/mvc.dart' 31 | show LocationCon, DemoItem; 32 | 33 | class SettingsDrawer extends StatefulWidget { 34 | SettingsDrawer({this.con, Key key}) : super(key: key); 35 | final Switcher con; 36 | @override 37 | _SettingsDrawerState createState() => _SettingsDrawerState(); 38 | } 39 | 40 | class _SettingsDrawerState extends StateMVC { 41 | _SettingsDrawerState() : super(LocationCon()); 42 | List> _demoItems; 43 | double _discreteValue = LocationTimer.intervals.toDouble(); 44 | 45 | @override 46 | void initState() { 47 | super.initState(); 48 | LocationTimer.initState(); 49 | _demoItems = LocationCon().listLocations( 50 | state: this, 51 | onSaved: (String v) { 52 | WeatherCon().getWeather(v); 53 | Navigator.pop(context); 54 | }); 55 | } 56 | 57 | @override 58 | void dispose() { 59 | LocationTimer.dispose(); 60 | super.dispose(); 61 | } 62 | 63 | @override 64 | Widget build(BuildContext context) { 65 | bool unitSet = widget.con.temperatureUnits == TemperatureUnits.celsius; 66 | String unitLabel = unitSet ? 'Celsius' : 'Fahrenheit'; 67 | String subTitle = 68 | 'Use ${unitSet ? 'metric' : 'imperial'} measurements for temperatur untis'; 69 | return Drawer( 70 | child: ListView( 71 | // Important: Remove any padding from the ListView. 72 | padding: EdgeInsets.zero, 73 | children: [ 74 | DrawerHeader( 75 | child: Text( 76 | 'Settings', 77 | style: const TextStyle(color: Colors.white), 78 | ), 79 | decoration: const BoxDecoration( 80 | color: Colors.blue, 81 | ), 82 | ), 83 | ListTile( 84 | title: const Text('Temperature Untis'), 85 | subtitle: Text(subTitle), 86 | trailing: Switch( 87 | value: unitSet, 88 | onChanged: widget.con.onChanged, 89 | ), 90 | ), 91 | SafeArea( 92 | top: false, 93 | bottom: false, 94 | child: Container( 95 | margin: const EdgeInsets.all(24.0), 96 | child: ExpansionPanelList( 97 | expansionCallback: (int index, bool isExpanded) { 98 | setState(() { 99 | _demoItems[index].isExpanded = !isExpanded; 100 | }); 101 | }, 102 | children: _demoItems.map((DemoItem item) { 103 | return ExpansionPanel( 104 | isExpanded: item.isExpanded, 105 | headerBuilder: item.headerBuilder, 106 | body: item.build()); 107 | }).toList()), 108 | ), 109 | ), 110 | Slider( 111 | value: _discreteValue, 112 | min: 0.0, 113 | max: 10.0, 114 | divisions: 2, 115 | label: '${_discreteValue.round()}', 116 | onChanged: (double value) { 117 | setState(() { 118 | _discreteValue = value; 119 | Navigator.pop(context); 120 | }); 121 | }, 122 | ), 123 | ]), 124 | ); 125 | } 126 | 127 | static void onTap() { 128 | var test = true; 129 | } 130 | } 131 | 132 | class Switcher { 133 | Switcher({this.temperatureUnits, this.onChanged}); 134 | TemperatureUnits temperatureUnits = TemperatureUnits.celsius; 135 | ValueChanged onChanged = (bool value) {}; 136 | } 137 | -------------------------------------------------------------------------------- /lib/src/home/view/drawer/weather_locations/controller/weather_locations.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 21 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'dart:core' 25 | show Duration, Future, List, String, bool, dynamic, int; 26 | 27 | import 'dart:async' show Future, Timer; 28 | 29 | import 'package:flutter/material.dart'; 30 | 31 | import 'package:weathercast/src/view.dart' show StateMVC; 32 | 33 | import 'package:weathercast/src/controller.dart' 34 | show ControllerMVC, Prefs, WeatherCon; 35 | 36 | import 'package:weathercast/src/home/view/drawer/weather_locations/mvc.dart' 37 | show DemoItem, LocationMod, weatherLocations; 38 | 39 | /// Weather forecast locations controller. 40 | class LocationCon extends ControllerMVC { 41 | factory LocationCon() { 42 | _this ??= LocationCon._(); 43 | return _this; 44 | } 45 | // Make only one instance of this class. 46 | static LocationCon _this; 47 | LocationCon._(); 48 | 49 | static List get locations => _locations; 50 | static List _locations; 51 | 52 | static String get value => _value; 53 | static String _value = LocationMod.city; 54 | 55 | /// Called by the App's init() function. 56 | Future init() async { 57 | bool init = await LocationMod.openDB(); 58 | try { 59 | if (init) { 60 | _locations = await LocationMod.getLocations(); 61 | } 62 | } catch (ex) { 63 | _locations = []; 64 | } 65 | return init; 66 | } 67 | 68 | /// Return a list of locations. 69 | List> listLocations( 70 | {StateMVC state, FormFieldSetter onSaved}) => 71 | weatherLocations(state: state, onSaved: onSaved); 72 | 73 | /// Called to retrieve the list of Weather forecast locations. 74 | Future> rebuild() async { 75 | _locations = await LocationMod.getLocations(); 76 | super.refresh(); 77 | return _locations; 78 | } 79 | 80 | /// Returns a row representing one particular location. 81 | static Row option(int index, FormFieldState field) { 82 | String location = _locations?.elementAt(index); 83 | return Row(mainAxisSize: MainAxisSize.min, children: [ 84 | Radio( 85 | value: location, 86 | groupValue: field.value, 87 | onChanged: field.didChange, 88 | ), 89 | Text(location), 90 | FlatButton( 91 | onPressed: () { 92 | LocationCon().delete(location); 93 | }, 94 | child: Icon(Icons.clear, color: Colors.grey), 95 | ), 96 | ]); 97 | } 98 | 99 | /// Save the specified location to the database. 100 | Future save(String value) => LocationMod.saveLocation(city: value); 101 | 102 | Future delete(String value) async { 103 | bool delete = await LocationMod.deleteCity(value); 104 | refresh(); 105 | return delete; 106 | } 107 | } 108 | 109 | typedef TimerCallback = void Function(Timer timer); 110 | 111 | /// The Location Timer to 'cycle' through the weather forecast location. 112 | class LocationTimer { 113 | static Timer _timer; 114 | 115 | /// A counter to iterate through the locations. 116 | static int _index = 0; 117 | 118 | /// Number of seconds between intervals. 119 | static int _seconds = 0; 120 | 121 | /// The callback function executed between intervals. 122 | static TimerCallback _callback = _timerCallback; 123 | 124 | /// Gets the number of seconds between intervals. 125 | static int get intervals => _seconds; 126 | 127 | /// Called in the App's init() function. 128 | static Future init() async { 129 | _index = LocationCon._locations.indexOf(LocationCon.value); 130 | int seconds = await Prefs.getIntF('intervals'); 131 | setTimer(seconds: seconds); 132 | return Future.value(true); 133 | } 134 | 135 | /// Turn off the timer 136 | static void initState() { 137 | cancel(); 138 | } 139 | 140 | /// Restart the timer. 141 | static void dispose() { 142 | setTimer(); 143 | } 144 | 145 | /// Starts the timer with the specified interval and callback function. 146 | static void setTimer({int seconds, TimerCallback callback}) { 147 | if (seconds != null) { 148 | if (seconds < 0) seconds = 0; 149 | _seconds = seconds; 150 | } 151 | if (_seconds == 0) { 152 | cancel(); 153 | return; 154 | } 155 | if (callback != null) { 156 | cancel(); 157 | _callback = callback; 158 | } 159 | if (_callback == null) { 160 | cancel(); 161 | return; 162 | } 163 | _timer = Timer.periodic(Duration(seconds: _seconds), _callback); 164 | Prefs.setInt('intervals', _seconds); 165 | } 166 | 167 | /// Turn off the Timer. 168 | static void cancel() { 169 | if (_timer != null && _timer.isActive) { 170 | _timer.cancel(); 171 | _timer = null; 172 | } 173 | } 174 | 175 | /// The Callback timer assigned by default. 176 | static _timerCallback(Timer timer) { 177 | List locations = LocationCon.locations; 178 | if (locations == null || locations.length < 2) return; 179 | if (_index < 0) _index = 0; 180 | String location = locations.elementAt(_index); 181 | _index++; 182 | if (_index == locations.length) _index = 0; 183 | WeatherCon().getWeather(location); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /lib/src/home/view/drawer/weather_locations/model/weather_locations.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 21 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:weathercast/src/model.dart'; 25 | 26 | class LocationMod extends SQLiteDB { 27 | factory LocationMod() { 28 | _this ??= LocationMod._(); 29 | return _this; 30 | } 31 | // Make only one instance of this class. 32 | static LocationMod _this; 33 | LocationMod._(); 34 | 35 | @override 36 | get name => 'Weather'; 37 | 38 | @override 39 | get version => 1; 40 | 41 | static const String tableName = 'Locations'; 42 | static List _locations = []; 43 | 44 | @override 45 | Future onCreate(Database db, int version) async { 46 | await db.execute(""" 47 | CREATE TABLE $tableName( 48 | id INTEGER PRIMARY KEY 49 | ,city TEXT 50 | ,deleted INTEGER DEFAULT 0 51 | ) 52 | """); 53 | } 54 | 55 | static Future openDB() => LocationMod().open(); 56 | 57 | static void dispose() => LocationMod().disposed(); 58 | 59 | static Future> getLocations() async { 60 | List> locations; 61 | locations = await getRecs(); 62 | for (Map location in locations) { 63 | _locations.add(location['city']); 64 | } 65 | return _locations; 66 | } 67 | 68 | static String get city => _city; 69 | static String _city = Prefs.getString('city', 'Chicago'); 70 | 71 | static Future saveLocation({String city}) async { 72 | bool saved = true; 73 | if (city == null || city.isEmpty) return saved; 74 | _city = city; 75 | if (!_locations.contains(city)) { 76 | Map rec = await LocationMod().saveMap(tableName, {'city': city}); 77 | saved = rec.isNotEmpty; 78 | if (saved) _locations.add(city); 79 | } 80 | return saved; 81 | } 82 | 83 | static Future>> getRecs() async { 84 | List> recs; 85 | 86 | try { 87 | recs = await LocationMod() 88 | .rawQuery('SELECT * FROM $tableName WHERE deleted = 0'); 89 | } catch (ex) { 90 | recs = []; 91 | } 92 | return recs; 93 | } 94 | 95 | static Future deleteCity(String city) async { 96 | List> recs = await getRecs(); 97 | int id = -1; 98 | for (Map rec in recs) { 99 | if (rec['city'] == city) { 100 | id = rec['id']; 101 | break; 102 | } 103 | } 104 | bool delete = id > -1; 105 | if(delete) delete = await LocationMod().delete(tableName, id) > 0; 106 | return delete; 107 | } 108 | 109 | Future onConfigure(Database db) { 110 | return db.execute("PRAGMA foreign_keys=ON;"); 111 | } 112 | } 113 | 114 | class Location implements Comparable { 115 | Location.fromMap(Map m) { 116 | city = m["city"]; 117 | } 118 | 119 | Map get toMap => {"city": _city}; 120 | 121 | String get city => _city; 122 | set city(String value) { 123 | if (value == null) value = ""; 124 | _city = value.trim(); 125 | } 126 | 127 | String _city; 128 | 129 | int compareTo(Location other) => _city.compareTo(other._city); 130 | 131 | static Future> listLocations( 132 | List> query) async { 133 | List locationList = []; 134 | for (Map city in query) { 135 | Location location = Location.fromMap(city); 136 | locationList.add(location); 137 | } 138 | return locationList; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /lib/src/home/view/drawer/weather_locations/mvc.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 21 Feb 2019 21 | /// 22 | /// 23 | 24 | export 'package:weathercast/src/home/view/drawer/weather_locations/model/weather_locations.dart'; 25 | 26 | export 'package:weathercast/src/home/view/drawer/weather_locations/view/weather_locations.dart'; 27 | 28 | export 'package:weathercast/src/home/view/drawer/weather_locations/controller/weather_locations.dart'; 29 | 30 | -------------------------------------------------------------------------------- /lib/src/home/view/drawer/weather_locations/view/weather_locations.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 21 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:flutter/material.dart'; 25 | 26 | import 'package:weathercast/src/view.dart' show StateMVC; 27 | 28 | import 'package:weathercast/src/home/view/drawer/weather_locations/mvc.dart' 29 | show LocationCon; 30 | 31 | List> weatherLocations( 32 | {StateMVC state, FormFieldSetter onSaved}) { 33 | 34 | List> _demoItems = >[ 35 | DemoItem( 36 | name: 'Location', 37 | value: LocationCon.value, 38 | hint: 'Select location', 39 | valueToString: (String location) => location, 40 | builder: (DemoItem item) { 41 | void close() { 42 | state.setState(() { 43 | item.isExpanded = false; 44 | }); 45 | } 46 | 47 | return Form(child: Builder(builder: (BuildContext context) { 48 | return CollapsibleBody( 49 | onSave: () { 50 | Form.of(context).save(); 51 | close(); 52 | }, 53 | onCancel: () { 54 | Form.of(context).reset(); 55 | close(); 56 | }, 57 | child: FormField( 58 | initialValue: item.value, 59 | onSaved: (String result) { 60 | item.value = result; 61 | if (onSaved != null) onSaved(result); 62 | }, 63 | builder: (FormFieldState field) { 64 | return Column(mainAxisSize: MainAxisSize.min, children:[ 65 | Flexible( 66 | flex: 1, 67 | fit: FlexFit.loose, 68 | child: ListView.builder( 69 | shrinkWrap: true, 70 | itemCount: LocationCon.locations?.length ?? 0, 71 | itemBuilder: (BuildContext context, int index) { 72 | return LocationCon.option(index, field); 73 | })), 74 | ]); 75 | }), 76 | ); 77 | })); 78 | }) 79 | ]; 80 | 81 | return _demoItems; 82 | } 83 | 84 | typedef DemoItemBodyBuilder = Widget Function(DemoItem item); 85 | typedef ValueToString = String Function(T value); 86 | 87 | class DemoItem { 88 | DemoItem({this.name, this.value, this.hint, this.builder, this.valueToString}) 89 | : textController = TextEditingController(text: valueToString(value)); 90 | 91 | final String name; 92 | final String hint; 93 | final TextEditingController textController; 94 | final DemoItemBodyBuilder builder; 95 | final ValueToString valueToString; 96 | T value; 97 | bool isExpanded = false; 98 | 99 | ExpansionPanelHeaderBuilder get headerBuilder { 100 | return (BuildContext context, bool isExpanded) { 101 | return DualHeaderWithHint( 102 | name: name, 103 | value: valueToString(value), 104 | hint: hint, 105 | showHint: isExpanded); 106 | }; 107 | } 108 | 109 | Widget build() => builder(this); 110 | } 111 | 112 | class DualHeaderWithHint extends StatelessWidget { 113 | const DualHeaderWithHint({this.name, this.value, this.hint, this.showHint}); 114 | 115 | final String name; 116 | final String value; 117 | final String hint; 118 | final bool showHint; 119 | 120 | Widget _crossFade(Widget first, Widget second, bool isExpanded) { 121 | return AnimatedCrossFade( 122 | firstChild: first, 123 | secondChild: second, 124 | firstCurve: const Interval(0.0, 0.6, curve: Curves.fastOutSlowIn), 125 | secondCurve: const Interval(0.4, 1.0, curve: Curves.fastOutSlowIn), 126 | sizeCurve: Curves.fastOutSlowIn, 127 | crossFadeState: 128 | isExpanded ? CrossFadeState.showSecond : CrossFadeState.showFirst, 129 | duration: const Duration(milliseconds: 200), 130 | ); 131 | } 132 | 133 | @override 134 | Widget build(BuildContext context) { 135 | final ThemeData theme = Theme.of(context); 136 | final TextTheme textTheme = theme.textTheme; 137 | 138 | return Row(children: [ 139 | Expanded( 140 | flex: 2, 141 | child: Container( 142 | margin: const EdgeInsets.only(left: 24.0), 143 | child: FittedBox( 144 | fit: BoxFit.scaleDown, 145 | alignment: Alignment.centerLeft, 146 | child: Text( 147 | name, 148 | style: textTheme.body1.copyWith(fontSize: 15.0), 149 | ), 150 | ), 151 | ), 152 | ), 153 | Expanded( 154 | flex: 3, 155 | child: Container( 156 | margin: const EdgeInsets.only(left: 24.0), 157 | child: _crossFade( 158 | Text(value, 159 | style: textTheme.caption.copyWith(fontSize: 15.0)), 160 | Text(hint, style: textTheme.caption.copyWith(fontSize: 15.0)), 161 | showHint))) 162 | ]); 163 | } 164 | } 165 | 166 | class CollapsibleBody extends StatelessWidget { 167 | const CollapsibleBody( 168 | {this.margin = EdgeInsets.zero, this.child, this.onSave, this.onCancel}); 169 | 170 | final EdgeInsets margin; 171 | final Widget child; 172 | final VoidCallback onSave; 173 | final VoidCallback onCancel; 174 | 175 | @override 176 | Widget build(BuildContext context) { 177 | final ThemeData theme = Theme.of(context); 178 | final TextTheme textTheme = theme.textTheme; 179 | 180 | return Column(children: [ 181 | Container( 182 | margin: const EdgeInsets.only(left: 24.0, right: 24.0, bottom: 24.0) - 183 | margin, 184 | child: Center( 185 | child: DefaultTextStyle( 186 | style: textTheme.caption.copyWith(fontSize: 15.0), 187 | child: child))), 188 | const Divider(height: 1.0), 189 | Container( 190 | padding: const EdgeInsets.symmetric(vertical: 16.0), 191 | child: 192 | Row(mainAxisAlignment: MainAxisAlignment.end, children: [ 193 | Container( 194 | margin: const EdgeInsets.only(right: 8.0), 195 | child: FlatButton( 196 | onPressed: onCancel, 197 | child: const Text('CANCEL', 198 | style: TextStyle( 199 | color: Colors.black54, 200 | fontSize: 15.0, 201 | fontWeight: FontWeight.w500)))), 202 | Container( 203 | margin: const EdgeInsets.only(right: 8.0), 204 | child: FlatButton( 205 | onPressed: onSave, 206 | textTheme: ButtonTextTheme.accent, 207 | child: const Text('SAVE'))) 208 | ])) 209 | ]); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /lib/src/home/view/home.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 22 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'dart:async' show Completer, Future; 25 | 26 | import 'package:flutter/material.dart'; 27 | 28 | import 'package:weathercast/src/model.dart' as model; 29 | 30 | import 'package:weathercast/src/view.dart' 31 | show 32 | CitySelection, 33 | GradientContainer, 34 | LastUpdated, 35 | Location, 36 | SettingsDrawer, 37 | StateMVC, 38 | TemperatureUnits, 39 | WeatherTemperature; 40 | 41 | import 'package:weathercast/src/controller.dart' 42 | show Settings, ThemeCon, WeatherCon; 43 | 44 | class Weather extends StatefulWidget { 45 | Weather({Key key}) : super(key: key); 46 | 47 | @override 48 | State createState() => _WeatherState(); 49 | } 50 | 51 | class _WeatherState extends StateMVC { 52 | _WeatherState() : super(WeatherCon()) { 53 | _weatherCon = controller; 54 | } 55 | WeatherCon _weatherCon; 56 | Completer _refreshCompleter = Completer(); 57 | 58 | // Scaffold key 59 | final GlobalKey _scaffoldKey = GlobalKey(); 60 | 61 | @override 62 | Widget build(BuildContext context) { 63 | return Scaffold( 64 | key: _scaffoldKey, 65 | endDrawer: SettingsDrawer(con: _weatherCon.settingsDrawer(context)), 66 | appBar: AppBar( 67 | title: Text('Flutter Weather'), 68 | actions: [ 69 | IconButton( 70 | icon: new Icon(Icons.settings), 71 | onPressed: () => _scaffoldKey.currentState.openEndDrawer()), 72 | IconButton( 73 | icon: Icon(Icons.search), 74 | onPressed: () async { 75 | String city = await Navigator.push( 76 | context, 77 | MaterialPageRoute( 78 | builder: (context) => CitySelection(), 79 | ), 80 | ); 81 | _weatherCon.onPressed(city); 82 | }, 83 | ) 84 | ], 85 | ), 86 | body: Center( 87 | child: Builder(builder: (_) { 88 | if (_weatherCon.city == null || _weatherCon.city.isEmpty) { 89 | return Text('Please Select a Location'); 90 | } 91 | if (_weatherCon.error) { 92 | return Text( 93 | 'Something went wrong!', 94 | style: TextStyle(color: Colors.red), 95 | ); 96 | } 97 | if (_weatherCon.weather == null) { 98 | return CircularProgressIndicator(); 99 | } 100 | final model.Weather weather = _weatherCon.weather; 101 | 102 | _refreshCompleter?.complete(); 103 | _refreshCompleter = Completer(); 104 | 105 | return GradientContainer( 106 | color: ThemeCon.color, 107 | child: RefreshIndicator( 108 | onRefresh: () { 109 | _weatherCon.onRefresh(); 110 | return _refreshCompleter.future; 111 | }, 112 | child: ListView( 113 | children: [ 114 | Padding( 115 | padding: EdgeInsets.only(top: 100.0), 116 | child: Center( 117 | child: Location(location: weather.location), 118 | ), 119 | ), 120 | Center( 121 | child: LastUpdated(dateTime: weather.lastUpdated), 122 | ), 123 | Padding( 124 | padding: EdgeInsets.symmetric(vertical: 50.0), 125 | child: Center( 126 | child: WeatherTemperature( 127 | weather: weather, 128 | ), 129 | ), 130 | ), 131 | ], 132 | ), 133 | ), 134 | ); 135 | }), 136 | ), 137 | ); 138 | } 139 | } 140 | 141 | class WeatherAppMenu { 142 | static State _state; 143 | 144 | static PopupMenuButton show(State state) { 145 | _state = state; 146 | return PopupMenuButton( 147 | onSelected: _showMenuSelection, 148 | itemBuilder: (BuildContext context) => >[ 149 | PopupMenuItem(value: 'Settings', child: Text('Settings')), 150 | const PopupMenuItem(value: 'About', child: Text('About')), 151 | ], 152 | ); 153 | } 154 | 155 | static _showMenuSelection(String value) async { 156 | switch (value) { 157 | case 'Settings': 158 | UnitsOfTemp.show( 159 | context: _state.context, 160 | ); 161 | break; 162 | case 'About': 163 | showAboutDialog( 164 | context: _state.context, 165 | applicationName: "Flutter Weather", 166 | children: [Text('A Flutter Weather App')]); 167 | break; 168 | default: 169 | } 170 | } 171 | } 172 | 173 | class UnitsOfTemp { 174 | static Future show({ 175 | @required BuildContext context, 176 | }) { 177 | bool unitSet = Settings.temperatureUnits == TemperatureUnits.celsius; 178 | String unitLabel = unitSet ? 'Celsius' : 'Fahrenheit'; 179 | return showDialog( 180 | context: context, 181 | builder: (BuildContext context) => 182 | SimpleDialog(title: Text(unitLabel), children: [ 183 | Container( 184 | padding: EdgeInsets.all(9.0), 185 | child: Center( 186 | child: Column(children: [ 187 | Switch( 188 | value: unitSet, 189 | onChanged: (bool set) { 190 | Settings.temperatureUnitsToggled(); 191 | WeatherCon().refresh(); 192 | Navigator.pop(context); 193 | }) 194 | ]), 195 | )), 196 | ])); 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /lib/src/home/view/location.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Felix Angelov of Skokie, Illinois 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | import 'package:flutter/material.dart' 25 | show 26 | BuildContext, 27 | Colors, 28 | FontWeight, 29 | Key, 30 | StatelessWidget, 31 | Text, 32 | TextStyle, 33 | Widget, 34 | required; 35 | 36 | import 'package:meta/meta.dart' show required; 37 | 38 | class Location extends StatelessWidget { 39 | final String location; 40 | 41 | Location({Key key, @required this.location}) 42 | : assert(location != null), 43 | super(key: key); 44 | 45 | @override 46 | Widget build(BuildContext context) { 47 | return Text( 48 | location, 49 | style: TextStyle( 50 | fontSize: 30.0, 51 | fontWeight: FontWeight.bold, 52 | color: Colors.white, 53 | ), 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/src/model.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | export 'package:sqflite/sqflite.dart'; 25 | 26 | export 'package:mvc_application/model.dart'; 27 | 28 | export 'package:weathercast/src/home/model/weather_model.dart'; 29 | 30 | export 'package:weathercast/src/home/model/repositories/weather_api_client.dart'; -------------------------------------------------------------------------------- /lib/src/view.dart: -------------------------------------------------------------------------------- 1 | /// 2 | /// Copyright (C) 2019 Andrious Solutions 3 | /// 4 | /// This program is free software; you can redistribute it and/or 5 | /// modify it under the terms of the GNU General Public License 6 | /// as published by the Free Software Foundation; either version 3 7 | /// of the License, or any later version. 8 | /// 9 | /// You may obtain a copy of the License at 10 | /// 11 | /// http://www.apache.org/licenses/LICENSE-2.0 12 | /// 13 | /// 14 | /// Unless required by applicable law or agreed to in writing, software 15 | /// distributed under the License is distributed on an "AS IS" BASIS, 16 | /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | /// See the License for the specific language governing permissions and 18 | /// limitations under the License. 19 | /// 20 | /// Created 13 Feb 2019 21 | /// 22 | /// 23 | 24 | export 'package:mvc_application/view.dart'; 25 | 26 | export 'package:weathercast/src/app/view/weatherapp.dart'; 27 | 28 | export 'package:weathercast/src/app/view/utils/gradient_container.dart'; 29 | 30 | export 'package:weathercast/src/home/view/home.dart'; 31 | 32 | export 'package:weathercast/src/home/view/location.dart'; 33 | 34 | export 'package:weathercast/src/home/view/drawer/settings_drawer.dart'; 35 | 36 | export 'package:weathercast/src/home/view/child/last_updated.dart'; 37 | 38 | export 'package:weathercast/src/home/view/child/weather_temperature.dart'; 39 | 40 | export 'package:weathercast/src/home/view/child/city_selection.dart'; 41 | 42 | export 'package:weathercast/src/home/view/child/temperature.dart'; 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: weathercast 2 | description: A simple Weather App demonstrating Flutter 3 | 4 | version: 1.0.3 5 | 6 | environment: 7 | sdk: ">=2.6.0 <3.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | mvc_application: ^1.0.0 14 | # path: ../../packages/mvc_application 15 | # git: 16 | # url: git://github.com/AndriousSolutions/mvc_application.git 17 | 18 | # https://pub.dev/packages/http 19 | http: 20 | 21 | # https://pub.dev/packages/equatable 22 | equatable: 23 | 24 | # https://pub.dev/packages/ads 25 | ads: ^1.0.0 26 | 27 | dev_dependencies: 28 | flutter_test: 29 | sdk: flutter 30 | 31 | flutter: 32 | uses-material-design: true 33 | assets: 34 | - assets/ -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter 3 | // provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to 4 | // find child widgets in the widget tree, read text, and verify that the values of widget properties 5 | // are correct. 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_test/flutter_test.dart'; 9 | 10 | //import 'package:weather_cast/main.dart'; 11 | 12 | void main() { 13 | // testWidgets('Counter increments smoke test', (WidgetTester tester) async { 14 | // // Build our app and trigger a frame. 15 | // await tester.pumpWidget(new MyApp()); 16 | // 17 | // // Verify that our counter starts at 0. 18 | // expect(find.text('0'), findsOneWidget); 19 | // expect(find.text('1'), findsNothing); 20 | // 21 | // // Tap the '+' icon and trigger a frame. 22 | // await tester.tap(find.byIcon(Icons.add)); 23 | // await tester.pump(); 24 | // 25 | // // Verify that our counter has incremented. 26 | // expect(find.text('0'), findsNothing); 27 | // expect(find.text('1'), findsOneWidget); 28 | // }); 29 | } 30 | --------------------------------------------------------------------------------