diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 780fd46..9dbab6c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,18 +41,11 @@ jobs: # - name : Run Test Coverage # run : flutter test --coverage - - name : Install lcov - run : sudo apt-get install -y lcov - - name : Upload Coverage To Codecov - uses: codecov/codecov-action@v2 - # with: - # token: ${{ secrets.CODECOV_TOKEN }} - # files: coverage/lcov.info - - name : Build Apk - run: flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi + # - name : Build Apk + # run: flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi \ No newline at end of file diff --git a/assets/icons/clear.png b/assets/icons/clear.png new file mode 100644 index 0000000..2e15781 Binary files /dev/null and b/assets/icons/clear.png differ diff --git a/assets/icons/clear@2x.png b/assets/icons/clear@2x.png new file mode 100644 index 0000000..74f3127 Binary files /dev/null and b/assets/icons/clear@2x.png differ diff --git a/assets/icons/clear@3x.png b/assets/icons/clear@3x.png new file mode 100644 index 0000000..8e5727f Binary files /dev/null and b/assets/icons/clear@3x.png differ diff --git a/assets/icons/partlysunny.png b/assets/icons/partlysunny.png new file mode 100644 index 0000000..3973670 Binary files /dev/null and b/assets/icons/partlysunny.png differ diff --git a/assets/icons/partlysunny@2x.png b/assets/icons/partlysunny@2x.png new file mode 100644 index 0000000..d08afd2 Binary files /dev/null and b/assets/icons/partlysunny@2x.png differ diff --git a/assets/icons/partlysunny@3x.png b/assets/icons/partlysunny@3x.png new file mode 100644 index 0000000..e726c13 Binary files /dev/null and b/assets/icons/partlysunny@3x.png differ diff --git a/assets/icons/rain.png b/assets/icons/rain.png new file mode 100644 index 0000000..80e2c80 Binary files /dev/null and b/assets/icons/rain.png differ diff --git a/assets/icons/rain@2x.png b/assets/icons/rain@2x.png new file mode 100644 index 0000000..051dcf5 Binary files /dev/null and b/assets/icons/rain@2x.png differ diff --git a/assets/icons/rain@3x.png b/assets/icons/rain@3x.png new file mode 100644 index 0000000..b1af53c Binary files /dev/null and b/assets/icons/rain@3x.png differ diff --git a/assets/images/sea_cloudy.png b/assets/images/sea_cloudy.png deleted file mode 100644 index 85c6654..0000000 Binary files a/assets/images/sea_cloudy.png and /dev/null differ diff --git a/assets/images/sea_rainy.png b/assets/images/sea_rainy.png deleted file mode 100644 index 70b4a8a..0000000 Binary files a/assets/images/sea_rainy.png and /dev/null differ diff --git a/assets/images/sea_sunnypng.png b/assets/images/sea_sunnypng.png deleted file mode 100644 index 9598f8b..0000000 Binary files a/assets/images/sea_sunnypng.png and /dev/null differ diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..d84c74c --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,28 @@ +PODS: + - Flutter (1.0.0) + - geolocator_apple (1.2.0): + - Flutter + - location (0.0.1): + - Flutter + +DEPENDENCIES: + - Flutter (from `Flutter`) + - geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`) + - location (from `.symlinks/plugins/location/ios`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + geolocator_apple: + :path: ".symlinks/plugins/geolocator_apple/ios" + location: + :path: ".symlinks/plugins/location/ios" + +SPEC CHECKSUMS: + Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + geolocator_apple: cc556e6844d508c95df1e87e3ea6fa4e58c50401 + location: d5cf8598915965547c3f36761ae9cc4f4e87d22e + +PODFILE CHECKSUM: 70d9d25280d0dd177a5f637cdb0f0b0b12c6a189 + +COCOAPODS: 1.12.1 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index de6f73a..80e8a02 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -8,12 +8,14 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 60484B8C83A87895EEF42A00 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 572B7EA82D2AE3843E229A93 /* Pods_RunnerTests.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + BECC8A5F86ADFAEABA219CB3 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8EBA0D54A29E78517B53D5C7 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -42,10 +44,17 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 30C43BA741402C72D9C479B1 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 572B7EA82D2AE3843E229A93 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 833826DB94761CB8FA203A33 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 8EBA0D54A29E78517B53D5C7 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 964B3173A01D28723971FC4C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -53,8 +62,9 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + B0A092FCEC58E97E6657FB45 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + B700077924DC8BB5E21CCBF3 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; + CA3979408ACCEF9343D0E76A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,12 +72,52 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + BECC8A5F86ADFAEABA219CB3 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + CA51240CA793451E187ABEA3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 60484B8C83A87895EEF42A00 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 7AE013390DD0D26A9E6998DA /* Pods */ = { + isa = PBXGroup; + children = ( + CA3979408ACCEF9343D0E76A /* Pods-Runner.debug.xcconfig */, + 833826DB94761CB8FA203A33 /* Pods-Runner.release.xcconfig */, + B0A092FCEC58E97E6657FB45 /* Pods-Runner.profile.xcconfig */, + 30C43BA741402C72D9C479B1 /* Pods-RunnerTests.debug.xcconfig */, + 964B3173A01D28723971FC4C /* Pods-RunnerTests.release.xcconfig */, + B700077924DC8BB5E21CCBF3 /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 861F3E4C45D767875B09CE8D /* Frameworks */ = { + isa = PBXGroup; + children = ( + 8EBA0D54A29E78517B53D5C7 /* Pods_Runner.framework */, + 572B7EA82D2AE3843E229A93 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -79,14 +129,6 @@ name = Flutter; sourceTree = ""; }; - 331C8082294A63A400263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; 97C146E51CF9000F007C117D = { isa = PBXGroup; children = ( @@ -94,6 +136,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, + 7AE013390DD0D26A9E6998DA /* Pods */, + 861F3E4C45D767875B09CE8D /* Frameworks */, ); sourceTree = ""; }; @@ -128,9 +172,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + C0B9A51727A8EF85FDB67771 /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, - 331C807E294A63A400263BE5 /* Frameworks */, 331C807F294A63A400263BE5 /* Resources */, + CA51240CA793451E187ABEA3 /* Frameworks */, ); buildRules = ( ); @@ -146,12 +191,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + FAE71A0DBE7306C9B6061A54 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 2BFE6FF6F87BBE72565EA3ED /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -223,6 +270,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 2BFE6FF6F87BBE72565EA3ED /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -254,6 +318,50 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + C0B9A51727A8EF85FDB67771 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + FAE71A0DBE7306C9B6061A54 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -377,7 +485,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = AE0B7B92F70575B8D7E0D07E /* Pods-RunnerTests.debug.xcconfig */; + baseConfigurationReference = 30C43BA741402C72D9C479B1 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -395,7 +503,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 89B67EB44CE7B6631473024E /* Pods-RunnerTests.release.xcconfig */; + baseConfigurationReference = 964B3173A01D28723971FC4C /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -411,7 +519,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 640959BDD8F10B91D80A66BE /* Pods-RunnerTests.profile.xcconfig */; + baseConfigurationReference = B700077924DC8BB5E21CCBF3 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/lib/domain/api/weather_service.dart b/lib/domain/api/weather_service.dart new file mode 100644 index 0000000..576eabf --- /dev/null +++ b/lib/domain/api/weather_service.dart @@ -0,0 +1,36 @@ + +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:weather_app/domain/model/forecast_responce.dart'; +import 'package:weather_app/domain/model/weather_responce.dart'; + +class WeatherApi { + final String apiKey = '395f5a02af3a3d158ca9d6649c9f2795'; + + Future fetchCurrentWeather(String city) async { + final response = await http.get( + Uri.parse( + 'https://api.openweathermap.org/data/2.5/weather?q=$city&appid=$apiKey'), + ); + + if (response.statusCode == 200) { + return WeatherResponse.fromJson(json.decode(response.body)); + } else { + throw Exception('Failed to load current weather data'); + } + } + + Future fetchWeatherForecast(String city) async { + final response = await http.get( + Uri.parse( + 'https://api.openweathermap.org/data/2.5/forecast?q=$city&appid=$apiKey'), + ); + + if (response.statusCode == 200) { + return ForecastResponse.fromJson(json.decode(response.body)); + } else { + throw Exception('Failed to load weather forecast data'); + } + } +} + diff --git a/lib/domain/model/forecast_responce.dart b/lib/domain/model/forecast_responce.dart new file mode 100644 index 0000000..0d2b149 --- /dev/null +++ b/lib/domain/model/forecast_responce.dart @@ -0,0 +1,359 @@ +// To parse this JSON data, do +// +// final forecastResponse = forecastResponseFromJson(jsonString); + +// ignore_for_file: constant_identifier_names + +import 'dart:convert'; + +ForecastResponse forecastResponseFromJson(String str) => ForecastResponse.fromJson(json.decode(str)); + +String forecastResponseToJson(ForecastResponse data) => json.encode(data.toJson()); + +class ForecastResponse { + String cod; + int message; + int cnt; + List list; + City city; + + ForecastResponse({ + required this.cod, + required this.message, + required this.cnt, + required this.list, + required this.city, + }); + + factory ForecastResponse.fromJson(Map json) => ForecastResponse( + cod: json["cod"], + message: json["message"], + cnt: json["cnt"], + list: List.from(json["list"].map((x) => ListElement.fromJson(x))), + city: City.fromJson(json["city"]), + ); + + Map toJson() => { + "cod": cod, + "message": message, + "cnt": cnt, + "list": List.from(list.map((x) => x.toJson())), + "city": city.toJson(), + }; +} + +class City { + int id; + String name; + Coord coord; + String country; + int population; + int timezone; + int sunrise; + int sunset; + + City({ + required this.id, + required this.name, + required this.coord, + required this.country, + required this.population, + required this.timezone, + required this.sunrise, + required this.sunset, + }); + + factory City.fromJson(Map json) => City( + id: json["id"], + name: json["name"], + coord: Coord.fromJson(json["coord"]), + country: json["country"], + population: json["population"], + timezone: json["timezone"], + sunrise: json["sunrise"], + sunset: json["sunset"], + ); + + Map toJson() => { + "id": id, + "name": name, + "coord": coord.toJson(), + "country": country, + "population": population, + "timezone": timezone, + "sunrise": sunrise, + "sunset": sunset, + }; +} + +class Coord { + double lat; + double lon; + + Coord({ + required this.lat, + required this.lon, + }); + + factory Coord.fromJson(Map json) => Coord( + lat: json["lat"]?.toDouble(), + lon: json["lon"]?.toDouble(), + ); + + Map toJson() => { + "lat": lat, + "lon": lon, + }; +} + +class ListElement { + int dt; + MainClass main; + List weather; + Clouds clouds; + Wind wind; + int visibility; + double pop; + Sys sys; + DateTime dtTxt; + Rain? rain; + + ListElement({ + required this.dt, + required this.main, + required this.weather, + required this.clouds, + required this.wind, + required this.visibility, + required this.pop, + required this.sys, + required this.dtTxt, + this.rain, + }); + + factory ListElement.fromJson(Map json) => ListElement( + dt: json["dt"], + main: MainClass.fromJson(json["main"]), + weather: List.from(json["weather"].map((x) => Weather.fromJson(x))), + clouds: Clouds.fromJson(json["clouds"]), + wind: Wind.fromJson(json["wind"]), + visibility: json["visibility"], + pop: json["pop"]?.toDouble(), + sys: Sys.fromJson(json["sys"]), + dtTxt: DateTime.parse(json["dt_txt"]), + rain: json["rain"] == null ? null : Rain.fromJson(json["rain"]), + ); + + Map toJson() => { + "dt": dt, + "main": main.toJson(), + "weather": List.from(weather.map((x) => x.toJson())), + "clouds": clouds.toJson(), + "wind": wind.toJson(), + "visibility": visibility, + "pop": pop, + "sys": sys.toJson(), + "dt_txt": dtTxt.toIso8601String(), + "rain": rain?.toJson(), + }; +} + +class Clouds { + int all; + + Clouds({ + required this.all, + }); + + factory Clouds.fromJson(Map json) => Clouds( + all: json["all"], + ); + + Map toJson() => { + "all": all, + }; +} + +class MainClass { + double temp; + double feelsLike; + double tempMin; + double tempMax; + int pressure; + int seaLevel; + int grndLevel; + int humidity; + double tempKf; + + MainClass({ + required this.temp, + required this.feelsLike, + required this.tempMin, + required this.tempMax, + required this.pressure, + required this.seaLevel, + required this.grndLevel, + required this.humidity, + required this.tempKf, + }); + + factory MainClass.fromJson(Map json) => MainClass( + temp: json["temp"]?.toDouble(), + feelsLike: json["feels_like"]?.toDouble(), + tempMin: json["temp_min"]?.toDouble(), + tempMax: json["temp_max"]?.toDouble(), + pressure: json["pressure"], + seaLevel: json["sea_level"], + grndLevel: json["grnd_level"], + humidity: json["humidity"], + tempKf: json["temp_kf"]?.toDouble(), + ); + + Map toJson() => { + "temp": temp, + "feels_like": feelsLike, + "temp_min": tempMin, + "temp_max": tempMax, + "pressure": pressure, + "sea_level": seaLevel, + "grnd_level": grndLevel, + "humidity": humidity, + "temp_kf": tempKf, + }; +} + +class Rain { + double the3H; + + Rain({ + required this.the3H, + }); + + factory Rain.fromJson(Map json) => Rain( + the3H: json["3h"]?.toDouble(), + ); + + Map toJson() => { + "3h": the3H, + }; +} + +class Sys { + Pod pod; + + Sys({ + required this.pod, + }); + + factory Sys.fromJson(Map json) => Sys( + pod: podValues.map[json["pod"]]!, + ); + + Map toJson() => { + "pod": podValues.reverse[pod], + }; +} + +enum Pod { + D, + N +} + +final podValues = EnumValues({ + "d": Pod.D, + "n": Pod.N +}); + +class Weather { + int id; + MainEnum main; + Description description; + String icon; + + Weather({ + required this.id, + required this.main, + required this.description, + required this.icon, + }); + + factory Weather.fromJson(Map json) => Weather( + id: json["id"], + main: mainEnumValues.map[json["main"]]!, + description: descriptionValues.map[json["description"]]!, + icon: json["icon"], + ); + + Map toJson() => { + "id": id, + "main": mainEnumValues.reverse[main], + "description": descriptionValues.reverse[description], + "icon": icon, + }; +} + +enum Description { + BROKEN_CLOUDS, + CLEAR_SKY, + FEW_CLOUDS, + LIGHT_RAIN, + OVERCAST_CLOUDS, + SCATTERED_CLOUDS +} + +final descriptionValues = EnumValues({ + "broken clouds": Description.BROKEN_CLOUDS, + "clear sky": Description.CLEAR_SKY, + "few clouds": Description.FEW_CLOUDS, + "light rain": Description.LIGHT_RAIN, + "overcast clouds": Description.OVERCAST_CLOUDS, + "scattered clouds": Description.SCATTERED_CLOUDS +}); + +enum MainEnum { + CLEAR, + CLOUDS, + RAIN +} + +final mainEnumValues = EnumValues({ + "Clear": MainEnum.CLEAR, + "Clouds": MainEnum.CLOUDS, + "Rain": MainEnum.RAIN +}); + +class Wind { + double speed; + int deg; + double gust; + + Wind({ + required this.speed, + required this.deg, + required this.gust, + }); + + factory Wind.fromJson(Map json) => Wind( + speed: json["speed"]?.toDouble(), + deg: json["deg"], + gust: json["gust"]?.toDouble(), + ); + + Map toJson() => { + "speed": speed, + "deg": deg, + "gust": gust, + }; +} + +class EnumValues { + Map map; + late Map reverseMap; + + EnumValues(this.map); + + Map get reverse { + reverseMap = map.map((k, v) => MapEntry(v, k)); + return reverseMap; + } +} diff --git a/lib/domain/model/weather_responce.dart b/lib/domain/model/weather_responce.dart new file mode 100644 index 0000000..6c24cfb --- /dev/null +++ b/lib/domain/model/weather_responce.dart @@ -0,0 +1,225 @@ +// To parse this JSON data, do +// +// final weatherResponse = weatherResponseFromJson(jsonString); + +import 'dart:convert'; + +WeatherResponse weatherResponseFromJson(String str) => WeatherResponse.fromJson(json.decode(str)); + +String weatherResponseToJson(WeatherResponse data) => json.encode(data.toJson()); + +class WeatherResponse { + Coord coord; + List weather; + String base; + Main main; + int visibility; + Wind wind; + Clouds clouds; + int dt; + Sys sys; + int timezone; + int id; + String name; + int cod; + + WeatherResponse({ + required this.coord, + required this.weather, + required this.base, + required this.main, + required this.visibility, + required this.wind, + required this.clouds, + required this.dt, + required this.sys, + required this.timezone, + required this.id, + required this.name, + required this.cod, + }); + + factory WeatherResponse.fromJson(Map json) => WeatherResponse( + coord: Coord.fromJson(json["coord"]), + weather: List.from(json["weather"].map((x) => Weather.fromJson(x))), + base: json["base"], + main: Main.fromJson(json["main"]), + visibility: json["visibility"], + wind: Wind.fromJson(json["wind"]), + clouds: Clouds.fromJson(json["clouds"]), + dt: json["dt"], + sys: Sys.fromJson(json["sys"]), + timezone: json["timezone"], + id: json["id"], + name: json["name"], + cod: json["cod"], + ); + + Map toJson() => { + "coord": coord.toJson(), + "weather": List.from(weather.map((x) => x.toJson())), + "base": base, + "main": main.toJson(), + "visibility": visibility, + "wind": wind.toJson(), + "clouds": clouds.toJson(), + "dt": dt, + "sys": sys.toJson(), + "timezone": timezone, + "id": id, + "name": name, + "cod": cod, + }; +} + +class Clouds { + int all; + + Clouds({ + required this.all, + }); + + factory Clouds.fromJson(Map json) => Clouds( + all: json["all"], + ); + + Map toJson() => { + "all": all, + }; +} + +class Coord { + double lon; + double lat; + + Coord({ + required this.lon, + required this.lat, + }); + + factory Coord.fromJson(Map json) => Coord( + lon: json["lon"]?.toDouble(), + lat: json["lat"]?.toDouble(), + ); + + Map toJson() => { + "lon": lon, + "lat": lat, + }; +} + +class Main { + double temp; + double feelsLike; + double tempMin; + double tempMax; + int pressure; + int humidity; + + Main({ + required this.temp, + required this.feelsLike, + required this.tempMin, + required this.tempMax, + required this.pressure, + required this.humidity, + }); + + factory Main.fromJson(Map json) => Main( + temp: json["temp"]?.toDouble(), + feelsLike: json["feels_like"]?.toDouble(), + tempMin: json["temp_min"]?.toDouble(), + tempMax: json["temp_max"]?.toDouble(), + pressure: json["pressure"], + humidity: json["humidity"], + ); + + Map toJson() => { + "temp": temp, + "feels_like": feelsLike, + "temp_min": tempMin, + "temp_max": tempMax, + "pressure": pressure, + "humidity": humidity, + }; +} + +class Sys { + int type; + int id; + String country; + int sunrise; + int sunset; + + Sys({ + required this.type, + required this.id, + required this.country, + required this.sunrise, + required this.sunset, + }); + + factory Sys.fromJson(Map json) => Sys( + type: json["type"], + id: json["id"], + country: json["country"], + sunrise: json["sunrise"], + sunset: json["sunset"], + ); + + Map toJson() => { + "type": type, + "id": id, + "country": country, + "sunrise": sunrise, + "sunset": sunset, + }; +} + +class Weather { + int id; + String main; + String description; + String icon; + + Weather({ + required this.id, + required this.main, + required this.description, + required this.icon, + }); + + factory Weather.fromJson(Map json) => Weather( + id: json["id"], + main: json["main"], + description: json["description"], + icon: json["icon"], + ); + + Map toJson() => { + "id": id, + "main": main, + "description": description, + "icon": icon, + }; +} + +class Wind { + double speed; + int deg; + + Wind({ + required this.speed, + required this.deg, + }); + + factory Wind.fromJson(Map json) => Wind( + speed: json["speed"]?.toDouble(), + deg: json["deg"], + ); + + Map toJson() => { + "speed": speed, + "deg": deg, + }; +} diff --git a/lib/main.dart b/lib/main.dart index 802a630..7e96282 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:weather_app/presentation/views/rainy.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:weather_app/presentation/views/weather_home_view.dart'; + +import 'presentation/cubit/weather_forecast_cubit_cubit.dart'; void main() { runApp(const MyApp()); @@ -11,14 +14,21 @@ class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), - useMaterial3: true, + return MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => WeatherForecastCubitCubit()..getWeatherForecast(), + ), + ], + child: MaterialApp( + debugShowCheckedModeBanner: false, + title: 'Flutter Demo', + theme: ThemeData( + colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), + useMaterial3: true, + ), + home: const RainyView(), ), - home: const RainyView(), ); } } - diff --git a/lib/presentation/cubit/weather_forecast_cubit_cubit.dart b/lib/presentation/cubit/weather_forecast_cubit_cubit.dart new file mode 100644 index 0000000..cafa765 --- /dev/null +++ b/lib/presentation/cubit/weather_forecast_cubit_cubit.dart @@ -0,0 +1,30 @@ +import 'package:bloc/bloc.dart'; +import 'package:meta/meta.dart'; +import 'package:weather_app/domain/model/forecast_responce.dart'; +import 'package:weather_app/domain/api/weather_service.dart'; + +part 'weather_forecast_cubit_state.dart'; + +class WeatherForecastCubitCubit extends Cubit { + WeatherForecastCubitCubit() : super(WeatherForecastCubitInitial()); + getWeatherForecast() async { + emit(WeatherForecastCubitLoading()); + try { + ForecastResponse forecastResponse = + await WeatherApi().fetchWeatherForecast('Nairobi'); + if (forecastResponse.list.isNotEmpty) { + final temperature = forecastResponse.list.first.main.temp; + final weather = forecastResponse.list.first.weather.first.main.name; + + emit(WeatherForecastCubitSuccess( + forecastRes: forecastResponse, + temperature: temperature, + weather: weather)); + } else { + emit(WeatherForecastCubitFail(error: "Weather not found")); + } + } catch (e) { + emit(WeatherForecastCubitFail(error: e.toString())); + } + } +} diff --git a/lib/presentation/cubit/weather_forecast_cubit_state.dart b/lib/presentation/cubit/weather_forecast_cubit_state.dart new file mode 100644 index 0000000..cb5a73b --- /dev/null +++ b/lib/presentation/cubit/weather_forecast_cubit_state.dart @@ -0,0 +1,23 @@ +part of 'weather_forecast_cubit_cubit.dart'; + +@immutable +sealed class WeatherForecastCubitState {} + +final class WeatherForecastCubitInitial extends WeatherForecastCubitState {} + +final class WeatherForecastCubitLoading extends WeatherForecastCubitState {} + +final class WeatherForecastCubitSuccess extends WeatherForecastCubitState { + final ForecastResponse forecastRes; + final double temperature; + final String weather; + + WeatherForecastCubitSuccess( + {required this.forecastRes, required this.temperature, required this.weather,}); +} + +final class WeatherForecastCubitFail extends WeatherForecastCubitState { + final String error; + + WeatherForecastCubitFail({required this.error}); +} diff --git a/lib/presentation/views/days_weather_view.dart b/lib/presentation/views/days_weather_view.dart new file mode 100644 index 0000000..3601e7a --- /dev/null +++ b/lib/presentation/views/days_weather_view.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; +import 'package:weather_app/presentation/views/weather_home_view.dart'; + +class DaysWeatherView extends StatelessWidget { + const DaysWeatherView({super.key}); + @override + Widget build(BuildContext context) { + return Column( + children: [ + // title + const Row( + children: [ + // min + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "10°", + style: TextStyle(color: Colors.white), + ), + Text( + "min", + style: TextStyle(color: Colors.white), + ), + ], + )), + //curent + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "19°", + style: TextStyle(color: Colors.white), + ), + Text( + "current", + style: TextStyle(color: Colors.white), + ), + ], + )), + // max + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "19°", + style: TextStyle(color: Colors.white), + ), + Text( + "max", + style: TextStyle(color: Colors.white), + ), + ], + )) + ], + ), + const Divider(color: Colors.white), + ...[ + DayWeather(day: "Monday", temperature: 23), + DayWeather(day: "Tuesday", temperature: 23), + DayWeather(day: "Wednesday", temperature: 23), + DayWeather(day: "Thursday", temperature: 23), + DayWeather(day: "Friday", temperature: 23), + DayWeather(day: "Saturday", temperature: 23), + DayWeather(day: "Sunday", temperature: 23), + ] + .map( + (e) => Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + children: [ + Expanded( + child: Text( + e.day, + style: const TextStyle(color: Colors.white), + )), + const Expanded( + child: Icon( + Icons.sunny, + color: Colors.white, + ), + ), + const SizedBox(width: 60), + Text( + "${e.temperature} °", + style: const TextStyle(color: Colors.white), + ), + ], + ), + ), + ) + .toList(), + ], + ); + } +} \ No newline at end of file diff --git a/lib/presentation/views/image_widget.dart b/lib/presentation/views/image_widget.dart new file mode 100644 index 0000000..10b8dc6 --- /dev/null +++ b/lib/presentation/views/image_widget.dart @@ -0,0 +1,52 @@ +// ignore_for_file: unrelated_type_equality_checks + +import 'package:flutter/material.dart'; +import 'package:weather_app/domain/model/forecast_responce.dart'; + +class ImageWidget extends StatelessWidget { + final ForecastResponse response; + final String weather; + final double temperature; + const ImageWidget( + {super.key, + required this.response, + required this.weather, + required this.temperature}); + + @override + Widget build(BuildContext context) { + return Container( + height: 400, + width: MediaQuery.of(context).size.width, + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage(response.list[0].weather[0].main == "Clouds" + ? 'assets/images/forest_sunny.png' + : response.list[0].weather[0].main == "Rainy" + ? 'assets/images/forest_rainy.png' + : 'assets/images/forest_cloudy.png'), + fit: BoxFit.fitHeight), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + temperature.toString(), + style: const TextStyle( + fontSize: 60, fontWeight: FontWeight.bold, color: Colors.white), + ), + Text( + weather, + style: const TextStyle( + fontSize: 32, + fontWeight: FontWeight.normal, + color: Colors.white), + ), + // Text(state.forecastResponce.city.name), + ], + ), + ); + } +} \ No newline at end of file diff --git a/lib/presentation/views/rainy.dart b/lib/presentation/views/rainy.dart deleted file mode 100644 index 0151c56..0000000 --- a/lib/presentation/views/rainy.dart +++ /dev/null @@ -1,164 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:weather_app/presentation/widgets/consts/theme.dart'; - -class RainyView extends StatefulWidget { - const RainyView({super.key}); - - @override - State createState() => _RainyView(); -} - -class _RainyView extends State { - @override - Widget build(BuildContext context) { - return const Scaffold( - backgroundColor: AppThemes.rainy, - body: Column( - children: [ImageWidget(), Expanded(child: DaysWeatherView())], - ), - ); - } -} - -class ImageWidget extends StatelessWidget { - const ImageWidget({super.key}); - - @override - Widget build(BuildContext context) { - return Container( - height: 400, - width: MediaQuery.of(context).size.width, - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/forest_rainy.png'), - fit: BoxFit.fitHeight), - ), - child: const Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - '15°', - style: TextStyle( - fontSize: 60, fontWeight: FontWeight.bold, color: Colors.white), - ), - Text( - 'RAINY', - style: TextStyle( - fontSize: 32, - fontWeight: FontWeight.normal, - color: Colors.white), - ), - ], - ), - ); - } -} - -class DaysWeatherView extends StatelessWidget { - const DaysWeatherView({super.key}); - - @override - Widget build(BuildContext context) { - return Column( - children: [ - // title - const Row( - children: [ - // min - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "10°", - style: TextStyle(color: Colors.white), - ), - Text( - "min", - style: TextStyle(color: Colors.white), - ), - ], - )), - //curent - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "19°", - style: TextStyle(color: Colors.white), - ), - Text( - "current", - style: TextStyle(color: Colors.white), - ), - ], - )), - // max - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "19°", - style: TextStyle(color: Colors.white), - ), - Text( - "max", - style: TextStyle(color: Colors.white), - ), - ], - )) - ], - ), - const Divider(color: Colors.white), - ...[ - DayWeather(day: "Monday", temperature: 23), - DayWeather(day: "Tuesday", temperature: 23), - DayWeather(day: "Wednesday", temperature: 23), - DayWeather(day: "Thursday", temperature: 23), - DayWeather(day: "Friday", temperature: 23), - DayWeather(day: "Saturday", temperature: 23), - DayWeather(day: "Sunday", temperature: 23), - ] - .map((e) => Padding( - padding: const EdgeInsets.all(8.0), - child: - Row( - children: [ - Expanded( - child: Text( - e.day, - style: const TextStyle(color: Colors.white), - )), - const Expanded( - child: Icon( - Icons.sunny, - color: Colors.white, - ), - ), - const SizedBox(width: 60), - Text( - "${e.temperature} °", - style: const TextStyle(color: Colors.white), - ), - ], - ), - )) - .toList() - ], - ); - } -} - -class DayWeather { - final String day; - final num temperature; - - DayWeather({ - required this.day, - required this.temperature, - }); -} diff --git a/lib/presentation/views/weather_home_view.dart b/lib/presentation/views/weather_home_view.dart new file mode 100644 index 0000000..2e1eacf --- /dev/null +++ b/lib/presentation/views/weather_home_view.dart @@ -0,0 +1,61 @@ +// ignore_for_file: unrelated_type_equality_checks + +import 'package:flutter/material.dart'; +import 'package:weather_app/presentation/views/days_weather_view.dart'; +import 'package:weather_app/presentation/views/image_widget.dart'; +import 'package:weather_app/presentation/widgets/consts/theme.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../cubit/weather_forecast_cubit_cubit.dart'; + +class RainyView extends StatefulWidget { + const RainyView({super.key}); + + @override + State createState() => _RainyView(); +} + +class _RainyView extends State { + String weatherCondition = required.toString(); + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: + AppThemes.getDynamicTheme(weatherCondition: weatherCondition), + body: BlocConsumer( + listener: (context, state) {}, + builder: (context, state) { + if (state is WeatherForecastCubitLoading) { + return const Center(child: CircularProgressIndicator()); + } + if (state is WeatherForecastCubitSuccess) { + return Column( + children: [ + // Text(state.forecastRes.city.name), + ImageWidget( + response: state.forecastRes, + weather: state.weather, + temperature: state.temperature, + ), + const Expanded(child: DaysWeatherView()) + ], + ); + } else { + return Container(); + } + }, + ), + ); + } +} + + +class DayWeather { + final String day; + final num temperature; + + DayWeather({ + required this.day, + required this.temperature, + }); +} diff --git a/lib/presentation/views/weather_page.dart b/lib/presentation/views/weather_page.dart deleted file mode 100644 index f9e0a60..0000000 --- a/lib/presentation/views/weather_page.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter/material.dart'; - -class WeatherPage extends StatefulWidget { - const WeatherPage({super.key}); - - @override - State createState() => _WeatherPageState(); -} - -class _WeatherPageState extends State{ - @override - Widget build(BuildContext context) { - return const Scaffold(); - } -} diff --git a/lib/presentation/widgets/consts/theme.dart b/lib/presentation/widgets/consts/theme.dart index 32383bd..c224e8a 100644 --- a/lib/presentation/widgets/consts/theme.dart +++ b/lib/presentation/widgets/consts/theme.dart @@ -1,7 +1,20 @@ import 'package:flutter/material.dart'; class AppThemes { - static const sunny = Color(0xFF47AB2F); - static const rainy = Color(0xFF57575D); - static const cloudy = Color(0xFF54717A); -} \ No newline at end of file + static Color sunny = const Color(0xFF47AB2F); + static Color rainy = const Color(0xFF57575D); + static Color cloudy = const Color(0xFF54717A); + + static Color getDynamicTheme({required String weatherCondition}) { + switch (weatherCondition) { + case "Cloudy": + return cloudy; + case "Rainy": + return rainy; + case "Sunny": + return sunny; + default: + return cloudy; + } + } +} diff --git a/lib/services/weather_service.dart b/lib/services/weather_service.dart deleted file mode 100644 index e8077c1..0000000 --- a/lib/services/weather_service.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:location/location.dart'; - -class WeatherService { - static Future getWeather() async { - const String key = ''; - LocationData location = await Location().getLocation(); - } -} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 6b401e5..b1d4adf 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,8 +5,10 @@ import FlutterMacOS import Foundation +import geolocator_apple import location func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 8934e61..cd32b56 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.0" + bloc: + dependency: "direct main" + description: + name: bloc + sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49" + url: "https://pub.dev" + source: hosted + version: "8.1.2" boolean_selector: dependency: transitive description: @@ -41,6 +49,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.17.2" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" cupertino_icons: dependency: "direct main" description: @@ -62,6 +78,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae + url: "https://pub.dev" + source: hosted + version: "8.1.3" flutter_lints: dependency: "direct dev" description: @@ -80,6 +104,62 @@ packages: description: flutter source: sdk version: "0.0.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: e946395fc608842bb2f6c914807e9183f86f3cb787f6b8f832753e5251036f02 + url: "https://pub.dev" + source: hosted + version: "10.1.0" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: "93906636752ea4d4e778afa981fdfe7409f545b3147046300df194330044d349" + url: "https://pub.dev" + source: hosted + version: "4.3.1" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: ab90ae811c42ec2f6021e01eca71df00dee6ff1e69d2c2dafd4daeb0b793f73d + url: "https://pub.dev" + source: hosted + version: "2.3.2" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: b7aca62aa05d7e610c396a53a1936ff87fce2f735d76e93fde9269c341c46a25 + url: "https://pub.dev" + source: hosted + version: "4.1.1" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: "59083f7e0871b78299918d92bf930a14377f711d2d1156c558cd5ebae6c20d58" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: "8725beaa00db2b52f53d9811584cb4488240b250b04a09763e80945017f65c9c" + url: "https://pub.dev" + source: hosted + version: "0.2.1" + http: + dependency: "direct main" + description: + name: http + sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + url: "https://pub.dev" + source: hosted + version: "1.1.0" http_parser: dependency: transitive description: @@ -145,13 +225,21 @@ packages: source: hosted version: "0.5.0" meta: - dependency: transitive + dependency: "direct main" description: name: meta sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted version: "1.9.1" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" path: dependency: transitive description: @@ -168,6 +256,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.6" + provider: + dependency: transitive + description: + name: provider + sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + url: "https://pub.dev" + source: hosted + version: "6.0.5" sky_engine: dependency: transitive description: flutter @@ -229,6 +325,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + uuid: + dependency: transitive + description: + name: uuid + sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + url: "https://pub.dev" + source: hosted + version: "3.0.7" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 0f42396..0299d55 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,11 +10,13 @@ dependencies: flutter: sdk: flutter - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 location: ^5.0.3 + flutter_bloc: ^8.1.3 + http: ^1.1.0 + bloc: ^8.1.2 + meta: ^1.9.1 + geolocator: ^10.1.0 dev_dependencies: flutter_test: @@ -26,34 +28,18 @@ flutter: uses-material-design: true - # To add assets to your application, add an assets section, like this: assets: - assets/images/forest_cloudy.png - assets/images/forest_rainy.png - assets/images/forest_sunny.png + - assets/icons/clear.png + - assets/icons/clear@2x.png + - assets/icons/clear@3x.png + - assets/icons/partlysunny.png + - assets/icons/partlysunny@2x.png + - assets/icons/partlysunny@3x.png + - assets/icons/rain.png + - assets/icons/rain@2x.png + - assets/icons/rain@3x.png + - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8b6d468..1ece8f2 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + GeolocatorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("GeolocatorWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b93c4c3..7f101a7 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + geolocator_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST