diff --git a/.gitignore b/.gitignore
index 4314849..f76f15e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@ migrate_working_dir/
*.ipr
*.iws
.idea/
+.cxx/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
@@ -41,4 +42,4 @@ app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
-/android/app/release
\ No newline at end of file
+/android/app/release
diff --git a/.metadata b/.metadata
index 262ceed..2d1be89 100644
--- a/.metadata
+++ b/.metadata
@@ -1,11 +1,11 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
-# This file should be version controlled.
+# This file should be version controlled and should not be manually edited.
version:
- revision: 135454af32477f815a7525073027a3ff9eff1bfd
- channel: stable
+ revision: "2663184aa79047d0a33a14a3b607954f8fdd8730"
+ channel: "stable"
project_type: app
@@ -13,26 +13,26 @@ project_type: app
migration:
platforms:
- platform: root
- create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
- base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
+ create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
+ base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
- platform: android
- create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
- base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
+ create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
+ base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
- platform: ios
- create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
- base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
+ create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
+ base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
- platform: linux
- create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
- base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
+ create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
+ base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
- platform: macos
- create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
- base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
+ create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
+ base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
- platform: web
- create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
- base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
+ create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
+ base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
- platform: windows
- create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
- base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
+ create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
+ base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
# User provided section
diff --git a/README.md b/README.md
index faf32d4..14e161c 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,15 @@
-

-
🌦️ Rain
+

+
🌦️ Rain
-
-
-
-
-
-
+
+
+
+
+
+
Tired of unpredictable weather? Rain's got you covered! Get ready for any forecast. 🌦️
@@ -40,7 +40,7 @@ We fetch weather data from [Open-Meteo](https://open-meteo.com/en/docs) and use
### 📸 Screenshots
-
+
### 💰 Support Us
@@ -52,7 +52,6 @@ If you find Rain valuable and worthy for future innovation, consider supporting
### 📥 Get Rain Now
[](https://play.google.com/store/apps/details?id=com.yoshi.rain)
-[](https://apps.rustore.ru/app/com.yoshi.rain)
Or get the latest APK from the [Releases Section](https://github.com/DarkMooNight/Rain/releases/latest). You can also find the app on IzzyOnDroid via a F-Droid client [here](https://apt.izzysoft.de/fdroid/index/apk/com.yoshi.rain).
@@ -63,5 +62,5 @@ This project is licensed under the [MIT License](./LICENSE).
### 👨💻 Our Contributors
-
+
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 9847a76..6a479c4 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -4,24 +4,6 @@ plugins {
id "dev.flutter.flutter-gradle-plugin"
}
-def localProperties = new Properties()
-def localPropertiesFile = rootProject.file('local.properties')
-if (localPropertiesFile.exists()) {
- localPropertiesFile.withReader('UTF-8') { reader ->
- localProperties.load(reader)
- }
-}
-
-def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
-if (flutterVersionCode == null) {
- flutterVersionCode = '1'
-}
-
-def flutterVersionName = localProperties.getProperty('flutter.versionName')
-if (flutterVersionName == null) {
- flutterVersionName = '1.0'
-}
-
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
@@ -29,64 +11,73 @@ if (keystorePropertiesFile.exists()) {
}
android {
- namespace 'com.yoshi.rain'
- compileSdkVersion 34
- ndkVersion flutter.ndkVersion
+ namespace = 'com.yoshi.rain'
+ compileSdk = 35
+ ndkVersion = '29.0.13113456'
compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ coreLibraryDesugaringEnabled = true
}
kotlinOptions {
- jvmTarget = '1.8'
+ jvmTarget = JavaVersion.VERSION_17
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
+ dependenciesInfo {
+ // Disables dependency metadata when building APKs.
+ includeInApk = false
+ // Disables dependency metadata when building Android App Bundles.
+ includeInBundle = false
+ }
+
defaultConfig {
- applicationId "com.yoshi.rain"
- minSdkVersion 23
- targetSdkVersion flutter.targetSdkVersion
- versionCode flutterVersionCode.toInteger()
- versionName flutterVersionName
+ applicationId = 'com.yoshi.rain'
+ minSdk = 23
+ targetSdk = flutter.targetSdkVersion
+ versionCode = flutter.versionCode
+ versionName = flutter.versionName
}
signingConfigs {
- release {
- keyAlias keystoreProperties['keyAlias']
- keyPassword keystoreProperties['keyPassword']
- storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
- storePassword keystoreProperties['storePassword']
+ release {
+ keyAlias = keystoreProperties['keyAlias']
+ keyPassword = keystoreProperties['keyPassword']
+ storeFile = keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
+ storePassword = keystoreProperties['storePassword']
}
}
buildTypes {
release {
- signingConfig signingConfigs.release
+ signingConfig = signingConfigs.release
}
debug {
- signingConfig signingConfigs.debug
- minifyEnabled true
+ signingConfig = signingConfigs.debug
+ minifyEnabled = true
}
}
buildFeatures {
- viewBinding true
+ viewBinding = true
}
}
flutter {
- source '../..'
+ source = "../.."
}
dependencies {
implementation("androidx.core:core-remoteviews:1.1.0")
implementation("com.google.android.material:material:1.12.0")
- implementation("androidx.work:work-runtime-ktx:2.9.0")
+ implementation('androidx.work:work-runtime-ktx:2.10.0')
+ coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
}
// Remove this for FLOSS version
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 1934665..d02b0cf 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -18,6 +18,7 @@
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
+ android:enableOnBackInvokedCallback="true"
android:windowSoftInputMode="adjustResize">
-
\ No newline at end of file
+
diff --git a/android/gradle.properties b/android/gradle.properties
index 598d13f..a792b07 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,3 +1,4 @@
org.gradle.jvmargs=-Xmx4G
android.useAndroidX=true
android.enableJetifier=true
+android.enableR8.fullMode = false
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 3c472b9..c6a2952 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
diff --git a/android/settings.gradle b/android/settings.gradle
index 9f0fe47..18a751a 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -5,10 +5,9 @@ pluginManagement {
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
- }
- settings.ext.flutterSdkPath = flutterSdkPath()
+ }()
- includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
+ includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories {
google()
@@ -19,8 +18,8 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
- id "com.android.application" version "7.4.2" apply false
- id "org.jetbrains.kotlin.android" version "2.0.0" apply false
+ id "com.android.application" version "8.9.0" apply false
+ id "org.jetbrains.kotlin.android" version "2.1.10" apply false
}
include ":app"
diff --git a/ios/RunnerTests/RunnerTests.swift b/ios/RunnerTests/RunnerTests.swift
new file mode 100644
index 0000000..86a7c3b
--- /dev/null
+++ b/ios/RunnerTests/RunnerTests.swift
@@ -0,0 +1,12 @@
+import Flutter
+import UIKit
+import XCTest
+
+class RunnerTests: XCTestCase {
+
+ func testExample() {
+ // If you add code to the Runner application, consider adding tests here.
+ // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
+ }
+
+}
diff --git a/lib/app/api/api.dart b/lib/app/api/api.dart
old mode 100644
new mode 100755
index 2a30802..f2f6715
--- a/lib/app/api/api.dart
+++ b/lib/app/api/api.dart
@@ -3,12 +3,12 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:rain/app/api/city_api.dart';
import 'package:rain/app/api/weather_api.dart';
-import 'package:rain/app/data/weather.dart';
+import 'package:rain/app/data/db.dart';
import 'package:rain/main.dart';
class WeatherAPI {
- final Dio dio = Dio()
- ..options.baseUrl = 'https://api.open-meteo.com/v1/forecast?';
+ final Dio dio =
+ Dio()..options.baseUrl = 'https://api.open-meteo.com/v1/forecast?';
final Dio dioLocation = Dio();
static const String _weatherParams =
@@ -41,14 +41,25 @@ class WeatherAPI {
}
}
- Future getWeatherCard(double lat, double lon, String city,
- String district, String timezone) async {
+ Future getWeatherCard(
+ double lat,
+ double lon,
+ String city,
+ String district,
+ String timezone,
+ ) async {
final String urlWeather = _buildWeatherUrl(lat, lon);
try {
Response response = await dio.get(urlWeather);
WeatherDataApi weatherData = WeatherDataApi.fromJson(response.data);
return _mapWeatherDataToCard(
- weatherData, lat, lon, city, district, timezone);
+ weatherData,
+ lat,
+ lon,
+ city,
+ district,
+ timezone,
+ );
} on DioException catch (e) {
if (kDebugMode) {
print(e);
@@ -124,8 +135,14 @@ class WeatherAPI {
);
}
- WeatherCard _mapWeatherDataToCard(WeatherDataApi weatherData, double lat,
- double lon, String city, String district, String timezone) {
+ WeatherCard _mapWeatherDataToCard(
+ WeatherDataApi weatherData,
+ double lat,
+ double lon,
+ String city,
+ String district,
+ String timezone,
+ ) {
return WeatherCard(
time: weatherData.hourly.time,
temperature2M: weatherData.hourly.temperature2M,
diff --git a/lib/app/api/city_api.dart b/lib/app/api/city_api.dart
old mode 100644
new mode 100755
index 55a3b6a..9712e75
--- a/lib/app/api/city_api.dart
+++ b/lib/app/api/city_api.dart
@@ -1,15 +1,14 @@
class CityApi {
- CityApi({
- required this.results,
- });
+ CityApi({required this.results});
List results;
factory CityApi.fromJson(Map json) => CityApi(
- results: json['results'] == null
+ results:
+ json['results'] == null
? List.empty()
: List.from(json['results'].map((x) => Result.fromJson(x))),
- );
+ );
}
class Result {
@@ -26,9 +25,9 @@ class Result {
double longitude;
factory Result.fromJson(Map json) => Result(
- admin1: json['admin1'] ?? '',
- name: json['name'],
- latitude: json['latitude'],
- longitude: json['longitude'],
- );
+ admin1: json['admin1'] ?? '',
+ name: json['name'],
+ latitude: json['latitude'],
+ longitude: json['longitude'],
+ );
}
diff --git a/lib/app/api/weather_api.dart b/lib/app/api/weather_api.dart
old mode 100644
new mode 100755
diff --git a/lib/app/api/weather_api.freezed.dart b/lib/app/api/weather_api.freezed.dart
old mode 100644
new mode 100755
diff --git a/lib/app/api/weather_api.g.dart b/lib/app/api/weather_api.g.dart
old mode 100644
new mode 100755
diff --git a/lib/app/controller/controller.dart b/lib/app/controller/controller.dart
old mode 100644
new mode 100755
index 1e01069..32d3ceb
--- a/lib/app/controller/controller.dart
+++ b/lib/app/controller/controller.dart
@@ -1,7 +1,6 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
-import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_timezone/flutter_timezone.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
@@ -11,11 +10,11 @@ import 'package:isar/isar.dart';
import 'package:lat_lng_to_timezone/lat_lng_to_timezone.dart' as tzmap;
import 'package:path_provider/path_provider.dart';
import 'package:rain/app/api/api.dart';
-import 'package:rain/app/data/weather.dart';
-import 'package:rain/app/services/notification.dart';
-import 'package:rain/app/services/utils.dart';
-import 'package:rain/app/widgets/status/status_data.dart';
-import 'package:rain/app/widgets/status/status_weather.dart';
+import 'package:rain/app/data/db.dart';
+import 'package:rain/app/utils/notification.dart';
+import 'package:rain/app/utils/show_snack_bar.dart';
+import 'package:rain/app/ui/widgets/weather/status/status_data.dart';
+import 'package:rain/app/ui/widgets/weather/status/status_weather.dart';
import 'package:rain/main.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
import 'package:timezone/data/latest_all.dart' as tz;
@@ -53,15 +52,14 @@ class WeatherController extends GetxController {
@override
void onInit() {
- weatherCards
- .assignAll(isar.weatherCards.where().sortByIndex().findAllSync());
+ weatherCards.assignAll(
+ isar.weatherCards.where().sortByIndex().findAllSync(),
+ );
super.onInit();
}
- Future determinePosition() async {
- LocationPermission permission;
-
- permission = await Geolocator.checkPermission();
+ Future _determinePosition() async {
+ LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
@@ -71,7 +69,8 @@ class WeatherController extends GetxController {
if (permission == LocationPermission.deniedForever) {
return Future.error(
- 'Location permissions are permanently denied, we cannot request permissions.');
+ 'Location permissions are permanently denied, we cannot request permissions.',
+ );
}
return await Geolocator.getCurrentPosition();
}
@@ -80,25 +79,26 @@ class WeatherController extends GetxController {
if (settings.location) {
await getCurrentLocation();
} else {
- if ((isar.locationCaches.where().findAllSync()).isNotEmpty) {
- LocationCache locationCity =
- (isar.locationCaches.where().findFirstSync())!;
- await getLocation(locationCity.lat!, locationCity.lon!,
- locationCity.district!, locationCity.city!);
+ final locationCity = isar.locationCaches.where().findFirstSync();
+ if (locationCity != null) {
+ await getLocation(
+ locationCity.lat!,
+ locationCity.lon!,
+ locationCity.district!,
+ locationCity.city!,
+ );
}
}
}
Future getCurrentLocation() async {
- bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
-
if (!(await isOnline.value)) {
showSnackBar(content: 'no_inter'.tr);
await readCache();
return;
}
- if (!serviceEnabled) {
+ if (!await Geolocator.isLocationServiceEnabled()) {
showSnackBar(
content: 'no_location'.tr,
onPressed: () => Geolocator.openLocationSettings(),
@@ -107,70 +107,73 @@ class WeatherController extends GetxController {
return;
}
- if ((isar.mainWeatherCaches.where().findAllSync()).isNotEmpty) {
+ if (isar.mainWeatherCaches.where().findAllSync().isNotEmpty) {
await readCache();
return;
}
- Position position = await determinePosition();
- List placemarks =
- await placemarkFromCoordinates(position.latitude, position.longitude);
- Placemark place = placemarks[0];
+ final position = await _determinePosition();
+ final placemarks = await placemarkFromCoordinates(
+ position.latitude,
+ position.longitude,
+ );
+ final place = placemarks[0];
_latitude.value = position.latitude;
_longitude.value = position.longitude;
- _district.value = '${place.administrativeArea}';
- _city.value = '${place.locality}';
+ _district.value = place.administrativeArea ?? '';
+ _city.value = place.locality ?? '';
- _mainWeather.value =
- await WeatherAPI().getWeatherData(_latitude.value, _longitude.value);
+ _mainWeather.value = await WeatherAPI().getWeatherData(
+ _latitude.value,
+ _longitude.value,
+ );
notificationCheck();
-
await writeCache();
await readCache();
}
- Future