Compare commits

...

41 commits
v1.3.2 ... main

Author SHA1 Message Date
Yoshi
9ba80c3609 Refactor code 2025-05-28 17:42:15 +03:00
Yoshi
33be8dcdc6 Update dependencies 2025-04-25 18:57:26 +03:00
Yoshi
089f3ae0b7 issue #201 2025-03-16 21:24:22 +03:00
Yoshi
fb150421a6 Fix bugs 2025-03-15 23:40:48 +03:00
Yoshi
d169f6237f Update README.md 2025-03-13 22:24:56 +03:00
Yoshi
e14dc03524 Update README.md 2025-03-12 22:21:22 +03:00
Yoshi
97aa5024b4 Update README.md 2025-03-11 21:01:16 +03:00
Yoshi
f880c5d274 Update dependencies and delete support 2025-03-02 15:58:04 +03:00
Yoshi
0973fb5230 Update dependencies 2025-02-08 13:09:25 +03:00
Yoshi
416f77765c Update dependencies 2025-01-08 14:26:35 +03:00
Yoshi
a59c6b7338 Android 15 2025-01-08 12:22:43 +03:00
Yoshi
0552a84e6f Fix dependencies 2024-12-15 13:41:23 +03:00
Yoshi
3a23dd6288 Update java 2024-11-10 19:55:18 +03:00
Yoshi
b7d0e8012a Update dependencies 2024-11-03 20:51:49 +03:00
Yoshi
fa0921d1b0 Fix settings gradle 2024-10-12 22:27:27 +03:00
Yoshi
7a00917ca2 Update build.gradle 2024-10-05 22:23:21 +03:00
Yoshi
ddf7115579 Update gradle 2024-10-05 17:49:08 +03:00
Yoshi
014a52c215 Rename folders 2024-09-06 22:07:50 +03:00
Yoshi
07142e25a7 Hide map 2024-08-30 22:31:42 +03:00
Yoshi
55e813749a Fix widget 2024-08-29 22:00:08 +03:00
Yoshi
1d7cbbd1bf Fix map and add new button 2024-08-28 21:52:42 +03:00
Yoshi
1ea344c69a Settings widget 2024-08-26 21:27:15 +03:00
Yoshi
5cd6e2e6c8 Delete 2gis 2024-08-23 07:15:37 +03:00
Yoshi
c0c15bb811 Fix ExpandableFab 2024-08-22 23:34:56 +03:00
Yoshi
d5a34ea11b Fix map 2024-08-22 22:49:37 +03:00
Yoshi
f174c0f336 Add buttons to the map 2024-08-21 23:20:50 +03:00
Yoshi
d0791279a2 Fix animation markers 2024-08-21 21:55:29 +03:00
Yoshi
88a7bafffb Add clear cache 2024-08-20 22:19:02 +03:00
Yoshi
27e276a092 Add search the map 2024-08-18 18:35:30 +03:00
Yoshi
383fb24881 Fix markers 2024-08-18 14:08:54 +03:00
Yoshi
8ed047a1aa Add markers 2024-08-15 22:39:51 +03:00
Yoshi
6c7da7b28d Add map 2024-08-12 21:03:35 +03:00
Yoshi
b2e843c5d9 Update dependencies 2024-08-09 22:19:37 +03:00
Yoshi
91e1757a20 Replacing SizedBox with Gap 2024-08-04 11:48:25 +03:00
Yoshi
8bce420296 Fix UI 2024-08-03 18:55:26 +03:00
Yoshi
2cc70f9221 Add mmHg and m/s 2024-08-02 22:52:33 +03:00
Yoshi
dd57938153 Fix anim new add form && Add feels to the top tile 2024-07-29 22:37:08 +03:00
Yoshi
fc246ac5a2 Add new form create_card_weather 2024-07-24 23:07:35 +03:00
Yoshi
33ceb30885 Fix api code 2024-07-13 07:00:58 +03:00
Yoshi
46e1546e5b Two weather display options 2024-07-10 21:59:36 +03:00
Yoshi
dd3339bc3b issue #185 2024-07-09 23:03:40 +03:00
122 changed files with 11614 additions and 9023 deletions

1
.gitignore vendored
View file

@ -15,6 +15,7 @@ migrate_working_dir/
*.ipr *.ipr
*.iws *.iws
.idea/ .idea/
.cxx/
# The .vscode folder contains launch configuration and tasks you configure in # 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 # VS Code which you may wish to be included in version control, so this line

View file

@ -1,11 +1,11 @@
# This file tracks properties of this Flutter project. # This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc. # 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: version:
revision: 135454af32477f815a7525073027a3ff9eff1bfd revision: "2663184aa79047d0a33a14a3b607954f8fdd8730"
channel: stable channel: "stable"
project_type: app project_type: app
@ -13,26 +13,26 @@ project_type: app
migration: migration:
platforms: platforms:
- platform: root - platform: root
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
- platform: android - platform: android
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
- platform: ios - platform: ios
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
- platform: linux - platform: linux
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
- platform: macos - platform: macos
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
- platform: web - platform: web
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
- platform: windows - platform: windows
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
# User provided section # User provided section

View file

@ -1,15 +1,15 @@
<div align='center'> <div align='center'>
<img src='/assets/icons/icon.png' width='150'/> <img src='/readme/icon.png' width='150'/>
<h2>🌦️ Rain</h2> <h2>🌦️ Rain</h2>
</div> </div>
<p align='center'> <p align='center'>
<p align='center'> <p align='center'>
<a href='https://github.com/darkmoonight/Rain/stargazers'><img alt='Stars' src='https://img.shields.io/github/stars/darkmoonight/Rain?color=abc0d3'/></a> <a href='https://github.com/darkmoonight/Rain/stargazers'><img alt='Stars' src='https://img.shields.io/github/stars/darkmoonight/Rain?color=abc0d3'/></a>
<a href='https://github.com/darkmoonight/Rain/forks'><img alt='Forks' src='https://img.shields.io/github/forks/darkmoonight/Rain?color=abc0d3'/></a> <a href='https://github.com/darkmoonight/Rain/forks'><img alt='Forks' src='https://img.shields.io/github/forks/darkmoonight/Rain?color=abc0d3'/></a>
<a href='https://github.com/darkmoonight/Rain/releases'><img alt='GitHub release' src='https://img.shields.io/github/v/release/darkmoonight/Rain?color=abc0d3'/></a> <a href='https://github.com/darkmoonight/Rain/releases'><img alt='GitHub release' src='https://img.shields.io/github/v/release/darkmoonight/Rain?color=abc0d3'/></a>
<a href='https://github.com/darkmoonight/Rain/blob/main/LICENSE'><img alt='License' src='https://img.shields.io/github/license/darkmoonight/Rain?color=abc0d3'/></a> <a href='https://github.com/darkmoonight/Rain/blob/main/LICENSE'><img alt='License' src='https://img.shields.io/github/license/darkmoonight/Rain?color=abc0d3'/></a>
</p> </p>
</p> </p>
<p align='center'> Tired of unpredictable weather? Rain's got you covered! Get ready for any forecast. 🌦️ </p> <p align='center'> Tired of unpredictable weather? Rain's got you covered! Get ready for any forecast. 🌦️ </p>
@ -40,7 +40,7 @@ We fetch weather data from [Open-Meteo](https://open-meteo.com/en/docs) and use
### 📸 Screenshots ### 📸 Screenshots
<img src='/readme/1.png' width='200'/> <img src='/readme/2.png' width='200'/> <img src='/readme/3.png' width='200'/> <img src='/readme/4.png' width='200'/> <img src='/readme/1.png' width='200'/> <img src='/readme/2.png' width='200'/> <img src='/readme/3.png' width='200'/> <img src='/readme/4.png' width='200'/> <img src='/readme/5.png' width='200'/> <img src='/readme/6.png' width='200'/> <img src='/readme/7.png' width='200'/> <img src='/readme/8.png' width='200'/>
### 💰 Support Us ### 💰 Support Us
@ -52,7 +52,6 @@ If you find Rain valuable and worthy for future innovation, consider supporting
### 📥 Get Rain Now ### 📥 Get Rain Now
[![Play Store](https://img.shields.io/badge/Google_Play-414141?style=for-the-badge&logo=google-play&logoColor=white)](https://play.google.com/store/apps/details?id=com.yoshi.rain) [![Play Store](https://img.shields.io/badge/Google_Play-414141?style=for-the-badge&logo=google-play&logoColor=white)](https://play.google.com/store/apps/details?id=com.yoshi.rain)
[![RuStore](https://img.shields.io/badge/RuStore-blue?style=for-the-badge&logo=vk&logoColor=white)](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). 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 ### 👨‍💻 Our Contributors
<a href='https://github.com/darkmoonight/Rain/graphs/contributors'> <a href='https://github.com/darkmoonight/Rain/graphs/contributors'>
<img src='https://contrib.rocks/image?repo=darkmoonight/Rain' /> <img src='https://contrib.rocks/image?repo=darkmoonight/Rain'/>
</a> </a>

View file

@ -4,24 +4,6 @@ plugins {
id "dev.flutter.flutter-gradle-plugin" 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 keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties') def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) { if (keystorePropertiesFile.exists()) {
@ -29,64 +11,73 @@ if (keystorePropertiesFile.exists()) {
} }
android { android {
namespace 'com.yoshi.rain' namespace = 'com.yoshi.rain'
compileSdkVersion 34 compileSdk = 35
ndkVersion flutter.ndkVersion ndkVersion = '29.0.13113456'
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_17
coreLibraryDesugaringEnabled = true
} }
kotlinOptions { kotlinOptions {
jvmTarget = '1.8' jvmTarget = JavaVersion.VERSION_17
} }
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' 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 { defaultConfig {
applicationId "com.yoshi.rain" applicationId = 'com.yoshi.rain'
minSdkVersion 23 minSdk = 23
targetSdkVersion flutter.targetSdkVersion targetSdk = flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode = flutter.versionCode
versionName flutterVersionName versionName = flutter.versionName
} }
signingConfigs { signingConfigs {
release { release {
keyAlias keystoreProperties['keyAlias'] keyAlias = keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword'] keyPassword = keystoreProperties['keyPassword']
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null storeFile = keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword keystoreProperties['storePassword'] storePassword = keystoreProperties['storePassword']
} }
} }
buildTypes { buildTypes {
release { release {
signingConfig signingConfigs.release signingConfig = signingConfigs.release
} }
debug { debug {
signingConfig signingConfigs.debug signingConfig = signingConfigs.debug
minifyEnabled true minifyEnabled = true
} }
} }
buildFeatures { buildFeatures {
viewBinding true viewBinding = true
} }
} }
flutter { flutter {
source '../..' source = "../.."
} }
dependencies { dependencies {
implementation("androidx.core:core-remoteviews:1.1.0") implementation("androidx.core:core-remoteviews:1.1.0")
implementation("com.google.android.material:material:1.12.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 // Remove this for FLOSS version

View file

@ -11,16 +11,6 @@
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:extractNativeLibs="true"> android:extractNativeLibs="true">
<receiver
android:name=".OreoWidget"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/oreo_widget_info" />
</receiver>
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
@ -28,6 +18,7 @@
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:enableOnBackInvokedCallback="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<meta-data <meta-data
android:name="io.flutter.embedding.android.NormalTheme" android:name="io.flutter.embedding.android.NormalTheme"
@ -36,7 +27,32 @@
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="es.antonborri.home_widget.action.LAUNCH" />
</intent-filter>
</activity> </activity>
<receiver
android:name=".OreoWidget"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/oreo_widget_info" />
</receiver>
<receiver android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver"
android:exported="true">
<intent-filter>
<action android:name="es.antonborri.home_widget.action.BACKGROUND" />
</intent-filter>
</receiver>
<service android:name="es.antonborri.home_widget.HomeWidgetBackgroundService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true" />
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />

View file

@ -1,3 +1,4 @@
org.gradle.jvmargs=-Xmx4G org.gradle.jvmargs=-Xmx4G
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
android.enableR8.fullMode = false

View file

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists 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

View file

@ -5,10 +5,9 @@ pluginManagement {
def flutterSdkPath = properties.getProperty("flutter.sdk") def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties" assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath return flutterSdkPath
} }()
settings.ext.flutterSdkPath = flutterSdkPath()
includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
repositories { repositories {
google() google()
@ -19,8 +18,8 @@ pluginManagement {
plugins { plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.4.2" apply false id "com.android.application" version "8.9.0" apply false
id "org.jetbrains.kotlin.android" version "1.9.22" apply false id "org.jetbrains.kotlin.android" version "2.1.10" apply false
} }
include ":app" include ":app"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View file

@ -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.
}
}

243
lib/app/api/api.dart Normal file → Executable file
View file

@ -1,69 +1,38 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:rain/app/api/city.dart'; import 'package:rain/app/api/city_api.dart';
import 'package:rain/app/api/weather.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'; import 'package:rain/main.dart';
class WeatherAPI { class WeatherAPI {
final Dio dio = Dio() final Dio dio =
..options.baseUrl = 'https://api.open-meteo.com/v1/forecast?'; Dio()..options.baseUrl = 'https://api.open-meteo.com/v1/forecast?';
final Dio dioLocation = Dio(); final Dio dioLocation = Dio();
Future<MainWeatherCache> getWeatherData(double? lat, double? lon) async { static const String _weatherParams =
String url = 'hourly=temperature_2m,relativehumidity_2m,apparent_temperature,precipitation,rain,weathercode,surface_pressure,visibility,evapotranspiration,windspeed_10m,winddirection_10m,windgusts_10m,cloudcover,uv_index,dewpoint_2m,precipitation_probability,shortwave_radiation'
'latitude=$lat&longitude=$lon&hourly=temperature_2m,relativehumidity_2m,apparent_temperature,precipitation,rain,weathercode,surface_pressure,visibility,evapotranspiration,windspeed_10m,winddirection_10m,windgusts_10m,cloudcover,uv_index,dewpoint_2m,precipitation_probability,shortwave_radiation&daily=weathercode,temperature_2m_max,temperature_2m_min,apparent_temperature_max,apparent_temperature_min,sunrise,sunset,precipitation_sum,precipitation_probability_max,windspeed_10m_max,windgusts_10m_max,uv_index_max,rain_sum,winddirection_10m_dominant&forecast_days=12&timezone=auto'; '&daily=weathercode,temperature_2m_max,temperature_2m_min,apparent_temperature_max,apparent_temperature_min,sunrise,sunset,precipitation_sum,precipitation_probability_max,windspeed_10m_max,windgusts_10m_max,uv_index_max,rain_sum,winddirection_10m_dominant'
String urlWeather; '&forecast_days=12&timezone=auto';
settings.measurements == 'imperial' && settings.degrees == 'fahrenheit'
? urlWeather = String _buildWeatherUrl(double lat, double lon) {
'$url&temperature_unit=fahrenheit&windspeed_unit=mph&precipitation_unit=inch' String url = 'latitude=$lat&longitude=$lon&$_weatherParams';
: settings.measurements == 'imperial' if (settings.measurements == 'imperial') {
? urlWeather = '$url&windspeed_unit=mph&precipitation_unit=inch' url += '&windspeed_unit=mph&precipitation_unit=inch';
: settings.degrees == 'fahrenheit' }
? urlWeather = '$url&temperature_unit=fahrenheit' if (settings.degrees == 'fahrenheit') {
: urlWeather = url; url += '&temperature_unit=fahrenheit';
}
return url;
}
Future<MainWeatherCache> getWeatherData(double lat, double lon) async {
final String urlWeather = _buildWeatherUrl(lat, lon);
try { try {
Response response = await dio.get(urlWeather); Response response = await dio.get(urlWeather);
WeatherDataApi weatherData = WeatherDataApi.fromJson(response.data); WeatherDataApi weatherData = WeatherDataApi.fromJson(response.data);
return MainWeatherCache( return _mapWeatherDataToCache(weatherData);
time: weatherData.hourly.time,
temperature2M: weatherData.hourly.temperature2M,
relativehumidity2M: weatherData.hourly.relativeHumidity2M,
apparentTemperature: weatherData.hourly.apparentTemperature,
precipitation: weatherData.hourly.precipitation,
rain: weatherData.hourly.rain,
weathercode: weatherData.hourly.weatherCode,
surfacePressure: weatherData.hourly.surfacePressure,
visibility: weatherData.hourly.visibility,
evapotranspiration: weatherData.hourly.evapotranspiration,
windspeed10M: weatherData.hourly.windSpeed10M,
winddirection10M: weatherData.hourly.windDirection10M,
windgusts10M: weatherData.hourly.windGusts10M,
cloudcover: weatherData.hourly.cloudCover,
uvIndex: weatherData.hourly.uvIndex,
dewpoint2M: weatherData.hourly.dewpoint2M,
precipitationProbability: weatherData.hourly.precipitationProbability,
shortwaveRadiation: weatherData.hourly.shortwaveRadiation,
timeDaily: weatherData.daily.time,
weathercodeDaily: weatherData.daily.weatherCode,
temperature2MMax: weatherData.daily.temperature2MMax,
temperature2MMin: weatherData.daily.temperature2MMin,
apparentTemperatureMax: weatherData.daily.apparentTemperatureMax,
apparentTemperatureMin: weatherData.daily.apparentTemperatureMin,
sunrise: weatherData.daily.sunrise,
sunset: weatherData.daily.sunset,
precipitationSum: weatherData.daily.precipitationSum,
precipitationProbabilityMax:
weatherData.daily.precipitationProbabilityMax,
windspeed10MMax: weatherData.daily.windSpeed10MMax,
windgusts10MMax: weatherData.daily.windGusts10MMax,
uvIndexMax: weatherData.daily.uvIndexMax,
rainSum: weatherData.daily.rainSum,
winddirection10MDominant: weatherData.daily.windDirection10MDominant,
timezone: weatherData.timezone,
timestamp: DateTime.now(),
);
} on DioException catch (e) { } on DioException catch (e) {
if (kDebugMode) { if (kDebugMode) {
print(e); print(e);
@ -72,63 +41,24 @@ class WeatherAPI {
} }
} }
Future<WeatherCard> getWeatherCard(double? lat, double? lon, String city, Future<WeatherCard> getWeatherCard(
String district, String timezone) async { double lat,
String url = double lon,
'latitude=$lat&longitude=$lon&hourly=temperature_2m,relativehumidity_2m,apparent_temperature,precipitation,rain,weathercode,surface_pressure,visibility,evapotranspiration,windspeed_10m,winddirection_10m,windgusts_10m,cloudcover,uv_index,dewpoint_2m,precipitation_probability,shortwave_radiation&daily=weathercode,temperature_2m_max,temperature_2m_min,apparent_temperature_max,apparent_temperature_min,sunrise,sunset,precipitation_sum,precipitation_probability_max,windspeed_10m_max,windgusts_10m_max,uv_index_max,rain_sum,winddirection_10m_dominant&forecast_days=12&timezone=auto'; String city,
String urlWeather; String district,
settings.measurements == 'imperial' && settings.degrees == 'fahrenheit' String timezone,
? urlWeather = ) async {
'$url&temperature_unit=fahrenheit&windspeed_unit=mph&precipitation_unit=inch' final String urlWeather = _buildWeatherUrl(lat, lon);
: settings.measurements == 'imperial'
? urlWeather = '$url&windspeed_unit=mph&precipitation_unit=inch'
: settings.degrees == 'fahrenheit'
? urlWeather = '$url&temperature_unit=fahrenheit'
: urlWeather = url;
try { try {
Response response = await dio.get(urlWeather); Response response = await dio.get(urlWeather);
WeatherDataApi weatherData = WeatherDataApi.fromJson(response.data); WeatherDataApi weatherData = WeatherDataApi.fromJson(response.data);
return WeatherCard( return _mapWeatherDataToCard(
time: weatherData.hourly.time, weatherData,
temperature2M: weatherData.hourly.temperature2M, lat,
relativehumidity2M: weatherData.hourly.relativeHumidity2M, lon,
apparentTemperature: weatherData.hourly.apparentTemperature, city,
precipitation: weatherData.hourly.precipitation, district,
rain: weatherData.hourly.rain, timezone,
weathercode: weatherData.hourly.weatherCode,
surfacePressure: weatherData.hourly.surfacePressure,
visibility: weatherData.hourly.visibility,
evapotranspiration: weatherData.hourly.evapotranspiration,
windspeed10M: weatherData.hourly.windSpeed10M,
winddirection10M: weatherData.hourly.windDirection10M,
windgusts10M: weatherData.hourly.windGusts10M,
cloudcover: weatherData.hourly.cloudCover,
uvIndex: weatherData.hourly.uvIndex,
dewpoint2M: weatherData.hourly.dewpoint2M,
precipitationProbability: weatherData.hourly.precipitationProbability,
shortwaveRadiation: weatherData.hourly.shortwaveRadiation,
timeDaily: weatherData.daily.time,
weathercodeDaily: weatherData.daily.weatherCode,
temperature2MMax: weatherData.daily.temperature2MMax,
temperature2MMin: weatherData.daily.temperature2MMin,
apparentTemperatureMax: weatherData.daily.apparentTemperatureMax,
apparentTemperatureMin: weatherData.daily.apparentTemperatureMin,
sunrise: weatherData.daily.sunrise,
sunset: weatherData.daily.sunset,
precipitationSum: weatherData.daily.precipitationSum,
precipitationProbabilityMax:
weatherData.daily.precipitationProbabilityMax,
windspeed10MMax: weatherData.daily.windSpeed10MMax,
windgusts10MMax: weatherData.daily.windGusts10MMax,
uvIndexMax: weatherData.daily.uvIndexMax,
rainSum: weatherData.daily.rainSum,
winddirection10MDominant: weatherData.daily.windDirection10MDominant,
lat: lat,
lon: lon,
city: city,
district: district,
timezone: timezone,
timestamp: DateTime.now(),
); );
} on DioException catch (e) { } on DioException catch (e) {
if (kDebugMode) { if (kDebugMode) {
@ -139,7 +69,7 @@ class WeatherAPI {
} }
Future<Iterable<Result>> getCity(String query, Locale? locale) async { Future<Iterable<Result>> getCity(String query, Locale? locale) async {
final url = final String url =
'https://geocoding-api.open-meteo.com/v1/search?name=$query&count=5&language=${locale?.languageCode}&format=json'; 'https://geocoding-api.open-meteo.com/v1/search?name=$query&count=5&language=${locale?.languageCode}&format=json';
try { try {
Response response = await dioLocation.get(url); Response response = await dioLocation.get(url);
@ -163,4 +93,97 @@ class WeatherAPI {
rethrow; rethrow;
} }
} }
MainWeatherCache _mapWeatherDataToCache(WeatherDataApi weatherData) {
return MainWeatherCache(
time: weatherData.hourly.time,
temperature2M: weatherData.hourly.temperature2M,
relativehumidity2M: weatherData.hourly.relativeHumidity2M,
apparentTemperature: weatherData.hourly.apparentTemperature,
precipitation: weatherData.hourly.precipitation,
rain: weatherData.hourly.rain,
weathercode: weatherData.hourly.weatherCode,
surfacePressure: weatherData.hourly.surfacePressure,
visibility: weatherData.hourly.visibility,
evapotranspiration: weatherData.hourly.evapotranspiration,
windspeed10M: weatherData.hourly.windSpeed10M,
winddirection10M: weatherData.hourly.windDirection10M,
windgusts10M: weatherData.hourly.windGusts10M,
cloudcover: weatherData.hourly.cloudCover,
uvIndex: weatherData.hourly.uvIndex,
dewpoint2M: weatherData.hourly.dewpoint2M,
precipitationProbability: weatherData.hourly.precipitationProbability,
shortwaveRadiation: weatherData.hourly.shortwaveRadiation,
timeDaily: weatherData.daily.time,
weathercodeDaily: weatherData.daily.weatherCode,
temperature2MMax: weatherData.daily.temperature2MMax,
temperature2MMin: weatherData.daily.temperature2MMin,
apparentTemperatureMax: weatherData.daily.apparentTemperatureMax,
apparentTemperatureMin: weatherData.daily.apparentTemperatureMin,
sunrise: weatherData.daily.sunrise,
sunset: weatherData.daily.sunset,
precipitationSum: weatherData.daily.precipitationSum,
precipitationProbabilityMax:
weatherData.daily.precipitationProbabilityMax,
windspeed10MMax: weatherData.daily.windSpeed10MMax,
windgusts10MMax: weatherData.daily.windGusts10MMax,
uvIndexMax: weatherData.daily.uvIndexMax,
rainSum: weatherData.daily.rainSum,
winddirection10MDominant: weatherData.daily.windDirection10MDominant,
timezone: weatherData.timezone,
timestamp: DateTime.now(),
);
}
WeatherCard _mapWeatherDataToCard(
WeatherDataApi weatherData,
double lat,
double lon,
String city,
String district,
String timezone,
) {
return WeatherCard(
time: weatherData.hourly.time,
temperature2M: weatherData.hourly.temperature2M,
relativehumidity2M: weatherData.hourly.relativeHumidity2M,
apparentTemperature: weatherData.hourly.apparentTemperature,
precipitation: weatherData.hourly.precipitation,
rain: weatherData.hourly.rain,
weathercode: weatherData.hourly.weatherCode,
surfacePressure: weatherData.hourly.surfacePressure,
visibility: weatherData.hourly.visibility,
evapotranspiration: weatherData.hourly.evapotranspiration,
windspeed10M: weatherData.hourly.windSpeed10M,
winddirection10M: weatherData.hourly.windDirection10M,
windgusts10M: weatherData.hourly.windGusts10M,
cloudcover: weatherData.hourly.cloudCover,
uvIndex: weatherData.hourly.uvIndex,
dewpoint2M: weatherData.hourly.dewpoint2M,
precipitationProbability: weatherData.hourly.precipitationProbability,
shortwaveRadiation: weatherData.hourly.shortwaveRadiation,
timeDaily: weatherData.daily.time,
weathercodeDaily: weatherData.daily.weatherCode,
temperature2MMax: weatherData.daily.temperature2MMax,
temperature2MMin: weatherData.daily.temperature2MMin,
apparentTemperatureMax: weatherData.daily.apparentTemperatureMax,
apparentTemperatureMin: weatherData.daily.apparentTemperatureMin,
sunrise: weatherData.daily.sunrise,
sunset: weatherData.daily.sunset,
precipitationSum: weatherData.daily.precipitationSum,
precipitationProbabilityMax:
weatherData.daily.precipitationProbabilityMax,
windspeed10MMax: weatherData.daily.windSpeed10MMax,
windgusts10MMax: weatherData.daily.windGusts10MMax,
uvIndexMax: weatherData.daily.uvIndexMax,
rainSum: weatherData.daily.rainSum,
winddirection10MDominant: weatherData.daily.windDirection10MDominant,
lat: lat,
lon: lon,
city: city,
district: district,
timezone: timezone,
timestamp: DateTime.now(),
);
}
} }

19
lib/app/api/city.dart → lib/app/api/city_api.dart Normal file → Executable file
View file

@ -1,15 +1,14 @@
class CityApi { class CityApi {
CityApi({ CityApi({required this.results});
required this.results,
});
List<Result> results; List<Result> results;
factory CityApi.fromJson(Map<String, dynamic> json) => CityApi( factory CityApi.fromJson(Map<String, dynamic> json) => CityApi(
results: json['results'] == null results:
json['results'] == null
? List<Result>.empty() ? List<Result>.empty()
: List<Result>.from(json['results'].map((x) => Result.fromJson(x))), : List<Result>.from(json['results'].map((x) => Result.fromJson(x))),
); );
} }
class Result { class Result {
@ -26,9 +25,9 @@ class Result {
double longitude; double longitude;
factory Result.fromJson(Map<String, dynamic> json) => Result( factory Result.fromJson(Map<String, dynamic> json) => Result(
admin1: json['admin1'] ?? '', admin1: json['admin1'] ?? '',
name: json['name'], name: json['name'],
latitude: json['latitude'], latitude: json['latitude'],
longitude: json['longitude'], longitude: json['longitude'],
); );
} }

View file

@ -2,8 +2,8 @@ import 'package:freezed_annotation/freezed_annotation.dart';
//ignore_for_file: invalid_annotation_target //ignore_for_file: invalid_annotation_target
part 'weather.freezed.dart'; part 'weather_api.freezed.dart';
part 'weather.g.dart'; part 'weather_api.g.dart';
@freezed @freezed
class WeatherDataApi with _$WeatherDataApi { class WeatherDataApi with _$WeatherDataApi {

View file

@ -3,7 +3,7 @@
// ignore_for_file: type=lint // ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'weather.dart'; part of 'weather_api.dart';
// ************************************************************************** // **************************************************************************
// FreezedGenerator // FreezedGenerator
@ -24,8 +24,12 @@ mixin _$WeatherDataApi {
Daily get daily => throw _privateConstructorUsedError; Daily get daily => throw _privateConstructorUsedError;
String get timezone => throw _privateConstructorUsedError; String get timezone => throw _privateConstructorUsedError;
/// Serializes this WeatherDataApi to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError; Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
/// Create a copy of WeatherDataApi
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$WeatherDataApiCopyWith<WeatherDataApi> get copyWith => $WeatherDataApiCopyWith<WeatherDataApi> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@ -52,6 +56,8 @@ class _$WeatherDataApiCopyWithImpl<$Res, $Val extends WeatherDataApi>
// ignore: unused_field // ignore: unused_field
final $Res Function($Val) _then; final $Res Function($Val) _then;
/// Create a copy of WeatherDataApi
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@override @override
$Res call({ $Res call({
@ -75,6 +81,8 @@ class _$WeatherDataApiCopyWithImpl<$Res, $Val extends WeatherDataApi>
) as $Val); ) as $Val);
} }
/// Create a copy of WeatherDataApi
/// with the given fields replaced by the non-null parameter values.
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
$HourlyCopyWith<$Res> get hourly { $HourlyCopyWith<$Res> get hourly {
@ -83,6 +91,8 @@ class _$WeatherDataApiCopyWithImpl<$Res, $Val extends WeatherDataApi>
}); });
} }
/// Create a copy of WeatherDataApi
/// with the given fields replaced by the non-null parameter values.
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
$DailyCopyWith<$Res> get daily { $DailyCopyWith<$Res> get daily {
@ -116,6 +126,8 @@ class __$$WeatherDataApiImplCopyWithImpl<$Res>
_$WeatherDataApiImpl _value, $Res Function(_$WeatherDataApiImpl) _then) _$WeatherDataApiImpl _value, $Res Function(_$WeatherDataApiImpl) _then)
: super(_value, _then); : super(_value, _then);
/// Create a copy of WeatherDataApi
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@override @override
$Res call({ $Res call({
@ -172,11 +184,13 @@ class _$WeatherDataApiImpl implements _WeatherDataApi {
other.timezone == timezone)); other.timezone == timezone));
} }
@JsonKey(ignore: true) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash(runtimeType, hourly, daily, timezone); int get hashCode => Object.hash(runtimeType, hourly, daily, timezone);
@JsonKey(ignore: true) /// Create a copy of WeatherDataApi
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$WeatherDataApiImplCopyWith<_$WeatherDataApiImpl> get copyWith => _$$WeatherDataApiImplCopyWith<_$WeatherDataApiImpl> get copyWith =>
@ -206,8 +220,11 @@ abstract class _WeatherDataApi implements WeatherDataApi {
Daily get daily; Daily get daily;
@override @override
String get timezone; String get timezone;
/// Create a copy of WeatherDataApi
/// with the given fields replaced by the non-null parameter values.
@override @override
@JsonKey(ignore: true) @JsonKey(includeFromJson: false, includeToJson: false)
_$$WeatherDataApiImplCopyWith<_$WeatherDataApiImpl> get copyWith => _$$WeatherDataApiImplCopyWith<_$WeatherDataApiImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@ -251,8 +268,12 @@ mixin _$Hourly {
@JsonKey(name: 'shortwave_radiation') @JsonKey(name: 'shortwave_radiation')
List<double?>? get shortwaveRadiation => throw _privateConstructorUsedError; List<double?>? get shortwaveRadiation => throw _privateConstructorUsedError;
/// Serializes this Hourly to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError; Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
/// Create a copy of Hourly
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$HourlyCopyWith<Hourly> get copyWith => throw _privateConstructorUsedError; $HourlyCopyWith<Hourly> get copyWith => throw _privateConstructorUsedError;
} }
@ -293,6 +314,8 @@ class _$HourlyCopyWithImpl<$Res, $Val extends Hourly>
// ignore: unused_field // ignore: unused_field
final $Res Function($Val) _then; final $Res Function($Val) _then;
/// Create a copy of Hourly
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@override @override
$Res call({ $Res call({
@ -429,6 +452,8 @@ class __$$HourlyImplCopyWithImpl<$Res>
_$HourlyImpl _value, $Res Function(_$HourlyImpl) _then) _$HourlyImpl _value, $Res Function(_$HourlyImpl) _then)
: super(_value, _then); : super(_value, _then);
/// Create a copy of Hourly
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@override @override
$Res call({ $Res call({
@ -820,7 +845,7 @@ class _$HourlyImpl implements _Hourly {
.equals(other._shortwaveRadiation, _shortwaveRadiation)); .equals(other._shortwaveRadiation, _shortwaveRadiation));
} }
@JsonKey(ignore: true) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash( int get hashCode => Object.hash(
runtimeType, runtimeType,
@ -843,7 +868,9 @@ class _$HourlyImpl implements _Hourly {
const DeepCollectionEquality().hash(_precipitationProbability), const DeepCollectionEquality().hash(_precipitationProbability),
const DeepCollectionEquality().hash(_shortwaveRadiation)); const DeepCollectionEquality().hash(_shortwaveRadiation));
@JsonKey(ignore: true) /// Create a copy of Hourly
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$HourlyImplCopyWith<_$HourlyImpl> get copyWith => _$$HourlyImplCopyWith<_$HourlyImpl> get copyWith =>
@ -933,8 +960,11 @@ abstract class _Hourly implements Hourly {
@override @override
@JsonKey(name: 'shortwave_radiation') @JsonKey(name: 'shortwave_radiation')
List<double?>? get shortwaveRadiation; List<double?>? get shortwaveRadiation;
/// Create a copy of Hourly
/// with the given fields replaced by the non-null parameter values.
@override @override
@JsonKey(ignore: true) @JsonKey(includeFromJson: false, includeToJson: false)
_$$HourlyImplCopyWith<_$HourlyImpl> get copyWith => _$$HourlyImplCopyWith<_$HourlyImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
@ -978,8 +1008,12 @@ mixin _$Daily {
List<int?>? get windDirection10MDominant => List<int?>? get windDirection10MDominant =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
/// Serializes this Daily to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError; Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
/// Create a copy of Daily
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$DailyCopyWith<Daily> get copyWith => throw _privateConstructorUsedError; $DailyCopyWith<Daily> get copyWith => throw _privateConstructorUsedError;
} }
@ -1020,6 +1054,8 @@ class _$DailyCopyWithImpl<$Res, $Val extends Daily>
// ignore: unused_field // ignore: unused_field
final $Res Function($Val) _then; final $Res Function($Val) _then;
/// Create a copy of Daily
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@override @override
$Res call({ $Res call({
@ -1141,6 +1177,8 @@ class __$$DailyImplCopyWithImpl<$Res>
_$DailyImpl _value, $Res Function(_$DailyImpl) _then) _$DailyImpl _value, $Res Function(_$DailyImpl) _then)
: super(_value, _then); : super(_value, _then);
/// Create a copy of Daily
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
@override @override
$Res call({ $Res call({
@ -1478,7 +1516,7 @@ class _$DailyImpl implements _Daily {
other._windDirection10MDominant, _windDirection10MDominant)); other._windDirection10MDominant, _windDirection10MDominant));
} }
@JsonKey(ignore: true) @JsonKey(includeFromJson: false, includeToJson: false)
@override @override
int get hashCode => Object.hash( int get hashCode => Object.hash(
runtimeType, runtimeType,
@ -1498,7 +1536,9 @@ class _$DailyImpl implements _Daily {
const DeepCollectionEquality().hash(_rainSum), const DeepCollectionEquality().hash(_rainSum),
const DeepCollectionEquality().hash(_windDirection10MDominant)); const DeepCollectionEquality().hash(_windDirection10MDominant));
@JsonKey(ignore: true) /// Create a copy of Daily
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override @override
@pragma('vm:prefer-inline') @pragma('vm:prefer-inline')
_$$DailyImplCopyWith<_$DailyImpl> get copyWith => _$$DailyImplCopyWith<_$DailyImpl> get copyWith =>
@ -1581,8 +1621,11 @@ abstract class _Daily implements Daily {
@override @override
@JsonKey(name: 'winddirection_10m_dominant') @JsonKey(name: 'winddirection_10m_dominant')
List<int?>? get windDirection10MDominant; List<int?>? get windDirection10MDominant;
/// Create a copy of Daily
/// with the given fields replaced by the non-null parameter values.
@override @override
@JsonKey(ignore: true) @JsonKey(includeFromJson: false, includeToJson: false)
_$$DailyImplCopyWith<_$DailyImpl> get copyWith => _$$DailyImplCopyWith<_$DailyImpl> get copyWith =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }

View file

@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'weather.dart'; part of 'weather_api.dart';
// ************************************************************************** // **************************************************************************
// JsonSerializableGenerator // JsonSerializableGenerator

447
lib/app/controller/controller.dart Normal file → Executable file
View file

@ -1,7 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_timezone/flutter_timezone.dart'; import 'package:flutter_timezone/flutter_timezone.dart';
import 'package:geocoding/geocoding.dart'; import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart'; import 'package:geolocator/geolocator.dart';
@ -11,16 +10,17 @@ import 'package:isar/isar.dart';
import 'package:lat_lng_to_timezone/lat_lng_to_timezone.dart' as tzmap; import 'package:lat_lng_to_timezone/lat_lng_to_timezone.dart' as tzmap;
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:rain/app/api/api.dart'; import 'package:rain/app/api/api.dart';
import 'package:rain/app/data/weather.dart'; import 'package:rain/app/data/db.dart';
import 'package:rain/app/services/notification.dart'; import 'package:rain/app/utils/notification.dart';
import 'package:rain/app/services/utils.dart'; import 'package:rain/app/utils/show_snack_bar.dart';
import 'package:rain/app/widgets/status/status_data.dart'; import 'package:rain/app/ui/widgets/weather/status/status_data.dart';
import 'package:rain/app/widgets/status/status_weather.dart'; import 'package:rain/app/ui/widgets/weather/status/status_weather.dart';
import 'package:rain/main.dart'; import 'package:rain/main.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
import 'package:timezone/data/latest_all.dart' as tz; import 'package:timezone/data/latest_all.dart' as tz;
import 'package:timezone/standalone.dart' as tz; import 'package:timezone/standalone.dart' as tz;
import 'package:timezone/timezone.dart' as tz; import 'package:timezone/timezone.dart' as tz;
import 'package:url_launcher/url_launcher.dart';
import 'package:workmanager/workmanager.dart'; import 'package:workmanager/workmanager.dart';
class WeatherController extends GetxController { class WeatherController extends GetxController {
@ -52,15 +52,14 @@ class WeatherController extends GetxController {
@override @override
void onInit() { void onInit() {
weatherCards weatherCards.assignAll(
.assignAll(isar.weatherCards.where().sortByIndex().findAllSync()); isar.weatherCards.where().sortByIndex().findAllSync(),
);
super.onInit(); super.onInit();
} }
Future<Position> determinePosition() async { Future<Position> _determinePosition() async {
LocationPermission permission; LocationPermission permission = await Geolocator.checkPermission();
permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) { if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission(); permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) { if (permission == LocationPermission.denied) {
@ -70,35 +69,36 @@ class WeatherController extends GetxController {
if (permission == LocationPermission.deniedForever) { if (permission == LocationPermission.deniedForever) {
return Future.error( 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( return await Geolocator.getCurrentPosition();
desiredAccuracy: LocationAccuracy.high);
} }
Future<void> setLocation() async { Future<void> setLocation() async {
if (settings.location) { if (settings.location) {
await getCurrentLocation(); await getCurrentLocation();
} else { } else {
if ((isar.locationCaches.where().findAllSync()).isNotEmpty) { final locationCity = isar.locationCaches.where().findFirstSync();
LocationCache locationCity = if (locationCity != null) {
(isar.locationCaches.where().findFirstSync())!; await getLocation(
await getLocation(locationCity.lat!, locationCity.lon!, locationCity.lat!,
locationCity.district!, locationCity.city!); locationCity.lon!,
locationCity.district!,
locationCity.city!,
);
} }
} }
} }
Future<void> getCurrentLocation() async { Future<void> getCurrentLocation() async {
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!(await isOnline.value)) { if (!(await isOnline.value)) {
showSnackBar(content: 'no_inter'.tr); showSnackBar(content: 'no_inter'.tr);
await readCache(); await readCache();
return; return;
} }
if (!serviceEnabled) { if (!await Geolocator.isLocationServiceEnabled()) {
showSnackBar( showSnackBar(
content: 'no_location'.tr, content: 'no_location'.tr,
onPressed: () => Geolocator.openLocationSettings(), onPressed: () => Geolocator.openLocationSettings(),
@ -107,70 +107,73 @@ class WeatherController extends GetxController {
return; return;
} }
if ((isar.mainWeatherCaches.where().findAllSync()).isNotEmpty) { if (isar.mainWeatherCaches.where().findAllSync().isNotEmpty) {
await readCache(); await readCache();
return; return;
} }
Position position = await determinePosition(); final position = await _determinePosition();
List<Placemark> placemarks = final placemarks = await placemarkFromCoordinates(
await placemarkFromCoordinates(position.latitude, position.longitude); position.latitude,
Placemark place = placemarks[0]; position.longitude,
);
final place = placemarks[0];
_latitude.value = position.latitude; _latitude.value = position.latitude;
_longitude.value = position.longitude; _longitude.value = position.longitude;
_district.value = '${place.administrativeArea}'; _district.value = place.administrativeArea ?? '';
_city.value = '${place.locality}'; _city.value = place.locality ?? '';
_mainWeather.value = _mainWeather.value = await WeatherAPI().getWeatherData(
await WeatherAPI().getWeatherData(_latitude.value, _longitude.value); _latitude.value,
_longitude.value,
);
notificationCheck(); notificationCheck();
await writeCache(); await writeCache();
await readCache(); await readCache();
} }
Future<Map> getCurrentLocationSearch() async { Future<Map<String, dynamic>> getCurrentLocationSearch() async {
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
double lat, lon;
String city, district;
if (!(await isOnline.value)) { if (!(await isOnline.value)) {
showSnackBar(content: 'no_inter'.tr); showSnackBar(content: 'no_inter'.tr);
} }
if (!serviceEnabled) { if (!await Geolocator.isLocationServiceEnabled()) {
showSnackBar( showSnackBar(
content: 'no_location'.tr, content: 'no_location'.tr,
onPressed: () => Geolocator.openLocationSettings(), onPressed: () => Geolocator.openLocationSettings(),
); );
} }
Position position = await determinePosition(); final position = await _determinePosition();
List<Placemark> placemarks = final placemarks = await placemarkFromCoordinates(
await placemarkFromCoordinates(position.latitude, position.longitude); position.latitude,
Placemark place = placemarks[0]; position.longitude,
);
final place = placemarks[0];
lat = position.latitude; return {
lon = position.longitude; 'lat': position.latitude,
city = '${place.administrativeArea}'; 'lon': position.longitude,
district = '${place.locality}'; 'city': place.administrativeArea ?? '',
'district': place.locality ?? '',
Map location = {'lat': lat, 'lon': lon, 'city': city, 'district': district}; };
return location;
} }
Future<void> getLocation(double latitude, double longitude, String district, Future<void> getLocation(
String locality) async { double latitude,
double longitude,
String district,
String locality,
) async {
if (!(await isOnline.value)) { if (!(await isOnline.value)) {
showSnackBar(content: 'no_inter'.tr); showSnackBar(content: 'no_inter'.tr);
await readCache(); await readCache();
return; return;
} }
if ((isar.mainWeatherCaches.where().findAllSync()).isNotEmpty) { if (isar.mainWeatherCaches.where().findAllSync().isNotEmpty) {
await readCache(); await readCache();
return; return;
} }
@ -180,11 +183,12 @@ class WeatherController extends GetxController {
_district.value = district; _district.value = district;
_city.value = locality; _city.value = locality;
_mainWeather.value = _mainWeather.value = await WeatherAPI().getWeatherData(
await WeatherAPI().getWeatherData(_latitude.value, _longitude.value); _latitude.value,
_longitude.value,
);
notificationCheck(); notificationCheck();
await writeCache(); await writeCache();
await readCache(); await readCache();
} }
@ -201,10 +205,14 @@ class WeatherController extends GetxController {
_mainWeather.value = mainWeatherCache; _mainWeather.value = mainWeatherCache;
_location.value = locationCache; _location.value = locationCache;
hourOfDay.value = hourOfDay.value = getTime(
getTime(_mainWeather.value.time!, _mainWeather.value.timezone!); _mainWeather.value.time!,
dayOfNow.value = _mainWeather.value.timezone!,
getDay(_mainWeather.value.timeDaily!, _mainWeather.value.timezone!); );
dayOfNow.value = getDay(
_mainWeather.value.timeDaily!,
_mainWeather.value.timezone!,
);
if (Platform.isAndroid) { if (Platform.isAndroid) {
Workmanager().registerPeriodicTask( Workmanager().registerPeriodicTask(
@ -235,16 +243,10 @@ class WeatherController extends GetxController {
); );
isar.writeTxnSync(() { isar.writeTxnSync(() {
final mainWeatherCachesIsEmpty = if (isar.mainWeatherCaches.where().findAllSync().isEmpty) {
(isar.mainWeatherCaches.where().findAllSync()).isEmpty;
final locationCachesIsEmpty =
(isar.locationCaches.where().findAllSync()).isEmpty;
if (mainWeatherCachesIsEmpty) {
isar.mainWeatherCaches.putSync(_mainWeather.value); isar.mainWeatherCaches.putSync(_mainWeather.value);
} }
if (isar.locationCaches.where().findAllSync().isEmpty) {
if (locationCachesIsEmpty) {
isar.locationCaches.putSync(locationCaches); isar.locationCaches.putSync(locationCaches);
} }
}); });
@ -261,7 +263,7 @@ class WeatherController extends GetxController {
.timestampLessThan(cacheExpiry) .timestampLessThan(cacheExpiry)
.deleteAllSync(); .deleteAllSync();
}); });
if ((isar.mainWeatherCaches.where().findAllSync()).isEmpty) { if (isar.mainWeatherCaches.where().findAllSync().isEmpty) {
await flutterLocalNotificationsPlugin.cancelAll(); await flutterLocalNotificationsPlugin.cancelAll();
} }
} }
@ -271,31 +273,39 @@ class WeatherController extends GetxController {
return; return;
} }
bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); final serviceEnabled = await Geolocator.isLocationServiceEnabled();
await flutterLocalNotificationsPlugin.cancelAll(); await flutterLocalNotificationsPlugin.cancelAll();
isar.writeTxnSync(() { isar.writeTxnSync(() {
if (!settings.location) { if (!settings.location) {
isar.mainWeatherCaches.where().deleteAllSync(); isar.mainWeatherCaches.where().deleteAllSync();
} }
if ((settings.location && serviceEnabled) || changeCity) { if (settings.location && serviceEnabled || changeCity) {
isar.mainWeatherCaches.where().deleteAllSync(); isar.mainWeatherCaches.where().deleteAllSync();
isar.locationCaches.where().deleteAllSync(); isar.locationCaches.where().deleteAllSync();
} }
}); });
} }
// Card Weather
Future<void> addCardWeather( Future<void> addCardWeather(
double latitude, double longitude, String city, String district) async { double latitude,
double longitude,
String city,
String district,
) async {
if (!(await isOnline.value)) { if (!(await isOnline.value)) {
showSnackBar(content: 'no_inter'.tr); showSnackBar(content: 'no_inter'.tr);
return; return;
} }
String tz = tzmap.latLngToTimezoneString(latitude, longitude); final tz = tzmap.latLngToTimezoneString(latitude, longitude);
_weatherCard.value = await WeatherAPI() _weatherCard.value = await WeatherAPI().getWeatherCard(
.getWeatherCard(latitude, longitude, city, district, tz); latitude,
longitude,
city,
district,
tz,
);
isar.writeTxnSync(() { isar.writeTxnSync(() {
weatherCards.add(_weatherCard.value); weatherCards.add(_weatherCard.value);
isar.weatherCards.putSync(_weatherCard.value); isar.weatherCards.putSync(_weatherCard.value);
@ -303,120 +313,88 @@ class WeatherController extends GetxController {
} }
Future<void> updateCacheCard(bool refresh) async { Future<void> updateCacheCard(bool refresh) async {
List<WeatherCard> weatherCard = refresh final weatherCard = refresh
? isar.weatherCards.where().sortByIndex().findAllSync() ? isar.weatherCards.where().sortByIndex().findAllSync()
: isar.weatherCards : isar.weatherCards
.filter() .filter()
.timestampLessThan(cacheExpiry) .timestampLessThan(cacheExpiry)
.sortByIndex() .sortByIndex()
.findAllSync(); .findAllSync();
if ((!(await isOnline.value)) || weatherCard.isEmpty) { if (!(await isOnline.value) || weatherCard.isEmpty) {
return; return;
} }
for (var oldCard in weatherCard) { for (var oldCard in weatherCard) {
var updatedCard = await WeatherAPI().getWeatherCard(oldCard.lat, final updatedCard = await WeatherAPI().getWeatherCard(
oldCard.lon, oldCard.city!, oldCard.district!, oldCard.timezone!); oldCard.lat!,
oldCard.lon!,
oldCard.city!,
oldCard.district!,
oldCard.timezone!,
);
isar.writeTxnSync(() { isar.writeTxnSync(() {
oldCard _updateWeatherCard(oldCard, updatedCard);
..time = updatedCard.time
..weathercode = updatedCard.weathercode
..temperature2M = updatedCard.temperature2M
..apparentTemperature = updatedCard.apparentTemperature
..relativehumidity2M = updatedCard.relativehumidity2M
..precipitation = updatedCard.precipitation
..rain = updatedCard.rain
..surfacePressure = updatedCard.surfacePressure
..visibility = updatedCard.visibility
..evapotranspiration = updatedCard.evapotranspiration
..windspeed10M = updatedCard.windspeed10M
..winddirection10M = updatedCard.winddirection10M
..windgusts10M = updatedCard.windgusts10M
..cloudcover = updatedCard.cloudcover
..uvIndex = updatedCard.uvIndex
..dewpoint2M = updatedCard.dewpoint2M
..precipitationProbability = updatedCard.precipitationProbability
..shortwaveRadiation = updatedCard.shortwaveRadiation
..timeDaily = updatedCard.timeDaily
..weathercodeDaily = updatedCard.weathercodeDaily
..temperature2MMax = updatedCard.temperature2MMax
..temperature2MMin = updatedCard.temperature2MMin
..apparentTemperatureMax = updatedCard.apparentTemperatureMax
..apparentTemperatureMin = updatedCard.apparentTemperatureMin
..sunrise = updatedCard.sunrise
..sunset = updatedCard.sunset
..precipitationSum = updatedCard.precipitationSum
..precipitationProbabilityMax =
updatedCard.precipitationProbabilityMax
..windspeed10MMax = updatedCard.windspeed10MMax
..windgusts10MMax = updatedCard.windgusts10MMax
..uvIndexMax = updatedCard.uvIndexMax
..rainSum = updatedCard.rainSum
..winddirection10MDominant = updatedCard.winddirection10MDominant
..timestamp = DateTime.now();
isar.weatherCards.putSync(oldCard);
var newCard = oldCard;
int oldIdx = weatherCard.indexOf(oldCard);
weatherCards[oldIdx] = newCard;
weatherCards.refresh(); weatherCards.refresh();
}); });
} }
} }
void _updateWeatherCard(WeatherCard oldCard, WeatherCard updatedCard) {
oldCard
..time = updatedCard.time
..weathercode = updatedCard.weathercode
..temperature2M = updatedCard.temperature2M
..apparentTemperature = updatedCard.apparentTemperature
..relativehumidity2M = updatedCard.relativehumidity2M
..precipitation = updatedCard.precipitation
..rain = updatedCard.rain
..surfacePressure = updatedCard.surfacePressure
..visibility = updatedCard.visibility
..evapotranspiration = updatedCard.evapotranspiration
..windspeed10M = updatedCard.windspeed10M
..winddirection10M = updatedCard.winddirection10M
..windgusts10M = updatedCard.windgusts10M
..cloudcover = updatedCard.cloudcover
..uvIndex = updatedCard.uvIndex
..dewpoint2M = updatedCard.dewpoint2M
..precipitationProbability = updatedCard.precipitationProbability
..shortwaveRadiation = updatedCard.shortwaveRadiation
..timeDaily = updatedCard.timeDaily
..weathercodeDaily = updatedCard.weathercodeDaily
..temperature2MMax = updatedCard.temperature2MMax
..temperature2MMin = updatedCard.temperature2MMin
..apparentTemperatureMax = updatedCard.apparentTemperatureMax
..apparentTemperatureMin = updatedCard.apparentTemperatureMin
..sunrise = updatedCard.sunrise
..sunset = updatedCard.sunset
..precipitationSum = updatedCard.precipitationSum
..precipitationProbabilityMax = updatedCard.precipitationProbabilityMax
..windspeed10MMax = updatedCard.windspeed10MMax
..windgusts10MMax = updatedCard.windgusts10MMax
..uvIndexMax = updatedCard.uvIndexMax
..rainSum = updatedCard.rainSum
..winddirection10MDominant = updatedCard.winddirection10MDominant
..timestamp = DateTime.now();
isar.weatherCards.putSync(oldCard);
}
Future<void> updateCard(WeatherCard weatherCard) async { Future<void> updateCard(WeatherCard weatherCard) async {
if (!(await isOnline.value)) { if (!(await isOnline.value)) {
return; return;
} }
final updatedCard = await WeatherAPI().getWeatherCard( final updatedCard = await WeatherAPI().getWeatherCard(
weatherCard.lat, weatherCard.lat!,
weatherCard.lon, weatherCard.lon!,
weatherCard.city!, weatherCard.city!,
weatherCard.district!, weatherCard.district!,
weatherCard.timezone!, weatherCard.timezone!,
); );
isar.writeTxnSync(() { isar.writeTxnSync(() {
weatherCard _updateWeatherCard(weatherCard, updatedCard);
..time = updatedCard.time
..weathercode = updatedCard.weathercode
..temperature2M = updatedCard.temperature2M
..apparentTemperature = updatedCard.apparentTemperature
..relativehumidity2M = updatedCard.relativehumidity2M
..precipitation = updatedCard.precipitation
..rain = updatedCard.rain
..surfacePressure = updatedCard.surfacePressure
..visibility = updatedCard.visibility
..evapotranspiration = updatedCard.evapotranspiration
..windspeed10M = updatedCard.windspeed10M
..winddirection10M = updatedCard.winddirection10M
..windgusts10M = updatedCard.windgusts10M
..cloudcover = updatedCard.cloudcover
..uvIndex = updatedCard.uvIndex
..dewpoint2M = updatedCard.dewpoint2M
..precipitationProbability = updatedCard.precipitationProbability
..shortwaveRadiation = updatedCard.shortwaveRadiation
..timeDaily = updatedCard.timeDaily
..weathercodeDaily = updatedCard.weathercodeDaily
..temperature2MMax = updatedCard.temperature2MMax
..temperature2MMin = updatedCard.temperature2MMin
..apparentTemperatureMax = updatedCard.apparentTemperatureMax
..apparentTemperatureMin = updatedCard.apparentTemperatureMin
..sunrise = updatedCard.sunrise
..sunset = updatedCard.sunset
..precipitationSum = updatedCard.precipitationSum
..precipitationProbabilityMax = updatedCard.precipitationProbabilityMax
..windspeed10MMax = updatedCard.windspeed10MMax
..windgusts10MMax = updatedCard.windgusts10MMax
..uvIndexMax = updatedCard.uvIndexMax
..rainSum = updatedCard.rainSum
..winddirection10MDominant = updatedCard.winddirection10MDominant
..timestamp = DateTime.now();
isar.weatherCards.putSync(weatherCard);
}); });
} }
@ -428,35 +406,26 @@ class WeatherController extends GetxController {
} }
int getTime(List<String> time, String timezone) { int getTime(List<String> time, String timezone) {
int getTime = 0; return time.indexWhere((t) {
for (var i = 0; i < time.length; i++) { final dateTime = DateTime.parse(t);
if (tz.TZDateTime.now(tz.getLocation(timezone)).hour == return tz.TZDateTime.now(tz.getLocation(timezone)).hour ==
DateTime.parse(time[i]).hour && dateTime.hour &&
tz.TZDateTime.now(tz.getLocation(timezone)).day == tz.TZDateTime.now(tz.getLocation(timezone)).day == dateTime.day;
DateTime.parse(time[i]).day) { });
getTime = i;
}
}
return getTime;
} }
int getDay(List<DateTime> time, String timezone) { int getDay(List<DateTime> time, String timezone) {
int getDay = 0; return time.indexWhere(
for (var i = 0; i < time.length; i++) { (t) => tz.TZDateTime.now(tz.getLocation(timezone)).day == t.day,
if (tz.TZDateTime.now(tz.getLocation(timezone)).day == time[i].day) { );
getDay = i;
}
}
return getDay;
} }
TimeOfDay timeConvert(String normTime) { TimeOfDay timeConvert(String normTime) {
int hh = 0; final hh = normTime.endsWith('PM') ? 12 : 0;
if (normTime.endsWith('PM')) hh = 12; final timeParts = normTime.split(' ')[0].split(':');
normTime = normTime.split(' ')[0];
return TimeOfDay( return TimeOfDay(
hour: hh + int.parse(normTime.split(':')[0]) % 24, hour: hh + int.parse(timeParts[0]) % 24,
minute: int.parse(normTime.split(':')[1]) % 60, minute: int.parse(timeParts[1]) % 60,
); );
} }
@ -464,8 +433,8 @@ class WeatherController extends GetxController {
final directory = await getTemporaryDirectory(); final directory = await getTemporaryDirectory();
final imagePath = '${directory.path}/$icon'; final imagePath = '${directory.path}/$icon';
final ByteData data = await rootBundle.load('assets/images/$icon'); final data = await rootBundle.load('assets/images/$icon');
final List<int> bytes = data.buffer.asUint8List(); final bytes = data.buffer.asUint8List();
await File(imagePath).writeAsBytes(bytes); await File(imagePath).writeAsBytes(bytes);
@ -473,30 +442,30 @@ class WeatherController extends GetxController {
} }
void notification(MainWeatherCache mainWeatherCache) async { void notification(MainWeatherCache mainWeatherCache) async {
DateTime now = DateTime.now(); final now = DateTime.now();
int startHour = timeConvert(timeStart).hour; final startHour = timeConvert(timeStart).hour;
int endHour = timeConvert(timeEnd).hour; final endHour = timeConvert(timeEnd).hour;
for (var i = 0; i < mainWeatherCache.time!.length; i += timeRange) { for (var i = 0; i < mainWeatherCache.time!.length; i += timeRange) {
DateTime notificationTime = DateTime.parse(mainWeatherCache.time![i]); final notificationTime = DateTime.parse(mainWeatherCache.time![i]);
if (notificationTime.isAfter(now) && if (notificationTime.isAfter(now) &&
notificationTime.hour >= startHour && notificationTime.hour >= startHour &&
notificationTime.hour <= endHour) { notificationTime.hour <= endHour) {
for (var j = 0; j < mainWeatherCache.timeDaily!.length; j++) { for (var j = 0; j < mainWeatherCache.timeDaily!.length; j++) {
if (mainWeatherCache.timeDaily![j].day == notificationTime.day) { if (mainWeatherCache.timeDaily![j].day == notificationTime.day) {
NotificationShow().showNotification( NotificationShow().showNotification(
UniqueKey().hashCode, UniqueKey().hashCode,
'$city: ${mainWeatherCache.temperature2M![i]}°', '$city: ${mainWeatherCache.temperature2M![i]}°',
'${StatusWeather().getText(mainWeatherCache.weathercode![i])} · ${StatusData().getTimeFormat(mainWeatherCache.time![i])}', '${StatusWeather().getText(mainWeatherCache.weathercode![i])} · ${StatusData().getTimeFormat(mainWeatherCache.time![i])}',
notificationTime, notificationTime,
StatusWeather().getImageNotification( StatusWeather().getImageNotification(
mainWeatherCache.weathercode![i], mainWeatherCache.weathercode![i],
mainWeatherCache.time![i], mainWeatherCache.time![i],
mainWeatherCache.sunrise![j], mainWeatherCache.sunrise![j],
mainWeatherCache.sunset![j], mainWeatherCache.sunset![j],
), ),
); );
} }
} }
} }
@ -505,15 +474,15 @@ class WeatherController extends GetxController {
void notificationCheck() async { void notificationCheck() async {
if (settings.notifications) { if (settings.notifications) {
final List<PendingNotificationRequest> pendingNotificationRequests = final pendingNotificationRequests = await flutterLocalNotificationsPlugin
await flutterLocalNotificationsPlugin.pendingNotificationRequests(); .pendingNotificationRequests();
if (pendingNotificationRequests.isEmpty) { if (pendingNotificationRequests.isEmpty) {
notification(_mainWeather.value); notification(_mainWeather.value);
} }
} }
} }
void reorder(oldIndex, newIndex) { void reorder(int oldIndex, int newIndex) {
if (newIndex > oldIndex) { if (newIndex > oldIndex) {
newIndex -= 1; newIndex -= 1;
} }
@ -533,15 +502,11 @@ class WeatherController extends GetxController {
isar.settings.putSync(settings); isar.settings.putSync(settings);
}); });
return Future.wait<bool?>([ final results = await Future.wait<bool?>([
HomeWidget.saveWidgetData( HomeWidget.saveWidgetData('background_color', color),
'background_color',
color,
),
HomeWidget.updateWidget(androidName: androidWidgetName), HomeWidget.updateWidget(androidName: androidWidgetName),
]).then((value) { ]);
return !value.contains(false); return !results.contains(false);
});
} }
Future<bool> updateWidgetTextColor(String color) async { Future<bool> updateWidgetTextColor(String color) async {
@ -550,15 +515,11 @@ class WeatherController extends GetxController {
isar.settings.putSync(settings); isar.settings.putSync(settings);
}); });
return Future.wait<bool?>([ final results = await Future.wait<bool?>([
HomeWidget.saveWidgetData( HomeWidget.saveWidgetData('text_color', color),
'text_color',
color,
),
HomeWidget.updateWidget(androidName: androidWidgetName), HomeWidget.updateWidget(androidName: androidWidgetName),
]).then((value) { ]);
return !value.contains(false); return !results.contains(false);
});
} }
Future<bool> updateWidget() async { Future<bool> updateWidget() async {
@ -573,29 +534,39 @@ class WeatherController extends GetxController {
WeatherCardSchema, WeatherCardSchema,
], directory: (await getApplicationSupportDirectory()).path); ], directory: (await getApplicationSupportDirectory()).path);
MainWeatherCache? mainWeatherCache; final mainWeatherCache = isarWidget.mainWeatherCaches
mainWeatherCache = isarWidget.mainWeatherCaches.where().findFirstSync(); .where()
.findFirstSync();
if (mainWeatherCache == null) return false; if (mainWeatherCache == null) return false;
int hour = getTime(mainWeatherCache.time!, mainWeatherCache.timezone!); final hour = getTime(mainWeatherCache.time!, mainWeatherCache.timezone!);
int day = getDay(mainWeatherCache.timeDaily!, mainWeatherCache.timezone!); final day = getDay(mainWeatherCache.timeDaily!, mainWeatherCache.timezone!);
return Future.wait<bool?>([ final results = await Future.wait<bool?>([
HomeWidget.saveWidgetData( HomeWidget.saveWidgetData(
'weather_icon', 'weather_icon',
await getLocalImagePath(StatusWeather().getImageNotification( await getLocalImagePath(
StatusWeather().getImageNotification(
mainWeatherCache.weathercode![hour], mainWeatherCache.weathercode![hour],
mainWeatherCache.time![hour], mainWeatherCache.time![hour],
mainWeatherCache.sunrise![day], mainWeatherCache.sunrise![day],
mainWeatherCache.sunset![day], mainWeatherCache.sunset![day],
))), ),
),
),
HomeWidget.saveWidgetData( HomeWidget.saveWidgetData(
'weather_degree', 'weather_degree',
'${mainWeatherCache.temperature2M?[hour].round()}°', '${mainWeatherCache.temperature2M?[hour].round()}°',
), ),
HomeWidget.updateWidget(androidName: androidWidgetName), HomeWidget.updateWidget(androidName: androidWidgetName),
]).then((value) { ]);
return !value.contains(false); return !results.contains(false);
}); }
void urlLauncher(String uri) async {
final url = Uri.parse(uri);
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
throw Exception('Could not launch $url');
}
} }
} }

209
lib/app/data/weather.dart → lib/app/data/db.dart Normal file → Executable file
View file

@ -1,6 +1,6 @@
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
part 'weather.g.dart'; part 'db.g.dart';
@collection @collection
class Settings { class Settings {
@ -12,10 +12,14 @@ class Settings {
bool materialColor = false; bool materialColor = false;
bool amoledTheme = false; bool amoledTheme = false;
bool roundDegree = false; bool roundDegree = false;
bool largeElement = false;
bool hideMap = false;
String? widgetBackgroundColor; String? widgetBackgroundColor;
String? widgetTextColor; String? widgetTextColor;
String measurements = 'metric'; String measurements = 'metric';
String degrees = 'celsius'; String degrees = 'celsius';
String wind = 'kph';
String pressure = 'hPa';
String timeformat = '24'; String timeformat = '24';
String? language; String? language;
int? timeRange; int? timeRange;
@ -101,43 +105,43 @@ class MainWeatherCache {
}); });
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'id': id, 'id': id,
'time': time, 'time': time,
'weathercode': weathercode, 'weathercode': weathercode,
'temperature2M': temperature2M, 'temperature2M': temperature2M,
'apparentTemperature': apparentTemperature, 'apparentTemperature': apparentTemperature,
'relativehumidity2M': relativehumidity2M, 'relativehumidity2M': relativehumidity2M,
'precipitation': precipitation, 'precipitation': precipitation,
'rain': rain, 'rain': rain,
'surfacePressure': surfacePressure, 'surfacePressure': surfacePressure,
'visibility': visibility, 'visibility': visibility,
'evapotranspiration': evapotranspiration, 'evapotranspiration': evapotranspiration,
'windspeed10M': windspeed10M, 'windspeed10M': windspeed10M,
'winddirection10M': winddirection10M, 'winddirection10M': winddirection10M,
'windgusts10M': windgusts10M, 'windgusts10M': windgusts10M,
'cloudcover': cloudcover, 'cloudcover': cloudcover,
'uvIndex': uvIndex, 'uvIndex': uvIndex,
'dewpoint2M': dewpoint2M, 'dewpoint2M': dewpoint2M,
'precipitationProbability': precipitationProbability, 'precipitationProbability': precipitationProbability,
'shortwaveRadiation': shortwaveRadiation, 'shortwaveRadiation': shortwaveRadiation,
'timeDaily': timeDaily, 'timeDaily': timeDaily,
'weathercodeDaily': weathercodeDaily, 'weathercodeDaily': weathercodeDaily,
'temperature2MMax': temperature2MMax, 'temperature2MMax': temperature2MMax,
'temperature2MMin': temperature2MMin, 'temperature2MMin': temperature2MMin,
'apparentTemperatureMax': apparentTemperatureMax, 'apparentTemperatureMax': apparentTemperatureMax,
'apparentTemperatureMin': apparentTemperatureMin, 'apparentTemperatureMin': apparentTemperatureMin,
'sunrise': sunrise, 'sunrise': sunrise,
'sunset': sunset, 'sunset': sunset,
'precipitationSum': precipitationSum, 'precipitationSum': precipitationSum,
'precipitationProbabilityMax': precipitationProbabilityMax, 'precipitationProbabilityMax': precipitationProbabilityMax,
'windspeed10MMax': windspeed10MMax, 'windspeed10MMax': windspeed10MMax,
'windgusts10MMax': windgusts10MMax, 'windgusts10MMax': windgusts10MMax,
'uvIndexMax': uvIndexMax, 'uvIndexMax': uvIndexMax,
'rainSum': rainSum, 'rainSum': rainSum,
'winddirection10MDominant': winddirection10MDominant, 'winddirection10MDominant': winddirection10MDominant,
'timezone': timezone, 'timezone': timezone,
'timestamp': timestamp, 'timestamp': timestamp,
}; };
} }
@collection @collection
@ -148,12 +152,15 @@ class LocationCache {
String? city; String? city;
String? district; String? district;
LocationCache({ LocationCache({this.lat, this.lon, this.city, this.district});
this.lat,
this.lon, Map<String, dynamic> toJson() => {
this.city, 'id': id,
this.district, 'lat': lat,
}); 'lon': lon,
'city': city,
'district': district,
};
} }
@collection @collection
@ -244,56 +251,57 @@ class WeatherCard {
}); });
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {
'id': id, 'id': id,
'time': time, 'time': time,
'weathercode': weathercode, 'weathercode': weathercode,
'temperature2M': temperature2M, 'temperature2M': temperature2M,
'apparentTemperature': apparentTemperature, 'apparentTemperature': apparentTemperature,
'relativehumidity2M': relativehumidity2M, 'relativehumidity2M': relativehumidity2M,
'precipitation': precipitation, 'precipitation': precipitation,
'rain': rain, 'rain': rain,
'surfacePressure': surfacePressure, 'surfacePressure': surfacePressure,
'visibility': visibility, 'visibility': visibility,
'evapotranspiration': evapotranspiration, 'evapotranspiration': evapotranspiration,
'windspeed10M': windspeed10M, 'windspeed10M': windspeed10M,
'winddirection10M': winddirection10M, 'winddirection10M': winddirection10M,
'windgusts10M': windgusts10M, 'windgusts10M': windgusts10M,
'cloudcover': cloudcover, 'cloudcover': cloudcover,
'uvIndex': uvIndex, 'uvIndex': uvIndex,
'dewpoint2M': dewpoint2M, 'dewpoint2M': dewpoint2M,
'precipitationProbability': precipitationProbability, 'precipitationProbability': precipitationProbability,
'shortwaveRadiation': shortwaveRadiation, 'shortwaveRadiation': shortwaveRadiation,
'timeDaily': timeDaily, 'timeDaily': timeDaily,
'weathercodeDaily': weathercodeDaily, 'weathercodeDaily': weathercodeDaily,
'temperature2MMax': temperature2MMax, 'temperature2MMax': temperature2MMax,
'temperature2MMin': temperature2MMin, 'temperature2MMin': temperature2MMin,
'apparentTemperatureMax': apparentTemperatureMax, 'apparentTemperatureMax': apparentTemperatureMax,
'apparentTemperatureMin': apparentTemperatureMin, 'apparentTemperatureMin': apparentTemperatureMin,
'sunrise': sunrise, 'sunrise': sunrise,
'sunset': sunset, 'sunset': sunset,
'precipitationSum': precipitationSum, 'precipitationSum': precipitationSum,
'precipitationProbabilityMax': precipitationProbabilityMax, 'precipitationProbabilityMax': precipitationProbabilityMax,
'windspeed10MMax': windspeed10MMax, 'windspeed10MMax': windspeed10MMax,
'windgusts10MMax': windgusts10MMax, 'windgusts10MMax': windgusts10MMax,
'uvIndexMax': uvIndexMax, 'uvIndexMax': uvIndexMax,
'rainSum': rainSum, 'rainSum': rainSum,
'winddirection10MDominant': winddirection10MDominant, 'winddirection10MDominant': winddirection10MDominant,
'timezone': timezone, 'timezone': timezone,
'timestamp': timestamp, 'timestamp': timestamp,
'lat': lat, 'lat': lat,
'lon': lon, 'lon': lon,
'city': city, 'city': city,
'district': district, 'district': district,
'index': index, 'index': index,
}; };
factory WeatherCard.fromJson(Map<String, dynamic> json) { factory WeatherCard.fromJson(Map<String, dynamic> json) {
return WeatherCard( return WeatherCard(
time: List<String>.from(json['time'] ?? []), time: List<String>.from(json['time'] ?? []),
weathercode: List<int>.from(json['weathercode'] ?? []), weathercode: List<int>.from(json['weathercode'] ?? []),
temperature2M: List<double>.from(json['temperature2M'] ?? []), temperature2M: List<double>.from(json['temperature2M'] ?? []),
apparentTemperature: apparentTemperature: List<double?>.from(
List<double?>.from(json['apparentTemperature'] ?? []), json['apparentTemperature'] ?? [],
),
relativehumidity2M: List<int?>.from(json['relativehumidity2M'] ?? []), relativehumidity2M: List<int?>.from(json['relativehumidity2M'] ?? []),
precipitation: List<double>.from(json['precipitation'] ?? []), precipitation: List<double>.from(json['precipitation'] ?? []),
rain: List<double?>.from(json['rain'] ?? []), rain: List<double?>.from(json['rain'] ?? []),
@ -306,26 +314,31 @@ class WeatherCard {
cloudcover: List<int?>.from(json['cloudcover'] ?? []), cloudcover: List<int?>.from(json['cloudcover'] ?? []),
uvIndex: List<double?>.from(json['uvIndex'] ?? []), uvIndex: List<double?>.from(json['uvIndex'] ?? []),
dewpoint2M: List<double?>.from(json['dewpoint2M'] ?? []), dewpoint2M: List<double?>.from(json['dewpoint2M'] ?? []),
precipitationProbability: precipitationProbability: List<int?>.from(
List<int?>.from(json['precipitationProbability'] ?? []), json['precipitationProbability'] ?? [],
),
shortwaveRadiation: List<double?>.from(json['shortwaveRadiation'] ?? []), shortwaveRadiation: List<double?>.from(json['shortwaveRadiation'] ?? []),
timeDaily: List<DateTime>.from(json['timeDaily'] ?? []), timeDaily: List<DateTime>.from(json['timeDaily'] ?? []),
weathercodeDaily: List<int?>.from(json['weathercodeDaily'] ?? []), weathercodeDaily: List<int?>.from(json['weathercodeDaily'] ?? []),
temperature2MMax: List<double?>.from(json['temperature2MMax'] ?? []), temperature2MMax: List<double?>.from(json['temperature2MMax'] ?? []),
temperature2MMin: List<double?>.from(json['temperature2MMin'] ?? []), temperature2MMin: List<double?>.from(json['temperature2MMin'] ?? []),
apparentTemperatureMax: apparentTemperatureMax: List<double?>.from(
List<double?>.from(json['apparentTemperatureMax'] ?? []), json['apparentTemperatureMax'] ?? [],
apparentTemperatureMin: ),
List<double?>.from(json['apparentTemperatureMin'] ?? []), apparentTemperatureMin: List<double?>.from(
json['apparentTemperatureMin'] ?? [],
),
windspeed10MMax: List<double?>.from(json['windspeed10MMax'] ?? []), windspeed10MMax: List<double?>.from(json['windspeed10MMax'] ?? []),
windgusts10MMax: List<double?>.from(json['windgusts10MMax'] ?? []), windgusts10MMax: List<double?>.from(json['windgusts10MMax'] ?? []),
uvIndexMax: List<double?>.from(json['uvIndexMax'] ?? []), uvIndexMax: List<double?>.from(json['uvIndexMax'] ?? []),
rainSum: List<double?>.from(json['rainSum'] ?? []), rainSum: List<double?>.from(json['rainSum'] ?? []),
winddirection10MDominant: winddirection10MDominant: List<int?>.from(
List<int?>.from(json['winddirection10MDominant'] ?? []), json['winddirection10MDominant'] ?? [],
),
precipitationSum: List<double?>.from(json['precipitationSum'] ?? []), precipitationSum: List<double?>.from(json['precipitationSum'] ?? []),
precipitationProbabilityMax: precipitationProbabilityMax: List<int?>.from(
List<int?>.from(json['precipitationProbabilityMax'] ?? []), json['precipitationProbabilityMax'] ?? [],
),
sunrise: List<String>.from(json['sunrise'] ?? []), sunrise: List<String>.from(json['sunrise'] ?? []),
sunset: List<String>.from(json['sunset'] ?? []), sunset: List<String>.from(json['sunset'] ?? []),
lat: json['lat'], lat: json['lat'],

576
lib/app/data/weather.g.dart → lib/app/data/db.g.dart Normal file → Executable file
View file

@ -1,6 +1,6 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'weather.dart'; part of 'db.dart';
// ************************************************************************** // **************************************************************************
// IsarCollectionGenerator // IsarCollectionGenerator
@ -27,75 +27,95 @@ const SettingsSchema = CollectionSchema(
name: r'degrees', name: r'degrees',
type: IsarType.string, type: IsarType.string,
), ),
r'language': PropertySchema( r'hideMap': PropertySchema(
id: 2, id: 2,
name: r'hideMap',
type: IsarType.bool,
),
r'language': PropertySchema(
id: 3,
name: r'language', name: r'language',
type: IsarType.string, type: IsarType.string,
), ),
r'largeElement': PropertySchema(
id: 4,
name: r'largeElement',
type: IsarType.bool,
),
r'location': PropertySchema( r'location': PropertySchema(
id: 3, id: 5,
name: r'location', name: r'location',
type: IsarType.bool, type: IsarType.bool,
), ),
r'materialColor': PropertySchema( r'materialColor': PropertySchema(
id: 4, id: 6,
name: r'materialColor', name: r'materialColor',
type: IsarType.bool, type: IsarType.bool,
), ),
r'measurements': PropertySchema( r'measurements': PropertySchema(
id: 5, id: 7,
name: r'measurements', name: r'measurements',
type: IsarType.string, type: IsarType.string,
), ),
r'notifications': PropertySchema( r'notifications': PropertySchema(
id: 6, id: 8,
name: r'notifications', name: r'notifications',
type: IsarType.bool, type: IsarType.bool,
), ),
r'onboard': PropertySchema( r'onboard': PropertySchema(
id: 7, id: 9,
name: r'onboard', name: r'onboard',
type: IsarType.bool, type: IsarType.bool,
), ),
r'pressure': PropertySchema(
id: 10,
name: r'pressure',
type: IsarType.string,
),
r'roundDegree': PropertySchema( r'roundDegree': PropertySchema(
id: 8, id: 11,
name: r'roundDegree', name: r'roundDegree',
type: IsarType.bool, type: IsarType.bool,
), ),
r'theme': PropertySchema( r'theme': PropertySchema(
id: 9, id: 12,
name: r'theme', name: r'theme',
type: IsarType.string, type: IsarType.string,
), ),
r'timeEnd': PropertySchema( r'timeEnd': PropertySchema(
id: 10, id: 13,
name: r'timeEnd', name: r'timeEnd',
type: IsarType.string, type: IsarType.string,
), ),
r'timeRange': PropertySchema( r'timeRange': PropertySchema(
id: 11, id: 14,
name: r'timeRange', name: r'timeRange',
type: IsarType.long, type: IsarType.long,
), ),
r'timeStart': PropertySchema( r'timeStart': PropertySchema(
id: 12, id: 15,
name: r'timeStart', name: r'timeStart',
type: IsarType.string, type: IsarType.string,
), ),
r'timeformat': PropertySchema( r'timeformat': PropertySchema(
id: 13, id: 16,
name: r'timeformat', name: r'timeformat',
type: IsarType.string, type: IsarType.string,
), ),
r'widgetBackgroundColor': PropertySchema( r'widgetBackgroundColor': PropertySchema(
id: 14, id: 17,
name: r'widgetBackgroundColor', name: r'widgetBackgroundColor',
type: IsarType.string, type: IsarType.string,
), ),
r'widgetTextColor': PropertySchema( r'widgetTextColor': PropertySchema(
id: 15, id: 18,
name: r'widgetTextColor', name: r'widgetTextColor',
type: IsarType.string, type: IsarType.string,
),
r'wind': PropertySchema(
id: 19,
name: r'wind',
type: IsarType.string,
) )
}, },
estimateSize: _settingsEstimateSize, estimateSize: _settingsEstimateSize,
@ -109,7 +129,7 @@ const SettingsSchema = CollectionSchema(
getId: _settingsGetId, getId: _settingsGetId,
getLinks: _settingsGetLinks, getLinks: _settingsGetLinks,
attach: _settingsAttach, attach: _settingsAttach,
version: '3.1.7', version: '3.1.8',
); );
int _settingsEstimateSize( int _settingsEstimateSize(
@ -126,6 +146,7 @@ int _settingsEstimateSize(
} }
} }
bytesCount += 3 + object.measurements.length * 3; bytesCount += 3 + object.measurements.length * 3;
bytesCount += 3 + object.pressure.length * 3;
{ {
final value = object.theme; final value = object.theme;
if (value != null) { if (value != null) {
@ -157,6 +178,7 @@ int _settingsEstimateSize(
bytesCount += 3 + value.length * 3; bytesCount += 3 + value.length * 3;
} }
} }
bytesCount += 3 + object.wind.length * 3;
return bytesCount; return bytesCount;
} }
@ -168,20 +190,24 @@ void _settingsSerialize(
) { ) {
writer.writeBool(offsets[0], object.amoledTheme); writer.writeBool(offsets[0], object.amoledTheme);
writer.writeString(offsets[1], object.degrees); writer.writeString(offsets[1], object.degrees);
writer.writeString(offsets[2], object.language); writer.writeBool(offsets[2], object.hideMap);
writer.writeBool(offsets[3], object.location); writer.writeString(offsets[3], object.language);
writer.writeBool(offsets[4], object.materialColor); writer.writeBool(offsets[4], object.largeElement);
writer.writeString(offsets[5], object.measurements); writer.writeBool(offsets[5], object.location);
writer.writeBool(offsets[6], object.notifications); writer.writeBool(offsets[6], object.materialColor);
writer.writeBool(offsets[7], object.onboard); writer.writeString(offsets[7], object.measurements);
writer.writeBool(offsets[8], object.roundDegree); writer.writeBool(offsets[8], object.notifications);
writer.writeString(offsets[9], object.theme); writer.writeBool(offsets[9], object.onboard);
writer.writeString(offsets[10], object.timeEnd); writer.writeString(offsets[10], object.pressure);
writer.writeLong(offsets[11], object.timeRange); writer.writeBool(offsets[11], object.roundDegree);
writer.writeString(offsets[12], object.timeStart); writer.writeString(offsets[12], object.theme);
writer.writeString(offsets[13], object.timeformat); writer.writeString(offsets[13], object.timeEnd);
writer.writeString(offsets[14], object.widgetBackgroundColor); writer.writeLong(offsets[14], object.timeRange);
writer.writeString(offsets[15], object.widgetTextColor); writer.writeString(offsets[15], object.timeStart);
writer.writeString(offsets[16], object.timeformat);
writer.writeString(offsets[17], object.widgetBackgroundColor);
writer.writeString(offsets[18], object.widgetTextColor);
writer.writeString(offsets[19], object.wind);
} }
Settings _settingsDeserialize( Settings _settingsDeserialize(
@ -193,21 +219,25 @@ Settings _settingsDeserialize(
final object = Settings(); final object = Settings();
object.amoledTheme = reader.readBool(offsets[0]); object.amoledTheme = reader.readBool(offsets[0]);
object.degrees = reader.readString(offsets[1]); object.degrees = reader.readString(offsets[1]);
object.hideMap = reader.readBool(offsets[2]);
object.id = id; object.id = id;
object.language = reader.readStringOrNull(offsets[2]); object.language = reader.readStringOrNull(offsets[3]);
object.location = reader.readBool(offsets[3]); object.largeElement = reader.readBool(offsets[4]);
object.materialColor = reader.readBool(offsets[4]); object.location = reader.readBool(offsets[5]);
object.measurements = reader.readString(offsets[5]); object.materialColor = reader.readBool(offsets[6]);
object.notifications = reader.readBool(offsets[6]); object.measurements = reader.readString(offsets[7]);
object.onboard = reader.readBool(offsets[7]); object.notifications = reader.readBool(offsets[8]);
object.roundDegree = reader.readBool(offsets[8]); object.onboard = reader.readBool(offsets[9]);
object.theme = reader.readStringOrNull(offsets[9]); object.pressure = reader.readString(offsets[10]);
object.timeEnd = reader.readStringOrNull(offsets[10]); object.roundDegree = reader.readBool(offsets[11]);
object.timeRange = reader.readLongOrNull(offsets[11]); object.theme = reader.readStringOrNull(offsets[12]);
object.timeStart = reader.readStringOrNull(offsets[12]); object.timeEnd = reader.readStringOrNull(offsets[13]);
object.timeformat = reader.readString(offsets[13]); object.timeRange = reader.readLongOrNull(offsets[14]);
object.widgetBackgroundColor = reader.readStringOrNull(offsets[14]); object.timeStart = reader.readStringOrNull(offsets[15]);
object.widgetTextColor = reader.readStringOrNull(offsets[15]); object.timeformat = reader.readString(offsets[16]);
object.widgetBackgroundColor = reader.readStringOrNull(offsets[17]);
object.widgetTextColor = reader.readStringOrNull(offsets[18]);
object.wind = reader.readString(offsets[19]);
return object; return object;
} }
@ -223,33 +253,41 @@ P _settingsDeserializeProp<P>(
case 1: case 1:
return (reader.readString(offset)) as P; return (reader.readString(offset)) as P;
case 2: case 2:
return (reader.readStringOrNull(offset)) as P;
case 3:
return (reader.readBool(offset)) as P; return (reader.readBool(offset)) as P;
case 3:
return (reader.readStringOrNull(offset)) as P;
case 4: case 4:
return (reader.readBool(offset)) as P; return (reader.readBool(offset)) as P;
case 5: case 5:
return (reader.readString(offset)) as P; return (reader.readBool(offset)) as P;
case 6: case 6:
return (reader.readBool(offset)) as P; return (reader.readBool(offset)) as P;
case 7: case 7:
return (reader.readBool(offset)) as P; return (reader.readString(offset)) as P;
case 8: case 8:
return (reader.readBool(offset)) as P; return (reader.readBool(offset)) as P;
case 9: case 9:
return (reader.readStringOrNull(offset)) as P; return (reader.readBool(offset)) as P;
case 10: case 10:
return (reader.readStringOrNull(offset)) as P; return (reader.readString(offset)) as P;
case 11: case 11:
return (reader.readLongOrNull(offset)) as P; return (reader.readBool(offset)) as P;
case 12: case 12:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 13: case 13:
return (reader.readString(offset)) as P;
case 14:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 14:
return (reader.readLongOrNull(offset)) as P;
case 15: case 15:
return (reader.readStringOrNull(offset)) as P; return (reader.readStringOrNull(offset)) as P;
case 16:
return (reader.readString(offset)) as P;
case 17:
return (reader.readStringOrNull(offset)) as P;
case 18:
return (reader.readStringOrNull(offset)) as P;
case 19:
return (reader.readString(offset)) as P;
default: default:
throw IsarError('Unknown property with id $propertyId'); throw IsarError('Unknown property with id $propertyId');
} }
@ -484,6 +522,16 @@ extension SettingsQueryFilter
}); });
} }
QueryBuilder<Settings, Settings, QAfterFilterCondition> hideMapEqualTo(
bool value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'hideMap',
value: value,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> idEqualTo(Id value) { QueryBuilder<Settings, Settings, QAfterFilterCondition> idEqualTo(Id value) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo( return query.addFilterCondition(FilterCondition.equalTo(
@ -682,6 +730,16 @@ extension SettingsQueryFilter
}); });
} }
QueryBuilder<Settings, Settings, QAfterFilterCondition> largeElementEqualTo(
bool value) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'largeElement',
value: value,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> locationEqualTo( QueryBuilder<Settings, Settings, QAfterFilterCondition> locationEqualTo(
bool value) { bool value) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
@ -856,6 +914,136 @@ extension SettingsQueryFilter
}); });
} }
QueryBuilder<Settings, Settings, QAfterFilterCondition> pressureEqualTo(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'pressure',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> pressureGreaterThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'pressure',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> pressureLessThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'pressure',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> pressureBetween(
String lower,
String upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'pressure',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> pressureStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'pressure',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> pressureEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'pressure',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> pressureContains(
String value,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'pressure',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> pressureMatches(
String pattern,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'pressure',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> pressureIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'pressure',
value: '',
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> pressureIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'pressure',
value: '',
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> roundDegreeEqualTo( QueryBuilder<Settings, Settings, QAfterFilterCondition> roundDegreeEqualTo(
bool value) { bool value) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
@ -1813,6 +2001,136 @@ extension SettingsQueryFilter
)); ));
}); });
} }
QueryBuilder<Settings, Settings, QAfterFilterCondition> windEqualTo(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'wind',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> windGreaterThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
include: include,
property: r'wind',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> windLessThan(
String value, {
bool include = false,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.lessThan(
include: include,
property: r'wind',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> windBetween(
String lower,
String upper, {
bool includeLower = true,
bool includeUpper = true,
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.between(
property: r'wind',
lower: lower,
includeLower: includeLower,
upper: upper,
includeUpper: includeUpper,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> windStartsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.startsWith(
property: r'wind',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> windEndsWith(
String value, {
bool caseSensitive = true,
}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.endsWith(
property: r'wind',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> windContains(
String value,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.contains(
property: r'wind',
value: value,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> windMatches(
String pattern,
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.matches(
property: r'wind',
wildcard: pattern,
caseSensitive: caseSensitive,
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> windIsEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.equalTo(
property: r'wind',
value: '',
));
});
}
QueryBuilder<Settings, Settings, QAfterFilterCondition> windIsNotEmpty() {
return QueryBuilder.apply(this, (query) {
return query.addFilterCondition(FilterCondition.greaterThan(
property: r'wind',
value: '',
));
});
}
} }
extension SettingsQueryObject extension SettingsQueryObject
@ -1846,6 +2164,18 @@ extension SettingsQuerySortBy on QueryBuilder<Settings, Settings, QSortBy> {
}); });
} }
QueryBuilder<Settings, Settings, QAfterSortBy> sortByHideMap() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'hideMap', Sort.asc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByHideMapDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'hideMap', Sort.desc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByLanguage() { QueryBuilder<Settings, Settings, QAfterSortBy> sortByLanguage() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'language', Sort.asc); return query.addSortBy(r'language', Sort.asc);
@ -1858,6 +2188,18 @@ extension SettingsQuerySortBy on QueryBuilder<Settings, Settings, QSortBy> {
}); });
} }
QueryBuilder<Settings, Settings, QAfterSortBy> sortByLargeElement() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'largeElement', Sort.asc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByLargeElementDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'largeElement', Sort.desc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByLocation() { QueryBuilder<Settings, Settings, QAfterSortBy> sortByLocation() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'location', Sort.asc); return query.addSortBy(r'location', Sort.asc);
@ -1918,6 +2260,18 @@ extension SettingsQuerySortBy on QueryBuilder<Settings, Settings, QSortBy> {
}); });
} }
QueryBuilder<Settings, Settings, QAfterSortBy> sortByPressure() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'pressure', Sort.asc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByPressureDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'pressure', Sort.desc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByRoundDegree() { QueryBuilder<Settings, Settings, QAfterSortBy> sortByRoundDegree() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'roundDegree', Sort.asc); return query.addSortBy(r'roundDegree', Sort.asc);
@ -2014,6 +2368,18 @@ extension SettingsQuerySortBy on QueryBuilder<Settings, Settings, QSortBy> {
return query.addSortBy(r'widgetTextColor', Sort.desc); return query.addSortBy(r'widgetTextColor', Sort.desc);
}); });
} }
QueryBuilder<Settings, Settings, QAfterSortBy> sortByWind() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'wind', Sort.asc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> sortByWindDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'wind', Sort.desc);
});
}
} }
extension SettingsQuerySortThenBy extension SettingsQuerySortThenBy
@ -2042,6 +2408,18 @@ extension SettingsQuerySortThenBy
}); });
} }
QueryBuilder<Settings, Settings, QAfterSortBy> thenByHideMap() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'hideMap', Sort.asc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenByHideMapDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'hideMap', Sort.desc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenById() { QueryBuilder<Settings, Settings, QAfterSortBy> thenById() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'id', Sort.asc); return query.addSortBy(r'id', Sort.asc);
@ -2066,6 +2444,18 @@ extension SettingsQuerySortThenBy
}); });
} }
QueryBuilder<Settings, Settings, QAfterSortBy> thenByLargeElement() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'largeElement', Sort.asc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenByLargeElementDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'largeElement', Sort.desc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenByLocation() { QueryBuilder<Settings, Settings, QAfterSortBy> thenByLocation() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'location', Sort.asc); return query.addSortBy(r'location', Sort.asc);
@ -2126,6 +2516,18 @@ extension SettingsQuerySortThenBy
}); });
} }
QueryBuilder<Settings, Settings, QAfterSortBy> thenByPressure() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'pressure', Sort.asc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenByPressureDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'pressure', Sort.desc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenByRoundDegree() { QueryBuilder<Settings, Settings, QAfterSortBy> thenByRoundDegree() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'roundDegree', Sort.asc); return query.addSortBy(r'roundDegree', Sort.asc);
@ -2222,6 +2624,18 @@ extension SettingsQuerySortThenBy
return query.addSortBy(r'widgetTextColor', Sort.desc); return query.addSortBy(r'widgetTextColor', Sort.desc);
}); });
} }
QueryBuilder<Settings, Settings, QAfterSortBy> thenByWind() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'wind', Sort.asc);
});
}
QueryBuilder<Settings, Settings, QAfterSortBy> thenByWindDesc() {
return QueryBuilder.apply(this, (query) {
return query.addSortBy(r'wind', Sort.desc);
});
}
} }
extension SettingsQueryWhereDistinct extension SettingsQueryWhereDistinct
@ -2239,6 +2653,12 @@ extension SettingsQueryWhereDistinct
}); });
} }
QueryBuilder<Settings, Settings, QDistinct> distinctByHideMap() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'hideMap');
});
}
QueryBuilder<Settings, Settings, QDistinct> distinctByLanguage( QueryBuilder<Settings, Settings, QDistinct> distinctByLanguage(
{bool caseSensitive = true}) { {bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
@ -2246,6 +2666,12 @@ extension SettingsQueryWhereDistinct
}); });
} }
QueryBuilder<Settings, Settings, QDistinct> distinctByLargeElement() {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'largeElement');
});
}
QueryBuilder<Settings, Settings, QDistinct> distinctByLocation() { QueryBuilder<Settings, Settings, QDistinct> distinctByLocation() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'location'); return query.addDistinctBy(r'location');
@ -2277,6 +2703,13 @@ extension SettingsQueryWhereDistinct
}); });
} }
QueryBuilder<Settings, Settings, QDistinct> distinctByPressure(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'pressure', caseSensitive: caseSensitive);
});
}
QueryBuilder<Settings, Settings, QDistinct> distinctByRoundDegree() { QueryBuilder<Settings, Settings, QDistinct> distinctByRoundDegree() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'roundDegree'); return query.addDistinctBy(r'roundDegree');
@ -2332,6 +2765,13 @@ extension SettingsQueryWhereDistinct
caseSensitive: caseSensitive); caseSensitive: caseSensitive);
}); });
} }
QueryBuilder<Settings, Settings, QDistinct> distinctByWind(
{bool caseSensitive = true}) {
return QueryBuilder.apply(this, (query) {
return query.addDistinctBy(r'wind', caseSensitive: caseSensitive);
});
}
} }
extension SettingsQueryProperty extension SettingsQueryProperty
@ -2354,12 +2794,24 @@ extension SettingsQueryProperty
}); });
} }
QueryBuilder<Settings, bool, QQueryOperations> hideMapProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'hideMap');
});
}
QueryBuilder<Settings, String?, QQueryOperations> languageProperty() { QueryBuilder<Settings, String?, QQueryOperations> languageProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'language'); return query.addPropertyName(r'language');
}); });
} }
QueryBuilder<Settings, bool, QQueryOperations> largeElementProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'largeElement');
});
}
QueryBuilder<Settings, bool, QQueryOperations> locationProperty() { QueryBuilder<Settings, bool, QQueryOperations> locationProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'location'); return query.addPropertyName(r'location');
@ -2390,6 +2842,12 @@ extension SettingsQueryProperty
}); });
} }
QueryBuilder<Settings, String, QQueryOperations> pressureProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'pressure');
});
}
QueryBuilder<Settings, bool, QQueryOperations> roundDegreeProperty() { QueryBuilder<Settings, bool, QQueryOperations> roundDegreeProperty() {
return QueryBuilder.apply(this, (query) { return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'roundDegree'); return query.addPropertyName(r'roundDegree');
@ -2438,6 +2896,12 @@ extension SettingsQueryProperty
return query.addPropertyName(r'widgetTextColor'); return query.addPropertyName(r'widgetTextColor');
}); });
} }
QueryBuilder<Settings, String, QQueryOperations> windProperty() {
return QueryBuilder.apply(this, (query) {
return query.addPropertyName(r'wind');
});
}
} }
// coverage:ignore-file // coverage:ignore-file
@ -2638,7 +3102,7 @@ const MainWeatherCacheSchema = CollectionSchema(
getId: _mainWeatherCacheGetId, getId: _mainWeatherCacheGetId,
getLinks: _mainWeatherCacheGetLinks, getLinks: _mainWeatherCacheGetLinks,
attach: _mainWeatherCacheAttach, attach: _mainWeatherCacheAttach,
version: '3.1.7', version: '3.1.8',
); );
int _mainWeatherCacheEstimateSize( int _mainWeatherCacheEstimateSize(
@ -10361,7 +10825,7 @@ const LocationCacheSchema = CollectionSchema(
getId: _locationCacheGetId, getId: _locationCacheGetId,
getLinks: _locationCacheGetLinks, getLinks: _locationCacheGetLinks,
attach: _locationCacheAttach, attach: _locationCacheAttach,
version: '3.1.7', version: '3.1.8',
); );
int _locationCacheEstimateSize( int _locationCacheEstimateSize(
@ -11460,7 +11924,7 @@ const WeatherCardSchema = CollectionSchema(
getId: _weatherCardGetId, getId: _weatherCardGetId,
getLinks: _weatherCardGetLinks, getLinks: _weatherCardGetLinks,
attach: _weatherCardAttach, attach: _weatherCardAttach,
version: '3.1.7', version: '3.1.8',
); );
int _weatherCardEstimateSize( int _weatherCardEstimateSize(

View file

@ -1,191 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax/iconsax.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/data/weather.dart';
import 'package:rain/app/widgets/daily/weather_daily.dart';
import 'package:rain/app/widgets/daily/weather_more.dart';
import 'package:rain/app/widgets/desc/desc_container.dart';
import 'package:rain/app/widgets/hourly/weather_hourly.dart';
import 'package:rain/app/widgets/now/weather_now.dart';
import 'package:rain/app/widgets/sun_moon/sunset_sunrise.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
class InfoWeatherCard extends StatefulWidget {
const InfoWeatherCard({
super.key,
required this.weatherCard,
});
final WeatherCard weatherCard;
@override
State<InfoWeatherCard> createState() => _InfoWeatherCardState();
}
class _InfoWeatherCardState extends State<InfoWeatherCard> {
int timeNow = 0;
int dayNow = 0;
final weatherController = Get.put(WeatherController());
final itemScrollController = ItemScrollController();
@override
void initState() {
getTime();
super.initState();
}
void getTime() {
final weatherCard = widget.weatherCard;
timeNow =
weatherController.getTime(weatherCard.time!, weatherCard.timezone!);
dayNow =
weatherController.getDay(weatherCard.timeDaily!, weatherCard.timezone!);
Future.delayed(const Duration(milliseconds: 30), () {
itemScrollController.scrollTo(
index: timeNow,
duration: const Duration(seconds: 2),
curve: Curves.easeInOutCubic,
);
});
}
@override
Widget build(BuildContext context) {
final weatherCard = widget.weatherCard;
return RefreshIndicator(
onRefresh: () async {
await weatherController.updateCard(weatherCard);
getTime();
setState(() {});
},
child: Scaffold(
appBar: AppBar(
centerTitle: true,
automaticallyImplyLeading: false,
leading: IconButton(
onPressed: () => Get.back(),
icon: const Icon(
Iconsax.arrow_left_1,
size: 20,
),
),
title: Text(
weatherCard.district!.isNotEmpty
? '${weatherCard.city}'
', ${weatherCard.district}'
: '${weatherCard.city}',
style: context.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: ListView(
children: [
WeatherNow(
time: weatherCard.time![timeNow],
weather: weatherCard.weathercode![timeNow],
degree: weatherCard.temperature2M![timeNow],
timeDay: weatherCard.sunrise![dayNow],
timeNight: weatherCard.sunset![dayNow],
tempMax: weatherCard.temperature2MMax![dayNow]!,
tempMin: weatherCard.temperature2MMin![dayNow]!,
),
Card(
margin: const EdgeInsets.only(bottom: 15),
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: SizedBox(
height: 135,
child: ScrollablePositionedList.separated(
key: const PageStorageKey(1),
separatorBuilder: (BuildContext context, int index) {
return const VerticalDivider(
width: 10,
indent: 40,
endIndent: 40,
);
},
scrollDirection: Axis.horizontal,
itemScrollController: itemScrollController,
itemCount: weatherCard.time!.length,
itemBuilder: (ctx, i) => GestureDetector(
onTap: () {
timeNow = i;
dayNow = (i / 24).floor();
setState(() {});
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 5),
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 5,
),
decoration: BoxDecoration(
color: i == timeNow
? context.theme.colorScheme.secondaryContainer
: Colors.transparent,
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
),
child: WeatherHourly(
time: weatherCard.time![i],
weather: weatherCard.weathercode![i],
degree: weatherCard.temperature2M![i],
timeDay: weatherCard.sunrise![(i / 24).floor()],
timeNight: weatherCard.sunset![(i / 24).floor()],
),
),
),
),
),
),
),
SunsetSunrise(
timeSunrise: weatherCard.sunrise![dayNow],
timeSunset: weatherCard.sunset![dayNow],
),
DescContainer(
humidity: weatherCard.relativehumidity2M?[timeNow],
wind: weatherCard.windspeed10M?[timeNow],
visibility: weatherCard.visibility?[timeNow],
feels: weatherCard.apparentTemperature?[timeNow],
evaporation: weatherCard.evapotranspiration?[timeNow],
precipitation: weatherCard.precipitation?[timeNow],
direction: weatherCard.winddirection10M?[timeNow],
pressure: weatherCard.surfacePressure?[timeNow],
rain: weatherCard.rain?[timeNow],
cloudcover: weatherCard.cloudcover?[timeNow],
windgusts: weatherCard.windgusts10M?[timeNow],
uvIndex: weatherCard.uvIndex?[timeNow],
dewpoint2M: weatherCard.dewpoint2M?[timeNow],
precipitationProbability:
weatherCard.precipitationProbability?[timeNow],
shortwaveRadiation: weatherCard.shortwaveRadiation?[timeNow],
initiallyExpanded: false,
title: 'hourlyVariables'.tr,
),
WeatherDaily(
weatherData: weatherCard,
onTap: () => Get.to(
() => WeatherMore(
weatherData: weatherCard,
),
transition: Transition.downToUp,
),
),
],
),
),
),
),
);
}
}

View file

@ -1,103 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax/iconsax.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/modules/cards/widgets/weather_card_list.dart';
import 'package:rain/app/widgets/text_form.dart';
class ListWeatherCard extends StatefulWidget {
const ListWeatherCard({super.key});
@override
State<ListWeatherCard> createState() => _ListWeatherCardState();
}
class _ListWeatherCardState extends State<ListWeatherCard> {
final weatherController = Get.put(WeatherController());
TextEditingController searchTasks = TextEditingController();
String filter = '';
applyFilter(String value) async {
filter = value.toLowerCase();
setState(() {});
}
@override
void initState() {
super.initState();
applyFilter('');
}
@override
Widget build(BuildContext context) {
final textTheme = context.textTheme;
final titleMedium = textTheme.titleMedium;
return Obx(
() => weatherController.weatherCards.isEmpty
? Center(
child: SingleChildScrollView(
child: Column(
children: [
Image.asset(
'assets/icons/City.png',
scale: 6,
),
SizedBox(
width: Get.size.width * 0.8,
child: Text(
'noWeatherCard'.tr,
textAlign: TextAlign.center,
style: titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
),
],
),
),
)
: NestedScrollView(
physics: const NeverScrollableScrollPhysics(),
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
SliverToBoxAdapter(
child: MyTextForm(
labelText: 'search'.tr,
type: TextInputType.text,
icon: const Icon(
Iconsax.search_normal_1,
size: 20,
),
controller: searchTasks,
margin: const EdgeInsets.symmetric(
horizontal: 10, vertical: 5),
onChanged: applyFilter,
iconButton: searchTasks.text.isNotEmpty
? IconButton(
onPressed: () {
searchTasks.clear();
applyFilter('');
},
icon: const Icon(
Iconsax.close_circle,
color: Colors.grey,
size: 20,
),
)
: null,
),
),
];
},
body: RefreshIndicator(
onRefresh: () async {
await weatherController.updateCacheCard(true);
setState(() {});
},
child: WeatherCardList(searchCity: filter),
),
),
);
}
}

View file

@ -1,251 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax/iconsax.dart';
import 'package:rain/app/api/api.dart';
import 'package:rain/app/api/city.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/widgets/text_form.dart';
import 'package:rain/main.dart';
class CreateWeatherCard extends StatefulWidget {
const CreateWeatherCard({super.key});
@override
State<CreateWeatherCard> createState() => _CreateWeatherCardState();
}
class _CreateWeatherCardState extends State<CreateWeatherCard> {
bool isLoading = false;
final formKey = GlobalKey<FormState>();
final _focusNode = FocusNode();
final weatherController = Get.put(WeatherController());
final _controller = TextEditingController();
final _controllerLat = TextEditingController();
final _controllerLon = TextEditingController();
final _controllerCity = TextEditingController();
final _controllerDistrict = TextEditingController();
textTrim(value) {
value.text = value.text.trim();
while (value.text.contains(' ')) {
value.text = value.text.replaceAll(' ', ' ');
}
}
void fillController(selection) {
_controllerLat.text = '${selection.latitude}';
_controllerLon.text = '${selection.longitude}';
_controllerCity.text = selection.name;
_controllerDistrict.text = selection.admin1;
_controller.clear();
_focusNode.unfocus();
setState(() {});
}
@override
Widget build(BuildContext context) {
const kTextFieldElevation = 4.0;
return Form(
key: formKey,
child: SingleChildScrollView(
child: Stack(
children: [
Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
onPressed: () {
Get.back();
},
icon: const Icon(
Iconsax.close_square,
size: 18,
),
),
Text(
'create'.tr,
style: context.textTheme.titleLarge?.copyWith(
fontSize: 20,
),
textAlign: TextAlign.center,
),
IconButton(
onPressed: () async {
if (formKey.currentState!.validate()) {
textTrim(_controllerLat);
textTrim(_controllerLon);
textTrim(_controllerCity);
textTrim(_controllerDistrict);
setState(() => isLoading = true);
await weatherController.addCardWeather(
double.parse(_controllerLat.text),
double.parse(_controllerLon.text),
_controllerCity.text,
_controllerDistrict.text,
);
setState(() => isLoading = false);
Get.back();
}
},
icon: const Icon(
Iconsax.tick_square,
size: 18,
),
),
],
),
),
RawAutocomplete<Result>(
focusNode: _focusNode,
textEditingController: _controller,
fieldViewBuilder: (BuildContext context,
TextEditingController fieldTextEditingController,
FocusNode fieldFocusNode,
VoidCallback onFieldSubmitted) {
return MyTextForm(
elevation: kTextFieldElevation,
labelText: 'search'.tr,
type: TextInputType.text,
icon: const Icon(Iconsax.global_search),
controller: _controller,
margin:
const EdgeInsets.only(left: 10, right: 10, top: 10),
focusNode: _focusNode,
);
},
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text.isEmpty) {
return const Iterable<Result>.empty();
}
return WeatherAPI()
.getCity(textEditingValue.text, locale);
},
onSelected: (Result selection) => fillController(selection),
displayStringForOption: (Result option) =>
'${option.name}, ${option.admin1}',
optionsViewBuilder: (BuildContext context,
AutocompleteOnSelected<Result> onSelected,
Iterable<Result> options) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Align(
alignment: Alignment.topCenter,
child: Material(
borderRadius: BorderRadius.circular(20),
elevation: 4.0,
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final Result option = options.elementAt(index);
return InkWell(
onTap: () => onSelected(option),
child: ListTile(
title: Text(
'${option.name}, ${option.admin1}',
style: context.textTheme.labelLarge,
),
),
);
},
),
),
),
);
},
),
MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerLat,
labelText: 'lat'.tr,
type: TextInputType.number,
icon: const Icon(Iconsax.location),
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
validator: (value) {
if (value == null || value.isEmpty) {
return 'validateValue'.tr;
}
double? numericValue = double.tryParse(value);
if (numericValue == null) {
return 'validateNumber'.tr;
}
if (numericValue < -90 || numericValue > 90) {
return 'validate90'.tr;
}
return null;
},
),
MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerLon,
labelText: 'lon'.tr,
type: TextInputType.number,
icon: const Icon(Iconsax.location),
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
validator: (value) {
if (value == null || value.isEmpty) {
return 'validateValue'.tr;
}
double? numericValue = double.tryParse(value);
if (numericValue == null) {
return 'validateNumber'.tr;
}
if (numericValue < -180 || numericValue > 180) {
return 'validate180'.tr;
}
return null;
},
),
MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerCity,
labelText: 'city'.tr,
type: TextInputType.name,
icon: const Icon(Icons.location_city_rounded),
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
validator: (value) {
if (value == null || value.isEmpty) {
return 'validateName'.tr;
}
return null;
},
),
MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerDistrict,
labelText: 'district'.tr,
type: TextInputType.streetAddress,
icon: const Icon(Iconsax.global),
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
validator: (value) {
if (value == null || value.isEmpty) {
return 'validateName'.tr;
}
return null;
},
),
const SizedBox(height: 20),
],
),
),
if (isLoading)
const Center(
child: CircularProgressIndicator(),
),
],
),
),
);
}
}

View file

@ -1,124 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/widgets/status/status_weather.dart';
import 'package:rain/app/widgets/status/status_data.dart';
import 'package:timezone/standalone.dart' as tz;
class WeatherCardContainer extends StatefulWidget {
const WeatherCardContainer({
super.key,
required this.time,
required this.weather,
required this.degree,
required this.district,
required this.city,
required this.timezone,
required this.timeDay,
required this.timeNight,
required this.timeDaily,
});
final List<String> time;
final List<String> timeDay;
final List<String> timeNight;
final List<DateTime> timeDaily;
final String district;
final String city;
final List<int> weather;
final List<double> degree;
final String timezone;
@override
State<WeatherCardContainer> createState() => _WeatherCardContainerState();
}
class _WeatherCardContainerState extends State<WeatherCardContainer> {
final statusWeather = StatusWeather();
final statusData = StatusData();
final weatherController = Get.put(WeatherController());
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 20),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
statusData.getDegree(widget.degree[weatherController
.getTime(widget.time, widget.timezone)]
.round()
.toInt()),
style: context.textTheme.titleLarge?.copyWith(
fontSize: 22,
fontWeight: FontWeight.w600,
),
),
const SizedBox(width: 7),
Text(
statusWeather.getText(widget.weather[weatherController
.getTime(widget.time, widget.timezone)]),
style: context.textTheme.titleMedium?.copyWith(
color: Colors.grey,
fontWeight: FontWeight.w400,
),
),
],
),
const SizedBox(height: 10),
Text(
widget.district.isEmpty
? widget.city
: widget.city.isEmpty
? widget.district
: widget.city == widget.district
? widget.city
: '${widget.city}'
', ${widget.district}',
style: context.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 5),
StreamBuilder(
stream: Stream.periodic(const Duration(seconds: 1)),
builder: (context, snapshot) {
return Text(
'${'time'.tr}: ${statusData.getTimeFormatTz(tz.TZDateTime.now(tz.getLocation(widget.timezone)))}',
style: context.textTheme.titleMedium?.copyWith(
color: Colors.grey,
fontWeight: FontWeight.w400,
),
);
},
),
],
),
),
const SizedBox(width: 5),
Image.asset(
statusWeather.getImageNow(
widget.weather[
weatherController.getTime(widget.time, widget.timezone)],
widget.time[
weatherController.getTime(widget.time, widget.timezone)],
widget.timeDay[weatherController.getDay(
widget.timeDaily, widget.timezone)],
widget.timeNight[weatherController.getDay(
widget.timeDaily, widget.timezone)]),
scale: 6.5,
),
],
),
),
);
}
}

View file

@ -1,115 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax/iconsax.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/modules/cards/view/info_weather_card.dart';
import 'package:rain/app/modules/cards/widgets/weather_card_container.dart';
class WeatherCardList extends StatefulWidget {
const WeatherCardList({
super.key,
required this.searchCity,
});
final String searchCity;
@override
State<WeatherCardList> createState() => _WeatherCardListState();
}
class _WeatherCardListState extends State<WeatherCardList> {
final weatherController = Get.put(WeatherController());
@override
Widget build(BuildContext context) {
final textTheme = context.textTheme;
final titleMedium = textTheme.titleMedium;
var weatherCards = weatherController.weatherCards
.where((weatherCard) => (widget.searchCity.isEmpty ||
weatherCard.city!.toLowerCase().contains(widget.searchCity)))
.toList()
.obs;
return ReorderableListView(
onReorder: (oldIndex, newIndex) =>
weatherController.reorder(oldIndex, newIndex),
children: [
...weatherCards.map(
(weatherCardList) => Dismissible(
key: ValueKey(weatherCardList),
direction: DismissDirection.endToStart,
background: Container(
alignment: Alignment.centerRight,
child: const Padding(
padding: EdgeInsets.only(right: 15),
child: Icon(
Iconsax.trush_square,
color: Colors.red,
),
),
),
confirmDismiss: (DismissDirection direction) async {
return await showAdaptiveDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog.adaptive(
title: Text(
'deletedCardWeather'.tr,
style: textTheme.titleLarge,
),
content: Text(
'deletedCardWeatherQuery'.tr,
style: titleMedium,
),
actions: [
TextButton(
onPressed: () => Get.back(result: false),
child: Text(
'cancel'.tr,
style: titleMedium?.copyWith(
color: Colors.blueAccent,
),
),
),
TextButton(
onPressed: () => Get.back(result: true),
child: Text(
'delete'.tr,
style: titleMedium?.copyWith(
color: Colors.red,
),
),
),
],
);
},
);
},
onDismissed: (DismissDirection direction) async {
await weatherController.deleteCardWeather(weatherCardList);
},
child: GestureDetector(
onTap: () => Get.to(
() => InfoWeatherCard(
weatherCard: weatherCardList,
),
transition: Transition.downToUp,
),
child: WeatherCardContainer(
time: weatherCardList.time!,
timeDaily: weatherCardList.timeDaily!,
timeDay: weatherCardList.sunrise!,
timeNight: weatherCardList.sunset!,
weather: weatherCardList.weathercode!,
degree: weatherCardList.temperature2M!,
district: weatherCardList.district!,
city: weatherCardList.city!,
timezone: weatherCardList.timezone!,
),
),
),
),
],
);
}
}

View file

@ -1,416 +0,0 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:iconsax/iconsax.dart';
import 'package:rain/app/api/api.dart';
import 'package:rain/app/api/city.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/modules/home.dart';
import 'package:rain/app/widgets/button.dart';
import 'package:rain/app/widgets/text_form.dart';
import 'package:rain/main.dart';
class SelectGeolocation extends StatefulWidget {
const SelectGeolocation({
super.key,
required this.isStart,
});
final bool isStart;
@override
State<SelectGeolocation> createState() => _SelectGeolocationState();
}
class _SelectGeolocationState extends State<SelectGeolocation> {
bool isLoading = false;
final formKeySearch = GlobalKey<FormState>();
final _focusNode = FocusNode();
final weatherController = Get.put(WeatherController());
final _controller = TextEditingController();
final _controllerLat = TextEditingController();
final _controllerLon = TextEditingController();
final _controllerCity = TextEditingController();
final _controllerDistrict = TextEditingController();
textTrim(value) {
value.text = value.text.trim();
while (value.text.contains(' ')) {
value.text = value.text.replaceAll(' ', ' ');
}
}
void fillController(selection) {
_controllerLat.text = '${selection.latitude}';
_controllerLon.text = '${selection.longitude}';
_controllerCity.text = selection.name;
_controllerDistrict.text = selection.admin1;
_controller.clear();
_focusNode.unfocus();
setState(() {});
}
void fillControllerGeo(location) {
_controllerLat.text = '${location['lat']}';
_controllerLon.text = '${location['lon']}';
_controllerCity.text = location['district'];
_controllerDistrict.text = location['city'];
setState(() {});
}
@override
Widget build(BuildContext context) {
const kTextFieldElevation = 4.0;
return Form(
key: formKeySearch,
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
centerTitle: true,
leading: widget.isStart
? null
: IconButton(
onPressed: () {
Get.back();
},
icon: const Icon(
Iconsax.arrow_left_1,
size: 20,
),
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
automaticallyImplyLeading: false,
title: Text(
'searchCity'.tr,
style: context.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
),
body: SafeArea(
child: Stack(
children: [
Column(
children: [
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Flexible(
child: SingleChildScrollView(
child: Column(
children: [
Image.asset(
'assets/icons/Search.png',
scale: 7,
),
Padding(
padding: const EdgeInsets.symmetric(
vertical: 5, horizontal: 10),
child: Text(
'searchMethod'.tr,
style: context.theme.textTheme.bodyLarge
?.copyWith(fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
Row(
children: [
Flexible(
child: RawAutocomplete<Result>(
focusNode: _focusNode,
textEditingController: _controller,
fieldViewBuilder: (BuildContext context,
TextEditingController
fieldTextEditingController,
FocusNode fieldFocusNode,
VoidCallback onFieldSubmitted) {
return MyTextForm(
elevation: kTextFieldElevation,
labelText: 'search'.tr,
type: TextInputType.text,
icon: const Icon(
Iconsax.global_search),
controller: _controller,
margin: const EdgeInsets.only(
left: 10, right: 10, top: 10),
focusNode: _focusNode,
);
},
optionsBuilder: (TextEditingValue
textEditingValue) {
if (textEditingValue.text.isEmpty) {
return const Iterable<
Result>.empty();
}
return WeatherAPI().getCity(
textEditingValue.text, locale);
},
onSelected: (Result selection) =>
fillController(selection),
displayStringForOption: (Result
option) =>
'${option.name}, ${option.admin1}',
optionsViewBuilder:
(BuildContext context,
AutocompleteOnSelected<Result>
onSelected,
Iterable<Result> options) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
),
child: Align(
alignment: Alignment.topCenter,
child: Material(
borderRadius:
BorderRadius.circular(20),
elevation: 4.0,
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: options.length,
itemBuilder:
(BuildContext context,
int index) {
final Result option =
options
.elementAt(index);
return InkWell(
onTap: () =>
onSelected(option),
child: ListTile(
title: Text(
'${option.name}, ${option.admin1}',
style: context
.textTheme
.labelLarge,
),
),
);
},
),
),
),
);
},
),
),
Card(
elevation: kTextFieldElevation,
margin: const EdgeInsets.only(
top: 10,
right: 10,
),
child: Container(
margin: const EdgeInsets.all(2.5),
child: IconButton(
onPressed: () async {
bool serviceEnabled =
await Geolocator
.isLocationServiceEnabled();
if (!serviceEnabled) {
if (!context.mounted) return;
await showAdaptiveDialog(
context: context,
builder:
(BuildContext context) {
return AlertDialog.adaptive(
title: Text(
'location'.tr,
style: context
.textTheme.titleLarge,
),
content: Text(
'no_location'.tr,
style: context.textTheme
.titleMedium,
),
actions: [
TextButton(
onPressed: () =>
Get.back(
result: false),
child: Text(
'cancel'.tr,
style: context
.textTheme
.titleMedium
?.copyWith(
color: Colors
.blueAccent,
),
),
),
TextButton(
onPressed: () {
Geolocator
.openLocationSettings();
Get.back(
result: true);
},
child: Text(
'settings'.tr,
style: context
.textTheme
.titleMedium
?.copyWith(
color: Colors
.green),
),
),
],
);
},
);
return;
}
setState(() => isLoading = true);
final location =
await weatherController
.getCurrentLocationSearch();
fillControllerGeo(location);
setState(() => isLoading = false);
},
icon: const Icon(
Iconsax.location,
),
),
),
),
],
),
MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerLat,
labelText: 'lat'.tr,
type: TextInputType.number,
icon: const Icon(Iconsax.location),
margin: const EdgeInsets.only(
left: 10,
right: 10,
top: 10,
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'validateValue'.tr;
}
double? numericValue =
double.tryParse(value);
if (numericValue == null) {
return 'validateNumber'.tr;
}
if (numericValue < -90 ||
numericValue > 90) {
return 'validate90'.tr;
}
return null;
},
),
MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerLon,
labelText: 'lon'.tr,
type: TextInputType.number,
icon: const Icon(Iconsax.location),
margin: const EdgeInsets.only(
left: 10,
right: 10,
top: 10,
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'validateValue'.tr;
}
double? numericValue =
double.tryParse(value);
if (numericValue == null) {
return 'validateNumber'.tr;
}
if (numericValue < -180 ||
numericValue > 180) {
return 'validate180'.tr;
}
return null;
},
),
MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerCity,
labelText: 'city'.tr,
type: TextInputType.name,
icon: const Icon(Icons.location_city_rounded),
margin: const EdgeInsets.only(
left: 10, right: 10, top: 10),
validator: (value) {
if (value == null || value.isEmpty) {
return 'validateName'.tr;
}
return null;
},
),
MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerDistrict,
labelText: 'district'.tr,
type: TextInputType.streetAddress,
icon: const Icon(Iconsax.global),
margin: const EdgeInsets.only(
left: 10, right: 10, top: 10),
),
const SizedBox(height: 20),
],
),
),
),
],
),
),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: MyTextButton(
buttonName: 'done'.tr,
onPressed: () async {
if (formKeySearch.currentState!.validate()) {
textTrim(_controllerLat);
textTrim(_controllerLon);
textTrim(_controllerCity);
textTrim(_controllerDistrict);
try {
await weatherController.deleteAll(true);
await weatherController.getLocation(
double.parse(_controllerLat.text),
double.parse(_controllerLon.text),
_controllerDistrict.text,
_controllerCity.text,
);
widget.isStart
? Get.off(() => const HomePage(),
transition: Transition.downToUp)
: Get.back();
} catch (error) {
Future.error(error);
}
}
},
),
),
],
),
if (isLoading)
BackdropFilter(
filter: ImageFilter.blur(sigmaY: 3, sigmaX: 3),
child: const Center(
child: CircularProgressIndicator(),
),
),
],
),
),
),
);
}
}

View file

@ -1,277 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax/iconsax.dart';
import 'package:isar/isar.dart';
import 'package:rain/app/api/api.dart';
import 'package:rain/app/api/city.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/data/weather.dart';
import 'package:rain/app/modules/cards/view/list_weather_card.dart';
import 'package:rain/app/modules/cards/widgets/create_card_weather.dart';
import 'package:rain/app/modules/geolocation.dart';
import 'package:rain/app/modules/main/view/weather.dart';
import 'package:rain/app/modules/settings/view/settings.dart';
import 'package:rain/app/services/utils.dart';
import 'package:rain/main.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
int tabIndex = 0;
bool visible = false;
final _focusNode = FocusNode();
late TabController tabController;
final weatherController = Get.put(WeatherController());
final _controller = TextEditingController();
final pages = [
const WeatherPage(),
const ListWeatherCard(),
const SettingsPage(),
];
@override
void initState() {
getData();
tabController = TabController(
initialIndex: tabIndex,
length: pages.length,
vsync: this,
);
tabController.animation?.addListener(() {
int value = (tabController.animation!.value).round();
if (value != tabIndex) setState(() => tabIndex = value);
});
tabController.addListener(() {
setState(() {
tabIndex = tabController.index;
});
});
super.initState();
}
void getData() async {
await weatherController.deleteCache();
await weatherController.updateCacheCard(false);
await weatherController.setLocation();
}
void changeTabIndex(int index) {
setState(() {
tabIndex = index;
});
tabController.animateTo(tabIndex);
}
@override
Widget build(BuildContext context) {
final textTheme = context.textTheme;
final labelLarge = textTheme.labelLarge;
return DefaultTabController(
length: pages.length,
child: ScaffoldMessenger(
key: globalKey,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
automaticallyImplyLeading: false,
leading: switch (tabIndex) {
0 => IconButton(
onPressed: () {
Get.to(() => const SelectGeolocation(isStart: false),
transition: Transition.downToUp);
},
icon: const Icon(
Iconsax.global_search,
size: 18,
),
),
int() => null,
},
title: switch (tabIndex) {
0 => visible
? RawAutocomplete<Result>(
focusNode: _focusNode,
textEditingController: _controller,
fieldViewBuilder: (_, __, ___, ____) {
return TextField(
controller: _controller,
focusNode: _focusNode,
style: labelLarge?.copyWith(fontSize: 16),
decoration: InputDecoration(
hintText: 'search'.tr,
),
);
},
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text.isEmpty) {
return const Iterable<Result>.empty();
}
return WeatherAPI()
.getCity(textEditingValue.text, locale);
},
onSelected: (Result selection) async {
await weatherController.deleteAll(true);
await weatherController.getLocation(
double.parse('${selection.latitude}'),
double.parse('${selection.longitude}'),
selection.admin1,
selection.name,
);
visible = false;
_controller.clear();
_focusNode.unfocus();
setState(() {});
},
displayStringForOption: (Result option) =>
'${option.name}, ${option.admin1}',
optionsViewBuilder: (BuildContext context,
AutocompleteOnSelected<Result> onSelected,
Iterable<Result> options) {
return Align(
alignment: Alignment.topLeft,
child: Material(
borderRadius: BorderRadius.circular(20),
elevation: 4.0,
child: SizedBox(
width: 250,
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final Result option =
options.elementAt(index);
return InkWell(
onTap: () => onSelected(option),
child: ListTile(
title: Text(
'${option.name}, ${option.admin1}',
style: labelLarge,
),
),
);
},
),
),
),
);
},
)
: Obx(
() {
final location = weatherController.location;
final city = location.city;
final district = location.district;
return Text(
weatherController.isLoading.isFalse
? district!.isEmpty
? '$city'
: city!.isEmpty
? district
: city == district
? city
: '$city' ', $district'
: settings.location
? 'search'.tr
: (isar.locationCaches.where().findAllSync())
.isNotEmpty
? 'loading'.tr
: 'searchCity'.tr,
style: textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
);
},
),
1 => Text(
'cities'.tr,
style: textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
2 => Text(
'settings_full'.tr,
style: textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
int() => null,
},
actions: switch (tabIndex) {
0 => [
IconButton(
onPressed: () {
if (visible) {
_controller.clear();
_focusNode.unfocus();
visible = false;
} else {
visible = true;
}
setState(() {});
},
icon: Icon(
visible ? Icons.close : Iconsax.search_normal_1,
size: 18,
),
)
],
int() => null,
},
),
body: SafeArea(
child: TabBarView(
controller: tabController,
children: pages,
),
),
bottomNavigationBar: NavigationBar(
onDestinationSelected: (int index) => changeTabIndex(index),
selectedIndex: tabIndex,
destinations: [
NavigationDestination(
icon: const Icon(Iconsax.cloud_sunny),
selectedIcon: const Icon(Iconsax.cloud_sunny5),
label: 'name'.tr,
),
NavigationDestination(
icon: const Icon(Iconsax.map_1),
selectedIcon: const Icon(Iconsax.map5),
label: 'cities'.tr,
),
NavigationDestination(
icon: const Icon(Iconsax.category),
selectedIcon: const Icon(Iconsax.category5),
label: 'settings_full'.tr,
),
],
),
floatingActionButton: tabIndex == 1
? FloatingActionButton(
onPressed: () => showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: false,
builder: (BuildContext context) =>
const CreateWeatherCard(),
),
child: const Icon(
Iconsax.add,
),
)
: null,
),
),
);
}
}

View file

@ -1,177 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/data/weather.dart';
import 'package:rain/app/widgets/daily/weather_daily.dart';
import 'package:rain/app/widgets/daily/weather_more.dart';
import 'package:rain/app/widgets/desc/desc_container.dart';
import 'package:rain/app/widgets/hourly/weather_hourly.dart';
import 'package:rain/app/widgets/now/weather_now.dart';
import 'package:rain/app/widgets/shimmer.dart';
import 'package:rain/app/widgets/sun_moon/sunset_sunrise.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
class WeatherPage extends StatefulWidget {
const WeatherPage({super.key});
@override
State<WeatherPage> createState() => _WeatherPageState();
}
class _WeatherPageState extends State<WeatherPage> {
final weatherController = Get.put(WeatherController());
@override
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: () async {
await weatherController.deleteAll(false);
await weatherController.setLocation();
setState(() {});
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Obx(() {
if (weatherController.isLoading.isTrue) {
return ListView(
children: const [
MyShimmer(
hight: 200,
),
MyShimmer(
hight: 130,
edgeInsetsMargin: EdgeInsets.symmetric(vertical: 15),
),
MyShimmer(
hight: 90,
edgeInsetsMargin: EdgeInsets.only(bottom: 15),
),
MyShimmer(
hight: 400,
edgeInsetsMargin: EdgeInsets.only(bottom: 15),
),
MyShimmer(
hight: 450,
edgeInsetsMargin: EdgeInsets.only(bottom: 15),
)
],
);
}
final mainWeather = weatherController.mainWeather;
final weatherCard = WeatherCard.fromJson(mainWeather.toJson());
final hourOfDay = weatherController.hourOfDay.value;
final dayOfNow = weatherController.dayOfNow.value;
final sunrise = mainWeather.sunrise![dayOfNow];
final sunset = mainWeather.sunset![dayOfNow];
final tempMax = mainWeather.temperature2MMax![dayOfNow];
final tempMin = mainWeather.temperature2MMin![dayOfNow];
return ListView(
children: [
WeatherNow(
time: mainWeather.time![hourOfDay],
weather: mainWeather.weathercode![hourOfDay],
degree: mainWeather.temperature2M![hourOfDay],
timeDay: sunrise,
timeNight: sunset,
tempMax: tempMax!,
tempMin: tempMin!,
),
Card(
margin: const EdgeInsets.only(bottom: 15),
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: SizedBox(
height: 135,
child: ScrollablePositionedList.separated(
key: const PageStorageKey(0),
separatorBuilder: (BuildContext context, int index) {
return const VerticalDivider(
width: 10,
indent: 40,
endIndent: 40,
);
},
scrollDirection: Axis.horizontal,
itemScrollController:
weatherController.itemScrollController,
itemCount: mainWeather.time!.length,
itemBuilder: (ctx, i) {
final i24 = (i / 24).floor();
return GestureDetector(
onTap: () {
weatherController.hourOfDay.value = i;
weatherController.dayOfNow.value = i24;
setState(() {});
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 5),
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 5,
),
decoration: BoxDecoration(
color: i == hourOfDay
? context.theme.colorScheme.secondaryContainer
: Colors.transparent,
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
),
child: WeatherHourly(
time: mainWeather.time![i],
weather: mainWeather.weathercode![i],
degree: mainWeather.temperature2M![i],
timeDay: mainWeather.sunrise![i24],
timeNight: mainWeather.sunset![i24],
),
),
);
},
),
),
),
),
SunsetSunrise(
timeSunrise: sunrise,
timeSunset: sunset,
),
DescContainer(
humidity: mainWeather.relativehumidity2M?[hourOfDay],
wind: mainWeather.windspeed10M?[hourOfDay],
visibility: mainWeather.visibility?[hourOfDay],
feels: mainWeather.apparentTemperature?[hourOfDay],
evaporation: mainWeather.evapotranspiration?[hourOfDay],
precipitation: mainWeather.precipitation?[hourOfDay],
direction: mainWeather.winddirection10M?[hourOfDay],
pressure: mainWeather.surfacePressure?[hourOfDay],
rain: mainWeather.rain?[hourOfDay],
cloudcover: mainWeather.cloudcover?[hourOfDay],
windgusts: mainWeather.windgusts10M?[hourOfDay],
uvIndex: mainWeather.uvIndex?[hourOfDay],
dewpoint2M: mainWeather.dewpoint2M?[hourOfDay],
precipitationProbability:
mainWeather.precipitationProbability?[hourOfDay],
shortwaveRadiation: mainWeather.shortwaveRadiation?[hourOfDay],
initiallyExpanded: false,
title: 'hourlyVariables'.tr,
),
WeatherDaily(
weatherData: weatherCard,
onTap: () => Get.to(
() => WeatherMore(
weatherData: weatherCard,
),
transition: Transition.downToUp,
),
)
],
);
}),
),
);
}
}

View file

@ -1,183 +0,0 @@
import 'package:rain/app/data/weather.dart';
import 'package:rain/app/modules/geolocation.dart';
import 'package:rain/app/widgets/button.dart';
import 'package:rain/main.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class OnBording extends StatefulWidget {
const OnBording({super.key});
@override
State<OnBording> createState() => _OnBordingState();
}
class _OnBordingState extends State<OnBording> {
late PageController pageController;
int pageIndex = 0;
@override
void initState() {
pageController = PageController(initialPage: 0);
super.initState();
}
@override
void dispose() {
pageController.dispose();
super.dispose();
}
void onBoardHome() {
settings.onboard = true;
isar.writeTxnSync(() => isar.settings.putSync(settings));
Get.off(() => const SelectGeolocation(isStart: true),
transition: Transition.downToUp);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Expanded(
child: PageView.builder(
controller: pageController,
itemCount: data.length,
onPageChanged: (index) {
setState(() {
pageIndex = index;
});
},
itemBuilder: (context, index) => OnboardContent(
image: data[index].image,
title: data[index].title,
description: data[index].description,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
...List.generate(
data.length,
(index) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: DotIndicator(isActive: index == pageIndex),
)),
],
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: MyTextButton(
buttonName:
pageIndex == data.length - 1 ? 'start'.tr : 'next'.tr,
onPressed: () {
pageIndex == data.length - 1
? onBoardHome()
: pageController.nextPage(
duration: const Duration(milliseconds: 300),
curve: Curves.ease,
);
},
),
)
],
),
),
);
}
}
class DotIndicator extends StatelessWidget {
const DotIndicator({
super.key,
this.isActive = false,
});
final bool isActive;
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
height: 8,
width: 8,
decoration: BoxDecoration(
color: isActive
? context.theme.colorScheme.secondary
: context.theme.colorScheme.secondaryContainer,
shape: BoxShape.circle,
),
);
}
}
class Onboard {
final String image, title, description;
Onboard({
required this.image,
required this.title,
required this.description,
});
}
final List<Onboard> data = [
Onboard(
image: 'assets/icons/Rain.png',
title: 'name'.tr,
description: 'description'.tr),
Onboard(
image: 'assets/icons/Design.png',
title: 'name2'.tr,
description: 'description2'.tr),
Onboard(
image: 'assets/icons/Team.png',
title: 'name3'.tr,
description: 'description3'.tr),
];
class OnboardContent extends StatelessWidget {
const OnboardContent({
super.key,
required this.image,
required this.title,
required this.description,
});
final String image, title, description;
@override
Widget build(BuildContext context) {
return Column(
children: [
Flexible(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
image,
scale: 5,
),
Text(
title,
style: context.textTheme.titleLarge
?.copyWith(fontWeight: FontWeight.w600),
),
const SizedBox(height: 10),
SizedBox(
width: 300,
child: Text(
description,
style: context.textTheme.labelLarge?.copyWith(fontSize: 14),
textAlign: TextAlign.center,
),
),
],
),
),
],
);
}
}

View file

@ -1,989 +0,0 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_hsvcolor_picker/flutter_hsvcolor_picker.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:iconsax/iconsax.dart';
import 'package:intl/intl.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/data/weather.dart';
import 'package:rain/app/modules/settings/widgets/setting_card.dart';
import 'package:rain/main.dart';
import 'package:rain/theme/theme_controller.dart';
import 'package:rain/utils/color_converter.dart';
import 'package:url_launcher/url_launcher.dart';
class SettingsPage extends StatefulWidget {
const SettingsPage({super.key});
@override
State<SettingsPage> createState() => _SettingsPageState();
}
class _SettingsPageState extends State<SettingsPage> {
final themeController = Get.put(ThemeController());
final weatherController = Get.put(WeatherController());
String? appVersion;
String? colorBackground;
String? colorText;
Future<void> infoVersion() async {
final packageInfo = await PackageInfo.fromPlatform();
setState(() {
appVersion = packageInfo.version;
});
}
void urlLauncher(String uri) async {
final Uri url = Uri.parse(uri);
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
throw Exception('Could not launch $url');
}
}
@override
void initState() {
infoVersion();
super.initState();
}
updateLanguage(Locale locale) {
settings.language = '$locale';
isar.writeTxnSync(() => isar.settings.putSync(settings));
Get.updateLocale(locale);
Get.back();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SettingCard(
icon: const Icon(Iconsax.brush_1),
text: 'appearance'.tr,
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, setState) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 15),
child: Text(
'appearance'.tr,
style: context.textTheme.titleLarge?.copyWith(
fontSize: 20,
),
),
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.moon),
text: 'theme'.tr,
dropdown: true,
dropdownName: settings.theme?.tr,
dropdownList: <String>[
'system'.tr,
'dark'.tr,
'light'.tr
],
dropdownCange: (String? newValue) {
final newThemeMode = newValue?.tr;
final darkTheme = 'dark'.tr;
final systemTheme = 'system'.tr;
ThemeMode themeMode =
newThemeMode == systemTheme
? ThemeMode.system
: newThemeMode == darkTheme
? ThemeMode.dark
: ThemeMode.light;
String theme = newThemeMode == systemTheme
? 'system'
: newThemeMode == darkTheme
? 'dark'
: 'light';
themeController.saveTheme(theme);
themeController.changeThemeMode(themeMode);
setState(() {});
},
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.mobile),
text: 'amoledTheme'.tr,
switcher: true,
value: settings.amoledTheme,
onChange: (value) {
themeController.saveOledTheme(value);
MyApp.updateAppState(context,
newAmoledTheme: value);
},
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.colorfilter),
text: 'materialColor'.tr,
switcher: true,
value: settings.materialColor,
onChange: (value) {
themeController.saveMaterialTheme(value);
MyApp.updateAppState(context,
newMaterialColor: value);
},
),
const SizedBox(height: 10),
],
),
);
},
);
},
);
},
),
SettingCard(
icon: const Icon(Iconsax.code),
text: 'functions'.tr,
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, setState) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 15),
child: Text(
'functions'.tr,
style: context.textTheme.titleLarge?.copyWith(
fontSize: 20,
),
),
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.map_1),
text: 'location'.tr,
switcher: true,
value: settings.location,
onChange: (value) async {
if (value) {
bool serviceEnabled = await Geolocator
.isLocationServiceEnabled();
if (!serviceEnabled) {
if (!context.mounted) return;
await showAdaptiveDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog.adaptive(
title: Text(
'location'.tr,
style: context.textTheme.titleLarge,
),
content: Text('no_location'.tr,
style: context
.textTheme.titleMedium),
actions: [
TextButton(
onPressed: () =>
Get.back(result: false),
child: Text(
'cancel'.tr,
style: context
.textTheme.titleMedium
?.copyWith(
color:
Colors.blueAccent),
),
),
TextButton(
onPressed: () {
Geolocator
.openLocationSettings();
Get.back(result: true);
},
child: Text(
'settings'.tr,
style: context
.textTheme.titleMedium
?.copyWith(
color: Colors.green),
),
),
],
);
},
);
return;
}
weatherController.getCurrentLocation();
}
isar.writeTxnSync(() {
settings.location = value;
isar.settings.putSync(settings);
});
setState(() {});
},
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.notification_1),
text: 'notifications'.tr,
switcher: true,
value: settings.notifications,
onChange: (value) async {
final resultExact =
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestExactAlarmsPermission();
final result = Platform.isIOS
? await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions()
: await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.requestNotificationsPermission();
if (result != null && resultExact != null) {
isar.writeTxnSync(() {
settings.notifications = value;
isar.settings.putSync(settings);
});
if (value) {
weatherController.notification(
weatherController.mainWeather);
} else {
flutterLocalNotificationsPlugin.cancelAll();
}
setState(() {});
}
},
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.notification_status),
text: 'timeRange'.tr,
dropdown: true,
dropdownName: '$timeRange',
dropdownList: const <String>[
'1',
'2',
'3',
'4',
'5',
],
dropdownCange: (String? newValue) {
isar.writeTxnSync(() {
settings.timeRange = int.parse(newValue!);
isar.settings.putSync(settings);
});
MyApp.updateAppState(context,
newTimeRange: int.parse(newValue!));
if (settings.notifications) {
flutterLocalNotificationsPlugin.cancelAll();
weatherController.notification(
weatherController.mainWeather);
}
},
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.timer_start),
text: 'timeStart'.tr,
info: true,
infoSettings: true,
infoWidget: _TextInfo(
info: settings.timeformat == '12'
? DateFormat.jm(locale.languageCode).format(
DateFormat.Hm(locale.languageCode)
.parse(weatherController
.timeConvert(timeStart)
.format(context)))
: DateFormat.Hm(locale.languageCode).format(
DateFormat.Hm(locale.languageCode)
.parse(weatherController
.timeConvert(timeStart)
.format(context))),
),
onPressed: () async {
final TimeOfDay? timeStartPicker =
await showTimePicker(
context: context,
initialTime:
weatherController.timeConvert(timeStart),
builder: (context, child) {
final Widget mediaQueryWrapper = MediaQuery(
data: MediaQuery.of(context).copyWith(
alwaysUse24HourFormat:
settings.timeformat == '12'
? false
: true,
),
child: child!,
);
return mediaQueryWrapper;
},
);
if (timeStartPicker != null) {
isar.writeTxnSync(() {
settings.timeStart =
timeStartPicker.format(context);
isar.settings.putSync(settings);
});
if (!context.mounted) return;
MyApp.updateAppState(context,
newTimeStart:
timeStartPicker.format(context));
if (settings.notifications) {
flutterLocalNotificationsPlugin.cancelAll();
weatherController.notification(
weatherController.mainWeather);
}
}
},
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.timer_pause),
text: 'timeEnd'.tr,
info: true,
infoSettings: true,
infoWidget: _TextInfo(
info: settings.timeformat == '12'
? DateFormat.jm(locale.languageCode).format(
DateFormat.Hm(locale.languageCode)
.parse(weatherController
.timeConvert(timeEnd)
.format(context)))
: DateFormat.Hm(locale.languageCode).format(
DateFormat.Hm(locale.languageCode)
.parse(weatherController
.timeConvert(timeEnd)
.format(context))),
),
onPressed: () async {
final TimeOfDay? timeEndPicker =
await showTimePicker(
context: context,
initialTime:
weatherController.timeConvert(timeEnd),
builder: (context, child) {
final Widget mediaQueryWrapper = MediaQuery(
data: MediaQuery.of(context).copyWith(
alwaysUse24HourFormat:
settings.timeformat == '12'
? false
: true,
),
child: child!,
);
return mediaQueryWrapper;
},
);
if (timeEndPicker != null) {
isar.writeTxnSync(() {
settings.timeEnd =
timeEndPicker.format(context);
isar.settings.putSync(settings);
});
if (!context.mounted) return;
MyApp.updateAppState(context,
newTimeEnd:
timeEndPicker.format(context));
if (settings.notifications) {
flutterLocalNotificationsPlugin.cancelAll();
weatherController.notification(
weatherController.mainWeather);
}
}
},
),
const SizedBox(height: 10),
],
),
);
},
);
},
);
},
),
SettingCard(
icon: const Icon(Iconsax.d_square),
text: 'data'.tr,
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, setState) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 15),
child: Text(
'data'.tr,
style: context.textTheme.titleLarge?.copyWith(
fontSize: 20,
),
),
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.cloud_notif),
text: 'roundDegree'.tr,
switcher: true,
value: settings.roundDegree,
onChange: (value) {
settings.roundDegree = value;
isar.writeTxnSync(
() => isar.settings.putSync(settings),
);
MyApp.updateAppState(
context,
newRoundDegree: value,
);
setState(() {});
},
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.sun_1),
text: 'degrees'.tr,
dropdown: true,
dropdownName: settings.degrees.tr,
dropdownList: <String>[
'celsius'.tr,
'fahrenheit'.tr
],
dropdownCange: (String? newValue) async {
isar.writeTxnSync(() {
settings.degrees = newValue == 'celsius'.tr
? 'celsius'
: 'fahrenheit';
isar.settings.putSync(settings);
});
await weatherController.deleteAll(false);
await weatherController.setLocation();
await weatherController.updateCacheCard(true);
setState(() {});
},
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.rulerpen),
text: 'measurements'.tr,
dropdown: true,
dropdownName: settings.measurements.tr,
dropdownList: <String>[
'metric'.tr,
'imperial'.tr
],
dropdownCange: (String? newValue) async {
isar.writeTxnSync(() {
settings.measurements =
newValue == 'metric'.tr
? 'metric'
: 'imperial';
isar.settings.putSync(settings);
});
await weatherController.deleteAll(false);
await weatherController.setLocation();
await weatherController.updateCacheCard(true);
setState(() {});
},
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.clock),
text: 'timeformat'.tr,
dropdown: true,
dropdownName: settings.timeformat.tr,
dropdownList: <String>['12'.tr, '24'.tr],
dropdownCange: (String? newValue) {
isar.writeTxnSync(() {
settings.timeformat =
newValue == '12'.tr ? '12' : '24';
isar.settings.putSync(settings);
});
setState(() {});
},
),
const SizedBox(height: 10),
],
),
);
},
);
},
);
},
),
SettingCard(
icon: const Icon(Iconsax.setting_3),
text: 'widget'.tr,
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, setState) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 15),
child: Text(
'widget'.tr,
style: context.textTheme.titleLarge?.copyWith(
fontSize: 20,
),
),
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.bucket_square),
text: 'widgetBackground'.tr,
info: true,
infoWidget: CircleAvatar(
backgroundColor: context.theme.indicatorColor,
radius: 11,
child: CircleAvatar(
backgroundColor: widgetBackgroundColor.isEmpty
? context.theme.primaryColor
: HexColor.fromHex(widgetBackgroundColor),
radius: 10,
),
),
onPressed: () {
colorBackground = null;
showDialog(
context: context,
builder: (context) => Dialog(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 15),
child: Text(
'widgetBackground'.tr,
style: context
.textTheme.titleMedium
?.copyWith(fontSize: 18),
),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15),
child: Theme(
data: context.theme.copyWith(
inputDecorationTheme:
InputDecorationTheme(
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(
8),
),
),
),
child: ColorPicker(
color: widgetBackgroundColor
.isEmpty
? context.theme.primaryColor
: HexColor.fromHex(
widgetBackgroundColor),
onChanged: (pickedColor) {
colorBackground =
pickedColor.toHex();
},
),
),
),
IconButton(
icon: const Icon(
Iconsax.tick_square,
),
onPressed: () {
if (colorBackground == null) {
return;
}
weatherController
.updateWidgetBackgroundColor(
colorBackground!);
MyApp.updateAppState(context,
newWidgetBackgroundColor:
colorBackground);
Get.back();
},
),
],
),
),
),
);
},
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.text_block),
text: 'widgetText'.tr,
info: true,
infoWidget: CircleAvatar(
backgroundColor: context.theme.indicatorColor,
radius: 11,
child: CircleAvatar(
backgroundColor: widgetTextColor.isEmpty
? context.theme.primaryColor
: HexColor.fromHex(widgetTextColor),
radius: 10,
),
),
onPressed: () {
colorText = null;
showDialog(
context: context,
builder: (context) => Dialog(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 15),
child: Text(
'widgetText'.tr,
style: context
.textTheme.titleMedium
?.copyWith(fontSize: 18),
),
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 15),
child: Theme(
data: context.theme.copyWith(
inputDecorationTheme:
InputDecorationTheme(
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(
8),
),
),
),
child: ColorPicker(
color: widgetTextColor.isEmpty
? context.theme.primaryColor
: HexColor.fromHex(
widgetTextColor),
onChanged: (pickedColor) {
colorText =
pickedColor.toHex();
},
),
),
),
IconButton(
icon: const Icon(
Iconsax.tick_square,
),
onPressed: () {
if (colorText == null) return;
weatherController
.updateWidgetTextColor(
colorText!);
MyApp.updateAppState(context,
newWidgetTextColor:
colorText);
Get.back();
},
),
],
),
),
),
);
},
),
const SizedBox(height: 10),
],
),
);
},
);
},
);
},
),
SettingCard(
icon: const Icon(Iconsax.language_square),
text: 'language'.tr,
info: true,
infoSettings: true,
infoWidget: _TextInfo(
info: appLanguages.firstWhere(
(element) => (element['locale'] == locale),
orElse: () => appLanguages.first)['name'],
),
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, setState) {
return ListView(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 15),
child: Text(
'language'.tr,
style: context.textTheme.titleLarge?.copyWith(
fontSize: 20,
),
textAlign: TextAlign.center,
),
),
ListView.builder(
shrinkWrap: true,
physics: const BouncingScrollPhysics(),
itemCount: appLanguages.length,
itemBuilder: (context, index) {
return Card(
elevation: 4,
margin: const EdgeInsets.symmetric(
horizontal: 10, vertical: 5),
child: ListTile(
title: Text(
appLanguages[index]['name'],
style: context.textTheme.labelLarge,
textAlign: TextAlign.center,
),
onTap: () {
MyApp.updateAppState(context,
newLocale: appLanguages[index]
['locale']);
updateLanguage(
appLanguages[index]['locale']);
},
),
);
},
),
const SizedBox(height: 10),
],
);
},
);
},
);
},
),
SettingCard(
icon: const Icon(Iconsax.dollar_square),
text: 'support'.tr,
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, setState) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 15),
child: Text(
'support'.tr,
style: context.textTheme.titleLarge?.copyWith(
fontSize: 20,
),
),
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.card),
text: 'DonationAlerts',
onPressed: () => urlLauncher(
'https://www.donationalerts.com/r/darkmoonight'),
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.wallet),
text: 'ЮMoney',
onPressed: () => urlLauncher(
'https://yoomoney.ru/to/4100117672775961'),
),
const SizedBox(height: 10),
],
),
);
},
);
},
);
},
),
SettingCard(
icon: const Icon(Iconsax.link_square),
text: 'groups'.tr,
onPressed: () {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, setState) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20, vertical: 15),
child: Text(
'groups'.tr,
style: context.textTheme.titleLarge?.copyWith(
fontSize: 20,
),
),
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.voice_square),
text: 'Discord',
onPressed: () async {
final Uri url =
Uri.parse('https://discord.gg/JMMa9aHh8f');
if (!await launchUrl(url,
mode: LaunchMode.externalApplication)) {
throw Exception('Could not launch $url');
}
},
),
SettingCard(
elevation: 4,
icon: const Icon(Iconsax.message_square),
text: 'Telegram',
onPressed: () async {
final Uri url =
Uri.parse('https://t.me/darkmoonightX');
if (!await launchUrl(url,
mode: LaunchMode.externalApplication)) {
throw Exception('Could not launch $url');
}
},
),
const SizedBox(height: 10),
],
),
);
},
);
},
);
},
),
SettingCard(
icon: const Icon(Iconsax.document),
text: 'license'.tr,
onPressed: () => Get.to(
LicensePage(
applicationIcon: Container(
width: 100,
height: 100,
margin: const EdgeInsets.symmetric(vertical: 5),
decoration: const BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20)),
image: DecorationImage(
image: AssetImage('assets/icons/icon.png'),
),
),
),
applicationName: 'Rain',
applicationVersion: appVersion,
),
transition: Transition.downToUp,
),
),
SettingCard(
icon: const Icon(Iconsax.hierarchy_square_2),
text: 'version'.tr,
info: true,
infoWidget: _TextInfo(
info: '$appVersion',
),
),
SettingCard(
icon: Image.asset(
'assets/images/github.png',
scale: 20,
),
text: '${'project'.tr} GitHub',
onPressed: () =>
urlLauncher('https://github.com/darkmoonight/Rain'),
),
Padding(
padding: const EdgeInsets.all(10),
child: GestureDetector(
child: Text(
'openMeteo'.tr,
style: context.textTheme.bodyMedium,
overflow: TextOverflow.visible,
textAlign: TextAlign.center,
),
onTap: () => urlLauncher('https://open-meteo.com/'),
),
),
const SizedBox(height: 10),
],
),
);
}
}
class _TextInfo extends StatelessWidget {
const _TextInfo({required this.info});
final String info;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(right: 5),
child: Text(
info,
style: context.textTheme.bodyMedium,
overflow: TextOverflow.visible,
),
);
}
}

View file

@ -1,94 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax/iconsax.dart';
class SettingCard extends StatelessWidget {
const SettingCard({
super.key,
required this.icon,
required this.text,
this.switcher = false,
this.dropdown = false,
this.info = false,
this.infoSettings = false,
this.elevation,
this.dropdownName,
this.dropdownList,
this.dropdownCange,
this.value,
this.onPressed,
this.onChange,
this.infoWidget,
});
final Widget icon;
final String text;
final bool switcher;
final bool dropdown;
final bool info;
final bool infoSettings;
final Widget? infoWidget;
final String? dropdownName;
final List<String>? dropdownList;
final Function(String?)? dropdownCange;
final bool? value;
final Function()? onPressed;
final Function(bool)? onChange;
final double? elevation;
@override
Widget build(BuildContext context) {
return Card(
elevation: elevation ?? 1,
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: ListTile(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
onTap: onPressed,
leading: icon,
title: Text(
text,
style: context.textTheme.titleMedium,
overflow: TextOverflow.visible,
),
trailing: switcher
? Transform.scale(
scale: 0.8,
child: Switch(
value: value!,
onChanged: onChange,
),
)
: dropdown
? DropdownButton<String>(
underline: Container(),
value: dropdownName,
items: dropdownList!
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: dropdownCange,
)
: info
? infoSettings
? Wrap(
children: [
infoWidget!,
const Icon(
Iconsax.arrow_right_3,
size: 18,
),
],
)
: infoWidget!
: const Icon(
Iconsax.arrow_right_3,
size: 18,
),
),
);
}
}

View file

@ -1,42 +0,0 @@
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/main.dart';
import 'package:timezone/timezone.dart' as tz;
class NotificationShow {
Future showNotification(
int id,
String title,
String body,
DateTime date,
String icon,
) async {
final imagePath = await WeatherController().getLocalImagePath(icon);
AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails(
'Rain',
'DARK NIGHT',
priority: Priority.high,
importance: Importance.max,
playSound: false,
enableVibration: false,
largeIcon: FilePathAndroidBitmap(imagePath),
);
NotificationDetails notificationDetails =
NotificationDetails(android: androidNotificationDetails);
var scheduledTime = tz.TZDateTime.from(date, tz.local);
flutterLocalNotificationsPlugin.zonedSchedule(
id,
title,
body,
scheduledTime,
notificationDetails,
uiLocalNotificationDateInterpretation:
UILocalNotificationDateInterpretation.absoluteTime,
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
payload: imagePath,
);
}
}

View file

@ -1,20 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
final globalKey = GlobalKey<ScaffoldMessengerState>();
void showSnackBar({required String content, Function? onPressed}) {
globalKey.currentState?.showSnackBar(
SnackBar(
content: Text(content),
action: onPressed != null
? SnackBarAction(
label: 'settings'.tr,
onPressed: () {
onPressed();
},
)
: null,
),
);
}

479
lib/app/ui/geolocation.dart Executable file
View file

@ -0,0 +1,479 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:gap/gap.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:latlong2/latlong.dart';
import 'package:rain/app/api/api.dart';
import 'package:rain/app/api/city_api.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/ui/home.dart';
import 'package:rain/app/ui/widgets/button.dart';
import 'package:rain/app/ui/widgets/text_form.dart';
import 'package:rain/main.dart';
class SelectGeolocation extends StatefulWidget {
const SelectGeolocation({super.key, required this.isStart});
final bool isStart;
@override
State<SelectGeolocation> createState() => _SelectGeolocationState();
}
class _SelectGeolocationState extends State<SelectGeolocation> {
bool isLoading = false;
final formKeySearch = GlobalKey<FormState>();
final _focusNode = FocusNode();
final weatherController = Get.put(WeatherController());
final _controller = TextEditingController();
final _controllerLat = TextEditingController();
final _controllerLon = TextEditingController();
final _controllerCity = TextEditingController();
final _controllerDistrict = TextEditingController();
static const kTextFieldElevation = 4.0;
static const colorFilter = ColorFilter.matrix(<double>[
-0.2, -0.7, -0.08, 0, 255, // Red channel
-0.2, -0.7, -0.08, 0, 255, // Green channel
-0.2, -0.7, -0.08, 0, 255, // Blue channel
0, 0, 0, 1, 0, // Alpha channel
]);
final bool _isDarkMode = Get.theme.brightness == Brightness.dark;
final mapController = MapController();
void textTrim(TextEditingController value) {
value.text = value.text.trim();
while (value.text.contains(' ')) {
value.text = value.text.replaceAll(' ', ' ');
}
}
void fillController(Result selection) {
_controllerLat.text = '${selection.latitude}';
_controllerLon.text = '${selection.longitude}';
_controllerCity.text = selection.name;
_controllerDistrict.text = selection.admin1;
_controller.clear();
_focusNode.unfocus();
setState(() {});
}
void fillControllerGeo(Map<String, dynamic> location) {
_controllerLat.text = '${location['lat']}';
_controllerLon.text = '${location['lon']}';
_controllerCity.text = location['district'];
_controllerDistrict.text = location['city'];
setState(() {});
}
void fillMap(double latitude, double longitude) {
_controllerLat.text = '$latitude';
_controllerLon.text = '$longitude';
setState(() {});
}
Widget _buildMapTileLayer() {
return TileLayer(
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
userAgentPackageName: 'com.darkmoonight.rain',
);
}
Widget _buildMap() {
return ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(20)),
child: SizedBox(
height: Get.size.height * 0.3,
child: FlutterMap(
mapController: mapController,
options: MapOptions(
backgroundColor: context.theme.colorScheme.surface,
initialCenter: const LatLng(55.7522, 37.6156),
initialZoom: 3,
interactionOptions: const InteractionOptions(
flags: InteractiveFlag.all & ~InteractiveFlag.rotate,
),
cameraConstraint: CameraConstraint.contain(
bounds: LatLngBounds(
const LatLng(-90, -180),
const LatLng(90, 180),
),
),
onLongPress: (tapPosition, point) =>
fillMap(point.latitude, point.longitude),
),
children: [
if (_isDarkMode)
ColorFiltered(
colorFilter: colorFilter,
child: _buildMapTileLayer(),
)
else
_buildMapTileLayer(),
RichAttributionWidget(
animationConfig: const ScaleRAWA(),
attributions: [
TextSourceAttribution(
'OpenStreetMap contributors',
onTap: () => weatherController.urlLauncher(
'https://openstreetmap.org/copyright',
),
),
],
),
],
),
),
);
}
Widget _buildSearchField() {
return RawAutocomplete<Result>(
focusNode: _focusNode,
textEditingController: _controller,
fieldViewBuilder:
(
BuildContext context,
TextEditingController fieldTextEditingController,
FocusNode fieldFocusNode,
VoidCallback onFieldSubmitted,
) {
return MyTextForm(
elevation: kTextFieldElevation,
labelText: 'search'.tr,
type: TextInputType.text,
icon: const Icon(IconsaxPlusLinear.global_search),
controller: _controller,
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
focusNode: _focusNode,
);
},
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text.isEmpty) {
return const Iterable<Result>.empty();
}
return WeatherAPI().getCity(textEditingValue.text, locale);
},
onSelected: (Result selection) => fillController(selection),
displayStringForOption: (Result option) =>
'${option.name}, ${option.admin1}',
optionsViewBuilder:
(
BuildContext context,
AutocompleteOnSelected<Result> onSelected,
Iterable<Result> options,
) {
return _buildOptionsView(context, onSelected, options);
},
);
}
Widget _buildOptionsView(
BuildContext context,
AutocompleteOnSelected<Result> onSelected,
Iterable<Result> options,
) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: Align(
alignment: Alignment.topCenter,
child: Material(
borderRadius: BorderRadius.circular(20),
elevation: 4.0,
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final Result option = options.elementAt(index);
return InkWell(
onTap: () => onSelected(option),
child: ListTile(
title: Text(
'${option.name}, ${option.admin1}',
style: context.textTheme.labelLarge,
),
),
);
},
),
),
),
);
}
Widget _buildLocationButton() {
return Card(
elevation: kTextFieldElevation,
margin: const EdgeInsets.only(top: 10, right: 10),
child: Container(
margin: const EdgeInsets.all(2.5),
child: IconButton(
onPressed: _handleLocationButtonPress,
icon: const Icon(IconsaxPlusLinear.location),
),
),
);
}
Future<void> _handleLocationButtonPress() async {
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
if (!context.mounted) return;
await _showLocationDialog();
return;
}
setState(() => isLoading = true);
final location = await weatherController.getCurrentLocationSearch();
fillControllerGeo(location);
setState(() => isLoading = false);
}
Future<void> _showLocationDialog() async {
await showAdaptiveDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog.adaptive(
title: Text('location'.tr, style: context.textTheme.titleLarge),
content: Text('no_location'.tr, style: context.textTheme.titleMedium),
actions: [
TextButton(
onPressed: () => Get.back(result: false),
child: Text(
'cancel'.tr,
style: context.textTheme.titleMedium?.copyWith(
color: Colors.blueAccent,
),
),
),
TextButton(
onPressed: () {
Geolocator.openLocationSettings();
Get.back(result: true);
},
child: Text(
'settings'.tr,
style: context.textTheme.titleMedium?.copyWith(
color: Colors.green,
),
),
),
],
);
},
);
}
Widget _buildLatitudeField() {
return MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerLat,
labelText: 'lat'.tr,
type: TextInputType.number,
icon: const Icon(IconsaxPlusLinear.location),
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
validator: (value) => _validateLatitude(value),
);
}
Widget _buildLongitudeField() {
return MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerLon,
labelText: 'lon'.tr,
type: TextInputType.number,
icon: const Icon(IconsaxPlusLinear.location),
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
validator: (value) => _validateLongitude(value),
);
}
Widget _buildCityField() {
return MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerCity,
labelText: 'city'.tr,
type: TextInputType.name,
icon: const Icon(IconsaxPlusLinear.building_3),
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
validator: (value) => _validateCity(value),
);
}
Widget _buildDistrictField() {
return MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerDistrict,
labelText: 'district'.tr,
type: TextInputType.streetAddress,
icon: const Icon(IconsaxPlusLinear.global),
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
);
}
Widget _buildSubmitButton() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: MyTextButton(buttonName: 'done'.tr, onPressed: _handleSubmit),
);
}
String? _validateLatitude(String? value) {
if (value == null || value.isEmpty) {
return 'validateValue'.tr;
}
double? numericValue = double.tryParse(value);
if (numericValue == null) {
return 'validateNumber'.tr;
}
if (numericValue < -90 || numericValue > 90) {
return 'validate90'.tr;
}
return null;
}
String? _validateLongitude(String? value) {
if (value == null || value.isEmpty) {
return 'validateValue'.tr;
}
double? numericValue = double.tryParse(value);
if (numericValue == null) {
return 'validateNumber'.tr;
}
if (numericValue < -180 || numericValue > 180) {
return 'validate180'.tr;
}
return null;
}
String? _validateCity(String? value) {
if (value == null || value.isEmpty) {
return 'validateName'.tr;
}
return null;
}
Future<void> _handleSubmit() async {
if (formKeySearch.currentState!.validate()) {
textTrim(_controllerLat);
textTrim(_controllerLon);
textTrim(_controllerCity);
textTrim(_controllerDistrict);
try {
await weatherController.deleteAll(true);
await weatherController.getLocation(
double.parse(_controllerLat.text),
double.parse(_controllerLon.text),
_controllerDistrict.text,
_controllerCity.text,
);
widget.isStart
? Get.off(() => const HomePage(), transition: Transition.downToUp)
: Get.back();
} catch (error) {
Future.error(error);
}
}
}
@override
Widget build(BuildContext context) {
return Form(
key: formKeySearch,
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: _buildAppBar(),
body: SafeArea(
child: Stack(
children: [
Column(
children: [
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Flexible(
child: SingleChildScrollView(
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
),
child: _buildMap(),
),
Padding(
padding: const EdgeInsets.fromLTRB(
10,
15,
10,
5,
),
child: Text(
'searchMethod'.tr,
style: context.theme.textTheme.bodyLarge
?.copyWith(fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
Row(
children: [
Flexible(child: _buildSearchField()),
_buildLocationButton(),
],
),
_buildLatitudeField(),
_buildLongitudeField(),
_buildCityField(),
_buildDistrictField(),
const Gap(20),
],
),
),
),
],
),
),
_buildSubmitButton(),
],
),
if (isLoading)
BackdropFilter(
filter: ImageFilter.blur(sigmaY: 3, sigmaX: 3),
child: const Center(child: CircularProgressIndicator()),
),
],
),
),
),
);
}
AppBar _buildAppBar() {
return AppBar(
centerTitle: true,
leading: widget.isStart
? null
: IconButton(
onPressed: () {
Get.back();
},
icon: const Icon(IconsaxPlusLinear.arrow_left_3, size: 20),
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
automaticallyImplyLeading: false,
title: Text(
'searchCity'.tr,
style: context.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
);
}
}

311
lib/app/ui/home.dart Executable file
View file

@ -0,0 +1,311 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:isar/isar.dart';
import 'package:rain/app/api/api.dart';
import 'package:rain/app/api/city_api.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/data/db.dart';
import 'package:rain/app/ui/places/view/place_list.dart';
import 'package:rain/app/ui/places/widgets/create_place.dart';
import 'package:rain/app/ui/geolocation.dart';
import 'package:rain/app/ui/main/view/main.dart';
import 'package:rain/app/ui/map/view/map.dart';
import 'package:rain/app/ui/settings/view/settings.dart';
import 'package:rain/app/utils/show_snack_bar.dart';
import 'package:rain/main.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
int tabIndex = 0;
bool visible = false;
final _focusNode = FocusNode();
late TabController tabController;
final weatherController = Get.put(WeatherController());
final _controller = TextEditingController();
final List<Widget> pages = [
const MainPage(),
const PlaceList(),
if (!settings.hideMap) const MapPage(),
const SettingsPage(),
];
@override
void initState() {
super.initState();
getData();
setupTabController();
}
@override
void dispose() {
tabController.dispose();
super.dispose();
}
void setupTabController() {
tabController = TabController(
initialIndex: tabIndex,
length: pages.length,
vsync: this,
);
tabController.animation?.addListener(() {
int value = (tabController.animation!.value).round();
if (value != tabIndex) setState(() => tabIndex = value);
});
tabController.addListener(() {
setState(() {
tabIndex = tabController.index;
});
});
}
void getData() async {
await weatherController.deleteCache();
await weatherController.updateCacheCard(false);
await weatherController.setLocation();
}
void changeTabIndex(int index) {
setState(() {
tabIndex = index;
});
tabController.animateTo(tabIndex);
}
Widget _buildAppBarTitle(
int tabIndex,
TextStyle? textStyle,
TextStyle? labelLarge,
) {
switch (tabIndex) {
case 0:
return visible
? _buildSearchField(labelLarge)
: Obx(() {
final location = weatherController.location;
final city = location.city;
final district = location.district;
return Text(
weatherController.isLoading.isFalse
? district!.isEmpty
? '$city'
: city!.isEmpty
? district
: city == district
? city
: '$city, $district'
: settings.location
? 'search'.tr
: (isar.locationCaches.where().findAllSync()).isNotEmpty
? 'loading'.tr
: 'searchCity'.tr,
style: textStyle,
);
});
case 1:
return Text('cities'.tr, style: textStyle);
case 2:
return settings.hideMap
? Text('settings_full'.tr, style: textStyle)
: Text('map'.tr, style: textStyle);
case 3:
return Text('settings_full'.tr, style: textStyle);
default:
return const SizedBox.shrink();
}
}
Widget _buildSearchField(TextStyle? labelLarge) {
return RawAutocomplete<Result>(
focusNode: _focusNode,
textEditingController: _controller,
fieldViewBuilder: (_, __, ___, ____) {
return TextField(
controller: _controller,
focusNode: _focusNode,
style: labelLarge?.copyWith(fontSize: 16),
decoration: InputDecoration(hintText: 'search'.tr),
);
},
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text.isEmpty) {
return const Iterable<Result>.empty();
}
return WeatherAPI().getCity(textEditingValue.text, locale);
},
onSelected: (Result selection) async {
await weatherController.deleteAll(true);
await weatherController.getLocation(
double.parse('${selection.latitude}'),
double.parse('${selection.longitude}'),
selection.admin1,
selection.name,
);
visible = false;
_controller.clear();
_focusNode.unfocus();
setState(() {});
},
displayStringForOption:
(Result option) => '${option.name}, ${option.admin1}',
optionsViewBuilder: (
BuildContext context,
AutocompleteOnSelected<Result> onSelected,
Iterable<Result> options,
) {
return _buildOptionsView(context, onSelected, options, labelLarge);
},
);
}
Widget _buildOptionsView(
BuildContext context,
AutocompleteOnSelected<Result> onSelected,
Iterable<Result> options,
TextStyle? labelLarge,
) {
return Align(
alignment: Alignment.topLeft,
child: Material(
borderRadius: BorderRadius.circular(20),
elevation: 4.0,
child: SizedBox(
width: 250,
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final Result option = options.elementAt(index);
return InkWell(
onTap: () => onSelected(option),
child: ListTile(
title: Text(
'${option.name}, ${option.admin1}',
style: labelLarge,
),
),
);
},
),
),
),
);
}
Widget _buildSearchIconButton() {
return IconButton(
onPressed: () {
if (visible) {
_controller.clear();
_focusNode.unfocus();
visible = false;
} else {
visible = true;
}
setState(() {});
},
icon: Icon(
visible
? IconsaxPlusLinear.close_circle
: IconsaxPlusLinear.search_normal_1,
size: 18,
),
);
}
@override
Widget build(BuildContext context) {
final textTheme = context.textTheme;
final labelLarge = textTheme.labelLarge;
final textStyle = textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
);
return DefaultTabController(
length: pages.length,
child: ScaffoldMessenger(
key: globalKey,
child: Scaffold(
appBar: AppBar(
centerTitle: true,
automaticallyImplyLeading: false,
leading:
tabIndex == 0
? IconButton(
onPressed: () {
Get.to(
() => const SelectGeolocation(isStart: false),
transition: Transition.downToUp,
);
},
icon: const Icon(
IconsaxPlusLinear.global_search,
size: 18,
),
)
: null,
title: _buildAppBarTitle(tabIndex, textStyle, labelLarge),
actions: tabIndex == 0 ? [_buildSearchIconButton()] : null,
),
body: SafeArea(
child: TabBarView(controller: tabController, children: pages),
),
bottomNavigationBar: NavigationBar(
onDestinationSelected: (int index) => changeTabIndex(index),
selectedIndex: tabIndex,
destinations: [
NavigationDestination(
icon: const Icon(IconsaxPlusLinear.cloud_sunny),
selectedIcon: const Icon(IconsaxPlusBold.cloud_sunny),
label: 'name'.tr,
),
NavigationDestination(
icon: const Icon(IconsaxPlusLinear.buildings),
selectedIcon: const Icon(IconsaxPlusBold.buildings),
label: 'cities'.tr,
),
if (!settings.hideMap)
NavigationDestination(
icon: const Icon(IconsaxPlusLinear.map),
selectedIcon: const Icon(IconsaxPlusBold.map),
label: 'map'.tr,
),
NavigationDestination(
icon: const Icon(IconsaxPlusLinear.category),
selectedIcon: const Icon(IconsaxPlusBold.category),
label: 'settings_full'.tr,
),
],
),
floatingActionButton:
tabIndex == 1
? FloatingActionButton(
onPressed:
() => showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: false,
builder:
(BuildContext context) => const CreatePlace(),
),
child: const Icon(IconsaxPlusLinear.add),
)
: null,
),
),
);
}
}

242
lib/app/ui/main/view/main.dart Executable file
View file

@ -0,0 +1,242 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/data/db.dart';
import 'package:rain/app/ui/widgets/weather/daily/daily_card_list.dart';
import 'package:rain/app/ui/widgets/weather/daily/daily_container.dart';
import 'package:rain/app/ui/widgets/weather/desc/desc_container.dart';
import 'package:rain/app/ui/widgets/weather/hourly.dart';
import 'package:rain/app/ui/widgets/weather/now.dart';
import 'package:rain/app/ui/widgets/shimmer.dart';
import 'package:rain/app/ui/widgets/weather/sunset_sunrise.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
class MainPage extends StatefulWidget {
const MainPage({super.key});
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
final weatherController = Get.put(WeatherController());
@override
Widget build(BuildContext context) {
return RefreshIndicator(
onRefresh: _handleRefresh,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Obx(() {
if (weatherController.isLoading.isTrue) {
return _buildLoadingView();
}
final mainWeather = weatherController.mainWeather;
final weatherCard = WeatherCard.fromJson(mainWeather.toJson());
final hourOfDay = weatherController.hourOfDay.value;
final dayOfNow = weatherController.dayOfNow.value;
final sunrise = mainWeather.sunrise![dayOfNow];
final sunset = mainWeather.sunset![dayOfNow];
final tempMax = mainWeather.temperature2MMax![dayOfNow];
final tempMin = mainWeather.temperature2MMin![dayOfNow];
return _buildMainView(
context,
mainWeather,
weatherCard,
hourOfDay,
dayOfNow,
sunrise,
sunset,
tempMax!,
tempMin!,
);
}),
),
);
}
Future<void> _handleRefresh() async {
await weatherController.deleteAll(false);
await weatherController.setLocation();
setState(() {});
}
Widget _buildLoadingView() {
return ListView(
children: const [
MyShimmer(height: 200),
MyShimmer(height: 130, margin: EdgeInsets.symmetric(vertical: 15)),
MyShimmer(height: 90, margin: EdgeInsets.only(bottom: 15)),
MyShimmer(height: 400, margin: EdgeInsets.only(bottom: 15)),
MyShimmer(height: 450, margin: EdgeInsets.only(bottom: 15)),
],
);
}
Widget _buildMainView(
BuildContext context,
MainWeatherCache mainWeather,
WeatherCard weatherCard,
int hourOfDay,
int dayOfNow,
String sunrise,
String sunset,
double tempMax,
double tempMin,
) {
return ListView(
children: [
_buildNowWidget(
mainWeather,
hourOfDay,
dayOfNow,
sunrise,
sunset,
tempMax,
tempMin,
),
_buildHourlyList(context, mainWeather, hourOfDay, dayOfNow),
_buildSunsetSunriseWidget(sunrise, sunset),
_buildHourlyDescContainer(mainWeather, hourOfDay),
_buildDailyContainer(weatherCard),
],
);
}
Widget _buildNowWidget(
MainWeatherCache mainWeather,
int hourOfDay,
int dayOfNow,
String sunrise,
String sunset,
double tempMax,
double tempMin,
) {
return Now(
time: mainWeather.time![hourOfDay],
weather: mainWeather.weathercode![hourOfDay],
degree: mainWeather.temperature2M![hourOfDay],
feels: mainWeather.apparentTemperature![hourOfDay]!,
timeDay: sunrise,
timeNight: sunset,
tempMax: tempMax,
tempMin: tempMin,
);
}
Widget _buildHourlyList(
BuildContext context,
MainWeatherCache mainWeather,
int hourOfDay,
int dayOfNow,
) {
return Card(
margin: const EdgeInsets.only(bottom: 15),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: SizedBox(
height: 135,
child: ScrollablePositionedList.separated(
key: const PageStorageKey(0),
separatorBuilder: (BuildContext context, int index) {
return const VerticalDivider(
width: 10,
indent: 40,
endIndent: 40,
);
},
scrollDirection: Axis.horizontal,
itemScrollController: weatherController.itemScrollController,
itemCount: mainWeather.time!.length,
itemBuilder: (ctx, i) {
return _buildHourlyItem(
context,
mainWeather,
i,
hourOfDay,
dayOfNow,
);
},
),
),
),
);
}
Widget _buildHourlyItem(
BuildContext context,
MainWeatherCache mainWeather,
int i,
int hourOfDay,
int dayOfNow,
) {
final i24 = (i / 24).floor();
return GestureDetector(
onTap: () {
weatherController.hourOfDay.value = i;
weatherController.dayOfNow.value = i24;
setState(() {});
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 5),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
decoration: BoxDecoration(
color: i == hourOfDay
? context.theme.colorScheme.secondaryContainer
: Colors.transparent,
borderRadius: const BorderRadius.all(Radius.circular(20)),
),
child: Hourly(
time: mainWeather.time![i],
weather: mainWeather.weathercode![i],
degree: mainWeather.temperature2M![i],
timeDay: mainWeather.sunrise![i24],
timeNight: mainWeather.sunset![i24],
),
),
);
}
Widget _buildSunsetSunriseWidget(String sunrise, String sunset) {
return SunsetSunrise(timeSunrise: sunrise, timeSunset: sunset);
}
Widget _buildHourlyDescContainer(
MainWeatherCache mainWeather,
int hourOfDay,
) {
return DescContainer(
humidity: mainWeather.relativehumidity2M?[hourOfDay],
wind: mainWeather.windspeed10M?[hourOfDay],
visibility: mainWeather.visibility?[hourOfDay],
feels: mainWeather.apparentTemperature?[hourOfDay],
evaporation: mainWeather.evapotranspiration?[hourOfDay],
precipitation: mainWeather.precipitation?[hourOfDay],
direction: mainWeather.winddirection10M?[hourOfDay],
pressure: mainWeather.surfacePressure?[hourOfDay],
rain: mainWeather.rain?[hourOfDay],
cloudcover: mainWeather.cloudcover?[hourOfDay],
windgusts: mainWeather.windgusts10M?[hourOfDay],
uvIndex: mainWeather.uvIndex?[hourOfDay],
dewpoint2M: mainWeather.dewpoint2M?[hourOfDay],
precipitationProbability:
mainWeather.precipitationProbability?[hourOfDay],
shortwaveRadiation: mainWeather.shortwaveRadiation?[hourOfDay],
initiallyExpanded: false,
title: 'hourlyVariables'.tr,
);
}
Widget _buildDailyContainer(WeatherCard weatherCard) {
return DailyContainer(
weatherData: weatherCard,
onTap: () => Get.to(
() => DailyCardList(weatherData: weatherCard),
transition: Transition.downToUp,
),
);
}
}

477
lib/app/ui/map/view/map.dart Executable file
View file

@ -0,0 +1,477 @@
import 'dart:io';
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
import 'package:flutter/material.dart';
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_animations/flutter_map_animations.dart';
import 'package:flutter_map_cache/flutter_map_cache.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart';
import 'package:http_cache_file_store/http_cache_file_store.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:latlong2/latlong.dart';
import 'package:path_provider/path_provider.dart';
import 'package:rain/app/api/api.dart';
import 'package:rain/app/api/city_api.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/data/db.dart';
import 'package:rain/app/ui/places/view/place_info.dart';
import 'package:rain/app/ui/places/widgets/create_place.dart';
import 'package:rain/app/ui/places/widgets/place_card.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/app/ui/widgets/text_form.dart';
import 'package:rain/main.dart';
class MapPage extends StatefulWidget {
const MapPage({super.key});
@override
State<MapPage> createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> with TickerProviderStateMixin {
late final AnimatedMapController _animatedMapController =
AnimatedMapController(vsync: this);
final weatherController = Get.put(WeatherController());
final statusWeather = StatusWeather();
final statusData = StatusData();
final Future<CacheStore> _cacheStoreFuture = _getCacheStore();
final GlobalKey<ExpandableFabState> _fabKey = GlobalKey<ExpandableFabState>();
final bool _isDarkMode = Get.theme.brightness == Brightness.dark;
WeatherCard? _selectedWeatherCard;
bool _isCardVisible = false;
late final AnimationController _animationController;
late final Animation<Offset> _offsetAnimation;
static const _useTransformerId = 'useTransformerId';
final bool _useTransformer = true;
final _focusNode = FocusNode();
late final TextEditingController _controllerSearch = TextEditingController();
static Future<CacheStore> _getCacheStore() async {
final dir = await getTemporaryDirectory();
return FileCacheStore('${dir.path}${Platform.pathSeparator}MapTiles');
}
@override
void initState() {
_animationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_offsetAnimation = Tween<Offset>(
begin: const Offset(0.0, 1.0),
end: Offset.zero,
).animate(
CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
);
super.initState();
}
@override
void dispose() {
_animatedMapController.dispose();
_controllerSearch.dispose();
_animationController.dispose();
super.dispose();
}
void _resetMapOrientation({LatLng? center, double? zoom}) {
_animatedMapController.animateTo(
customId: _useTransformer ? _useTransformerId : null,
dest: center,
zoom: zoom,
rotation: 0,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
}
void _onMarkerTap(WeatherCard weatherCard) {
setState(() {
_selectedWeatherCard = weatherCard;
});
_animationController.forward();
_isCardVisible = true;
if (_fabKey.currentState?.isOpen == true) {
_fabKey.currentState?.toggle();
}
}
void _hideCard() {
_animationController.reverse().then((_) {
setState(() {
_isCardVisible = false;
_selectedWeatherCard = null;
});
});
_focusNode.unfocus();
}
Widget _buildStyleMarkers(
int weathercode,
String time,
String sunrise,
String sunset,
double temperature2M,
) {
return Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
statusWeather.getImageNow(weathercode, time, sunrise, sunset),
scale: 18,
),
const MaxGap(5),
Text(
statusData.getDegree(
roundDegree ? temperature2M.round() : temperature2M,
),
style: context.textTheme.labelLarge?.copyWith(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
],
),
);
}
Marker _buildMainLocationMarker(
WeatherCard weatherCard,
int hourOfDay,
int dayOfNow,
) {
return Marker(
height: 50,
width: 100,
point: LatLng(weatherCard.lat!, weatherCard.lon!),
child: GestureDetector(
onTap: () => _onMarkerTap(weatherCard),
child: _buildStyleMarkers(
weatherCard.weathercode![hourOfDay],
weatherCard.time![hourOfDay],
weatherCard.sunrise![dayOfNow],
weatherCard.sunset![dayOfNow],
weatherCard.temperature2M![hourOfDay],
),
),
);
}
Marker _buildCardMarker(WeatherCard weatherCardList) {
final hourOfDay = weatherController.getTime(
weatherCardList.time!,
weatherCardList.timezone!,
);
final dayOfNow = weatherController.getDay(
weatherCardList.timeDaily!,
weatherCardList.timezone!,
);
return Marker(
height: 50,
width: 100,
point: LatLng(weatherCardList.lat!, weatherCardList.lon!),
child: GestureDetector(
onTap: () => _onMarkerTap(weatherCardList),
child: _buildStyleMarkers(
weatherCardList.weathercode![hourOfDay],
weatherCardList.time![hourOfDay],
weatherCardList.sunrise![dayOfNow],
weatherCardList.sunset![dayOfNow],
weatherCardList.temperature2M![hourOfDay],
),
),
);
}
Widget _buildMapTileLayer(CacheStore cacheStore) {
return TileLayer(
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
userAgentPackageName: 'com.darkmoonight.rain',
tileProvider: CachedTileProvider(
store: cacheStore,
maxStale: const Duration(days: 30),
),
);
}
Widget _buildWeatherCard() {
return _isCardVisible && _selectedWeatherCard != null
? SlideTransition(
position: _offsetAnimation,
child: GestureDetector(
onTap:
() => Get.to(
() => PlaceInfo(weatherCard: _selectedWeatherCard!),
transition: Transition.downToUp,
),
child: PlaceCard(
time: _selectedWeatherCard!.time!,
timeDaily: _selectedWeatherCard!.timeDaily!,
timeDay: _selectedWeatherCard!.sunrise!,
timeNight: _selectedWeatherCard!.sunset!,
weather: _selectedWeatherCard!.weathercode!,
degree: _selectedWeatherCard!.temperature2M!,
district: _selectedWeatherCard!.district!,
city: _selectedWeatherCard!.city!,
timezone: _selectedWeatherCard!.timezone!,
),
),
)
: const SizedBox.shrink();
}
Widget _buildSearchField() {
return RawAutocomplete<Result>(
focusNode: _focusNode,
textEditingController: _controllerSearch,
fieldViewBuilder: (
BuildContext context,
TextEditingController fieldTextEditingController,
FocusNode fieldFocusNode,
VoidCallback onFieldSubmitted,
) {
return MyTextForm(
labelText: 'search'.tr,
type: TextInputType.text,
icon: const Icon(IconsaxPlusLinear.global_search),
controller: _controllerSearch,
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
focusNode: _focusNode,
onChanged: (value) => setState(() {}),
iconButton:
_controllerSearch.text.isNotEmpty
? IconButton(
onPressed: () {
_controllerSearch.clear();
},
icon: const Icon(
IconsaxPlusLinear.close_circle,
color: Colors.grey,
size: 20,
),
)
: null,
);
},
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text.isEmpty) {
return const Iterable<Result>.empty();
}
return WeatherAPI().getCity(textEditingValue.text, locale);
},
onSelected: (Result selection) {
_animatedMapController.mapController.move(
LatLng(selection.latitude, selection.longitude),
14,
);
_controllerSearch.clear();
_focusNode.unfocus();
},
displayStringForOption:
(Result option) => '${option.name}, ${option.admin1}',
optionsViewBuilder: (
BuildContext context,
AutocompleteOnSelected<Result> onSelected,
Iterable<Result> options,
) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: Align(
alignment: Alignment.topCenter,
child: Material(
borderRadius: BorderRadius.circular(20),
elevation: 4.0,
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final Result option = options.elementAt(index);
return InkWell(
onTap: () => onSelected(option),
child: ListTile(
title: Text(
'${option.name}, ${option.admin1}',
style: context.textTheme.labelLarge,
),
),
);
},
),
),
),
);
},
);
}
@override
Widget build(BuildContext context) {
final mainLocation = weatherController.location;
final mainWeather = weatherController.mainWeather;
final hourOfDay = weatherController.hourOfDay.value;
final dayOfNow = weatherController.dayOfNow.value;
return Scaffold(
body: FutureBuilder<CacheStore>(
future: _cacheStoreFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text(snapshot.error.toString()));
}
final cacheStore = snapshot.data!;
return Stack(
children: [
FlutterMap(
mapController: _animatedMapController.mapController,
options: MapOptions(
backgroundColor: context.theme.colorScheme.surface,
initialCenter: LatLng(mainLocation.lat!, mainLocation.lon!),
initialZoom: 8,
interactionOptions: const InteractionOptions(
flags: InteractiveFlag.all & ~InteractiveFlag.rotate,
),
cameraConstraint: CameraConstraint.contain(
bounds: LatLngBounds(
const LatLng(-90, -180),
const LatLng(90, 180),
),
),
onTap: (_, __) => _hideCard(),
onLongPress:
(tapPosition, point) => showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: false,
builder:
(BuildContext context) => CreatePlace(
latitude: '${point.latitude}',
longitude: '${point.longitude}',
),
),
),
children: [
if (_isDarkMode)
ColorFiltered(
colorFilter: const ColorFilter.matrix(<double>[
-0.2, -0.7, -0.08, 0, 255, // Red channel
-0.2, -0.7, -0.08, 0, 255, // Green channel
-0.2, -0.7, -0.08, 0, 255, // Blue channel
0, 0, 0, 1, 0, // Alpha channel
]),
child: _buildMapTileLayer(cacheStore),
)
else
_buildMapTileLayer(cacheStore),
RichAttributionWidget(
animationConfig: const ScaleRAWA(),
alignment: AttributionAlignment.bottomLeft,
attributions: [
TextSourceAttribution(
'OpenStreetMap contributors',
onTap:
() => weatherController.urlLauncher(
'https://openstreetmap.org/copyright',
),
),
],
),
Obx(() {
final mainMarker = _buildMainLocationMarker(
WeatherCard.fromJson({
...mainWeather.toJson(),
...mainLocation.toJson(),
}),
hourOfDay,
dayOfNow,
);
final cardMarkers =
weatherController.weatherCards
.map(
(weatherCardList) =>
_buildCardMarker(weatherCardList),
)
.toList();
return MarkerLayer(markers: [mainMarker, ...cardMarkers]);
}),
ExpandableFab(
key: _fabKey,
pos: ExpandableFabPos.right,
type: ExpandableFabType.up,
distance: 70,
openButtonBuilder: RotateFloatingActionButtonBuilder(
child: const Icon(IconsaxPlusLinear.menu),
fabSize: ExpandableFabSize.regular,
),
closeButtonBuilder: DefaultFloatingActionButtonBuilder(
child: const Icon(Icons.close),
fabSize: ExpandableFabSize.regular,
),
children: [
FloatingActionButton(
heroTag: null,
child: const Icon(IconsaxPlusLinear.home_2),
onPressed:
() => _resetMapOrientation(
center: LatLng(
mainLocation.lat!,
mainLocation.lon!,
),
zoom: 8,
),
),
FloatingActionButton(
heroTag: null,
child: const Icon(IconsaxPlusLinear.search_zoom_out_1),
onPressed:
() => _animatedMapController.animatedZoomOut(
customId:
_useTransformer ? _useTransformerId : null,
),
),
FloatingActionButton(
heroTag: null,
child: const Icon(IconsaxPlusLinear.search_zoom_in),
onPressed:
() => _animatedMapController.animatedZoomIn(
customId:
_useTransformer ? _useTransformerId : null,
),
),
],
),
Positioned(
left: 0,
right: 0,
bottom: 0,
child: _buildWeatherCard(),
),
],
),
_buildSearchField(),
],
);
},
),
floatingActionButtonLocation: ExpandableFab.location,
);
}
}

198
lib/app/ui/onboarding.dart Executable file
View file

@ -0,0 +1,198 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:rain/app/data/db.dart';
import 'package:rain/app/ui/geolocation.dart';
import 'package:rain/app/ui/widgets/button.dart';
import 'package:rain/main.dart';
import 'package:get/get.dart';
class OnBording extends StatefulWidget {
const OnBording({super.key});
@override
State<OnBording> createState() => _OnBordingState();
}
class _OnBordingState extends State<OnBording> {
late PageController pageController;
int pageIndex = 0;
@override
void initState() {
super.initState();
pageController = PageController(initialPage: 0);
}
@override
void dispose() {
pageController.dispose();
super.dispose();
}
void onBoardHome() {
settings.onboard = true;
isar.writeTxnSync(() => isar.settings.putSync(settings));
Get.off(
() => const SelectGeolocation(isStart: true),
transition: Transition.downToUp,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: SafeArea(
child: Column(
children: [
_buildPageView(),
_buildDotIndicators(),
_buildActionButton(),
],
),
),
);
}
Widget _buildPageView() {
return Expanded(
child: PageView.builder(
controller: pageController,
itemCount: data.length,
onPageChanged: (index) {
setState(() {
pageIndex = index;
});
},
itemBuilder: (context, index) => OnboardContent(
image: data[index].image,
title: data[index].title,
description: data[index].description,
),
),
);
}
Widget _buildDotIndicators() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(
data.length,
(index) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: DotIndicator(isActive: index == pageIndex),
),
),
);
}
Widget _buildActionButton() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: MyTextButton(
buttonName: pageIndex == data.length - 1 ? 'start'.tr : 'next'.tr,
onPressed: () {
if (pageIndex == data.length - 1) {
onBoardHome();
} else {
pageController.nextPage(
duration: const Duration(milliseconds: 300),
curve: Curves.ease,
);
}
},
),
);
}
}
class DotIndicator extends StatelessWidget {
const DotIndicator({super.key, this.isActive = false});
final bool isActive;
@override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
height: 8,
width: 8,
decoration: BoxDecoration(
color: isActive
? context.theme.colorScheme.secondary
: context.theme.colorScheme.secondaryContainer,
shape: BoxShape.circle,
),
);
}
}
class Onboard {
final String image, title, description;
Onboard({
required this.image,
required this.title,
required this.description,
});
}
final List<Onboard> data = [
Onboard(
image: 'assets/icons/Rain.png',
title: 'name'.tr,
description: 'description'.tr,
),
Onboard(
image: 'assets/icons/Design.png',
title: 'name2'.tr,
description: 'description2'.tr,
),
Onboard(
image: 'assets/icons/Team.png',
title: 'name3'.tr,
description: 'description3'.tr,
),
];
class OnboardContent extends StatelessWidget {
const OnboardContent({
super.key,
required this.image,
required this.title,
required this.description,
});
final String image, title, description;
@override
Widget build(BuildContext context) {
return Column(
children: [
Flexible(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(image, scale: 5),
Text(
title,
style: context.textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.w600,
),
),
const Gap(10),
SizedBox(
width: 300,
child: Text(
description,
style: context.textTheme.labelLarge?.copyWith(fontSize: 14),
textAlign: TextAlign.center,
),
),
],
),
),
],
);
}
}

View file

@ -0,0 +1,212 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/data/db.dart';
import 'package:rain/app/ui/widgets/weather/daily/daily_card_list.dart';
import 'package:rain/app/ui/widgets/weather/daily/daily_container.dart';
import 'package:rain/app/ui/widgets/weather/desc/desc_container.dart';
import 'package:rain/app/ui/widgets/weather/hourly.dart';
import 'package:rain/app/ui/widgets/weather/now.dart';
import 'package:rain/app/ui/widgets/weather/sunset_sunrise.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
class PlaceInfo extends StatefulWidget {
const PlaceInfo({super.key, required this.weatherCard});
final WeatherCard weatherCard;
@override
State<PlaceInfo> createState() => _PlaceInfoState();
}
class _PlaceInfoState extends State<PlaceInfo> {
int timeNow = 0;
int dayNow = 0;
final weatherController = Get.put(WeatherController());
final itemScrollController = ItemScrollController();
@override
void initState() {
getTime();
super.initState();
}
void getTime() {
final weatherCard = widget.weatherCard;
timeNow = weatherController.getTime(
weatherCard.time!,
weatherCard.timezone!,
);
dayNow = weatherController.getDay(
weatherCard.timeDaily!,
weatherCard.timezone!,
);
Future.delayed(const Duration(milliseconds: 30), () {
itemScrollController.scrollTo(
index: timeNow,
duration: const Duration(seconds: 2),
curve: Curves.easeInOutCubic,
);
});
}
@override
Widget build(BuildContext context) {
final weatherCard = widget.weatherCard;
return RefreshIndicator(
onRefresh: _handleRefresh,
child: Scaffold(
appBar: _buildAppBar(context, weatherCard),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: ListView(
children: [
_buildNowWidget(weatherCard),
_buildHourlyList(weatherCard),
_buildSunsetSunriseWidget(weatherCard),
_buildHourlyDescContainer(weatherCard),
_buildDailyContainer(weatherCard),
],
),
),
),
),
);
}
Future<void> _handleRefresh() async {
await weatherController.updateCard(widget.weatherCard);
getTime();
setState(() {});
}
AppBar _buildAppBar(BuildContext context, WeatherCard weatherCard) {
return AppBar(
centerTitle: true,
automaticallyImplyLeading: false,
leading: IconButton(
onPressed: () => Get.back(),
icon: const Icon(IconsaxPlusLinear.arrow_left_3, size: 20),
),
title: Text(
weatherCard.district!.isNotEmpty
? '${weatherCard.city}, ${weatherCard.district}'
: '${weatherCard.city}',
style: context.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
);
}
Widget _buildNowWidget(WeatherCard weatherCard) {
return Now(
time: weatherCard.time![timeNow],
weather: weatherCard.weathercode![timeNow],
degree: weatherCard.temperature2M![timeNow],
feels: weatherCard.apparentTemperature![timeNow]!,
timeDay: weatherCard.sunrise![dayNow],
timeNight: weatherCard.sunset![dayNow],
tempMax: weatherCard.temperature2MMax![dayNow]!,
tempMin: weatherCard.temperature2MMin![dayNow]!,
);
}
Widget _buildHourlyList(WeatherCard weatherCard) {
return Card(
margin: const EdgeInsets.only(bottom: 15),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: SizedBox(
height: 135,
child: ScrollablePositionedList.separated(
key: const PageStorageKey(1),
separatorBuilder: (BuildContext context, int index) {
return const VerticalDivider(
width: 10,
indent: 40,
endIndent: 40,
);
},
scrollDirection: Axis.horizontal,
itemScrollController: itemScrollController,
itemCount: weatherCard.time!.length,
itemBuilder: (ctx, i) => _buildHourlyItem(weatherCard, i),
),
),
),
);
}
Widget _buildHourlyItem(WeatherCard weatherCard, int i) {
return GestureDetector(
onTap: () {
timeNow = i;
dayNow = (i / 24).floor();
setState(() {});
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 5),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
decoration: BoxDecoration(
color:
i == timeNow
? context.theme.colorScheme.secondaryContainer
: Colors.transparent,
borderRadius: const BorderRadius.all(Radius.circular(20)),
),
child: Hourly(
time: weatherCard.time![i],
weather: weatherCard.weathercode![i],
degree: weatherCard.temperature2M![i],
timeDay: weatherCard.sunrise![(i / 24).floor()],
timeNight: weatherCard.sunset![(i / 24).floor()],
),
),
);
}
Widget _buildSunsetSunriseWidget(WeatherCard weatherCard) {
return SunsetSunrise(
timeSunrise: weatherCard.sunrise![dayNow],
timeSunset: weatherCard.sunset![dayNow],
);
}
Widget _buildHourlyDescContainer(WeatherCard weatherCard) {
return DescContainer(
humidity: weatherCard.relativehumidity2M?[timeNow],
wind: weatherCard.windspeed10M?[timeNow],
visibility: weatherCard.visibility?[timeNow],
feels: weatherCard.apparentTemperature?[timeNow],
evaporation: weatherCard.evapotranspiration?[timeNow],
precipitation: weatherCard.precipitation?[timeNow],
direction: weatherCard.winddirection10M?[timeNow],
pressure: weatherCard.surfacePressure?[timeNow],
rain: weatherCard.rain?[timeNow],
cloudcover: weatherCard.cloudcover?[timeNow],
windgusts: weatherCard.windgusts10M?[timeNow],
uvIndex: weatherCard.uvIndex?[timeNow],
dewpoint2M: weatherCard.dewpoint2M?[timeNow],
precipitationProbability: weatherCard.precipitationProbability?[timeNow],
shortwaveRadiation: weatherCard.shortwaveRadiation?[timeNow],
initiallyExpanded: false,
title: 'hourlyVariables'.tr,
);
}
Widget _buildDailyContainer(WeatherCard weatherCard) {
return DailyContainer(
weatherData: weatherCard,
onTap:
() => Get.to(
() => DailyCardList(weatherData: weatherCard),
transition: Transition.downToUp,
),
);
}
}

View file

@ -0,0 +1,116 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/ui/places/widgets/place_card_list.dart';
import 'package:rain/app/ui/widgets/text_form.dart';
class PlaceList extends StatefulWidget {
const PlaceList({super.key});
@override
State<PlaceList> createState() => _PlaceListState();
}
class _PlaceListState extends State<PlaceList> {
final weatherController = Get.put(WeatherController());
final TextEditingController searchTasks = TextEditingController();
String filter = '';
@override
void initState() {
super.initState();
applyFilter('');
}
void applyFilter(String value) {
filter = value.toLowerCase();
setState(() {});
}
void clearSearch() {
searchTasks.clear();
applyFilter('');
}
@override
Widget build(BuildContext context) {
final textTheme = context.textTheme;
final titleMedium = textTheme.titleMedium;
return Obx(() => _buildContent(context, titleMedium));
}
Widget _buildContent(BuildContext context, TextStyle? titleMedium) {
if (weatherController.weatherCards.isEmpty) {
return _buildEmptyState(context, titleMedium);
} else {
return _buildListView(context);
}
}
Widget _buildEmptyState(BuildContext context, TextStyle? titleMedium) {
return Center(
child: SingleChildScrollView(
child: Column(
children: [
Image.asset('assets/icons/City.png', scale: 6),
SizedBox(
width: Get.size.width * 0.8,
child: Text(
'noWeatherCard'.tr,
textAlign: TextAlign.center,
style: titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
),
],
),
),
);
}
Widget _buildListView(BuildContext context) {
return NestedScrollView(
physics: const NeverScrollableScrollPhysics(),
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [_buildSearchField(context)];
},
body: RefreshIndicator(
onRefresh: _handleRefresh,
child: PlaceCardList(searchCity: filter),
),
);
}
Widget _buildSearchField(BuildContext context) {
return SliverToBoxAdapter(
child: MyTextForm(
labelText: 'search'.tr,
type: TextInputType.text,
icon: const Icon(IconsaxPlusLinear.search_normal_1, size: 20),
controller: searchTasks,
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
onChanged: applyFilter,
iconButton:
searchTasks.text.isNotEmpty
? IconButton(
onPressed: clearSearch,
icon: const Icon(
IconsaxPlusLinear.close_circle,
color: Colors.grey,
size: 20,
),
)
: null,
),
);
}
Future<void> _handleRefresh() async {
await weatherController.updateCacheCard(true);
setState(() {});
}
}

View file

@ -0,0 +1,346 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:rain/app/api/api.dart';
import 'package:rain/app/api/city_api.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/ui/widgets/button.dart';
import 'package:rain/app/ui/widgets/text_form.dart';
import 'package:rain/main.dart';
class CreatePlace extends StatefulWidget {
const CreatePlace({super.key, this.latitude, this.longitude});
final String? latitude;
final String? longitude;
@override
State<CreatePlace> createState() => _CreatePlaceState();
}
class _CreatePlaceState extends State<CreatePlace>
with SingleTickerProviderStateMixin {
bool isLoading = false;
final formKey = GlobalKey<FormState>();
final _focusNode = FocusNode();
final weatherController = Get.put(WeatherController());
static const kTextFieldElevation = 4.0;
late TextEditingController _controller;
late TextEditingController _controllerLat;
late TextEditingController _controllerLon;
late TextEditingController _controllerCity;
late TextEditingController _controllerDistrict;
late AnimationController _animationController;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = TextEditingController();
_controllerLat = TextEditingController(text: widget.latitude);
_controllerLon = TextEditingController(text: widget.longitude);
_controllerCity = TextEditingController();
_controllerDistrict = TextEditingController();
_animationController = AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this,
);
_animation = CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
);
}
@override
void dispose() {
_animationController.dispose();
_controller.dispose();
_controllerLat.dispose();
_controllerLon.dispose();
_controllerCity.dispose();
_controllerDistrict.dispose();
super.dispose();
}
void textTrim(TextEditingController value) {
value.text = value.text.trim();
while (value.text.contains(' ')) {
value.text = value.text.replaceAll(' ', ' ');
}
}
void fillController(Result selection) {
_controllerLat.text = '${selection.latitude}';
_controllerLon.text = '${selection.longitude}';
_controllerCity.text = selection.name;
_controllerDistrict.text = selection.admin1;
_controller.clear();
_focusNode.unfocus();
setState(() {});
}
bool get showButton {
return _controllerLon.text.isNotEmpty &&
_controllerLat.text.isNotEmpty &&
_controllerCity.text.isNotEmpty &&
_controllerDistrict.text.isNotEmpty;
}
void updateButtonVisibility() {
if (showButton) {
_animationController.forward();
} else {
_animationController.reverse();
}
}
@override
Widget build(BuildContext context) {
updateButtonVisibility();
return Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
child: Form(
key: formKey,
child: SingleChildScrollView(
child: Stack(
children: [
Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
_buildTitleText(),
_buildSearchField(),
_buildLatitudeField(),
_buildLongitudeField(),
_buildCityField(),
_buildDistrictField(),
_buildSubmitButton(),
],
),
),
if (isLoading) const Center(child: CircularProgressIndicator()),
],
),
),
),
);
}
Widget _buildTitleText() {
return Padding(
padding: const EdgeInsets.only(top: 14, bottom: 7),
child: Text(
'create'.tr,
style: context.textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
);
}
Widget _buildSearchField() {
return RawAutocomplete<Result>(
focusNode: _focusNode,
textEditingController: _controller,
fieldViewBuilder: (
BuildContext context,
TextEditingController fieldTextEditingController,
FocusNode fieldFocusNode,
VoidCallback onFieldSubmitted,
) {
return MyTextForm(
elevation: kTextFieldElevation,
labelText: 'search'.tr,
type: TextInputType.text,
icon: const Icon(IconsaxPlusLinear.global_search),
controller: _controller,
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
focusNode: _focusNode,
);
},
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text.isEmpty) {
return const Iterable<Result>.empty();
}
return WeatherAPI().getCity(textEditingValue.text, locale);
},
onSelected: (Result selection) => fillController(selection),
displayStringForOption:
(Result option) => '${option.name}, ${option.admin1}',
optionsViewBuilder: (
BuildContext context,
AutocompleteOnSelected<Result> onSelected,
Iterable<Result> options,
) {
return _buildOptionsView(context, onSelected, options);
},
);
}
Widget _buildOptionsView(
BuildContext context,
AutocompleteOnSelected<Result> onSelected,
Iterable<Result> options,
) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Align(
alignment: Alignment.topCenter,
child: Material(
borderRadius: BorderRadius.circular(20),
elevation: 4.0,
child: ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: true,
itemCount: options.length,
itemBuilder: (BuildContext context, int index) {
final Result option = options.elementAt(index);
return InkWell(
onTap: () => onSelected(option),
child: ListTile(
title: Text(
'${option.name}, ${option.admin1}',
style: context.textTheme.labelLarge,
),
),
);
},
),
),
),
);
}
Widget _buildLatitudeField() {
return MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerLat,
labelText: 'lat'.tr,
type: TextInputType.number,
icon: const Icon(IconsaxPlusLinear.location),
onChanged: (value) => setState(() {}),
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
validator: (value) => _validateLatitude(value),
);
}
Widget _buildLongitudeField() {
return MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerLon,
labelText: 'lon'.tr,
type: TextInputType.number,
icon: const Icon(IconsaxPlusLinear.location),
onChanged: (value) => setState(() {}),
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
validator: (value) => _validateLongitude(value),
);
}
Widget _buildCityField() {
return MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerCity,
labelText: 'city'.tr,
type: TextInputType.name,
icon: const Icon(IconsaxPlusLinear.building_3),
onChanged: (value) => setState(() {}),
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
validator: (value) => _validateCity(value),
);
}
Widget _buildDistrictField() {
return MyTextForm(
elevation: kTextFieldElevation,
controller: _controllerDistrict,
labelText: 'district'.tr,
type: TextInputType.streetAddress,
icon: const Icon(IconsaxPlusLinear.global),
onChanged: (value) => setState(() {}),
margin: const EdgeInsets.only(left: 10, right: 10, top: 10),
validator: (value) => _validateDistrict(value),
);
}
Widget _buildSubmitButton() {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: SizeTransition(
sizeFactor: _animation,
axisAlignment: -1.0,
child: MyTextButton(buttonName: 'done'.tr, onPressed: _handleSubmit),
),
);
}
String? _validateLatitude(String? value) {
if (value == null || value.isEmpty) {
return 'validateValue'.tr;
}
double? numericValue = double.tryParse(value);
if (numericValue == null) {
return 'validateNumber'.tr;
}
if (numericValue < -90 || numericValue > 90) {
return 'validate90'.tr;
}
return null;
}
String? _validateLongitude(String? value) {
if (value == null || value.isEmpty) {
return 'validateValue'.tr;
}
double? numericValue = double.tryParse(value);
if (numericValue == null) {
return 'validateNumber'.tr;
}
if (numericValue < -180 || numericValue > 180) {
return 'validate180'.tr;
}
return null;
}
String? _validateCity(String? value) {
if (value == null || value.isEmpty) {
return 'validateName'.tr;
}
return null;
}
String? _validateDistrict(String? value) {
if (value == null || value.isEmpty) {
return 'validateName'.tr;
}
return null;
}
Future<void> _handleSubmit() async {
if (formKey.currentState!.validate()) {
textTrim(_controllerLat);
textTrim(_controllerLon);
textTrim(_controllerCity);
textTrim(_controllerDistrict);
setState(() => isLoading = true);
await weatherController.addCardWeather(
double.parse(_controllerLat.text),
double.parse(_controllerLon.text),
_controllerCity.text,
_controllerDistrict.text,
);
setState(() => isLoading = false);
Get.back();
}
}
}

View file

@ -0,0 +1,155 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/ui/widgets/weather/status/status_weather.dart';
import 'package:rain/app/ui/widgets/weather/status/status_data.dart';
import 'package:timezone/standalone.dart' as tz;
class PlaceCard extends StatefulWidget {
const PlaceCard({
super.key,
required this.time,
required this.weather,
required this.degree,
required this.district,
required this.city,
required this.timezone,
required this.timeDay,
required this.timeNight,
required this.timeDaily,
});
final List<String> time;
final List<String> timeDay;
final List<String> timeNight;
final List<DateTime> timeDaily;
final String district;
final String city;
final List<int> weather;
final List<double> degree;
final String timezone;
@override
State<PlaceCard> createState() => _PlaceCardState();
}
class _PlaceCardState extends State<PlaceCard> {
final statusWeather = StatusWeather();
final statusData = StatusData();
final weatherController = Get.put(WeatherController());
@override
Widget build(BuildContext context) {
final currentTimeIndex = weatherController.getTime(
widget.time,
widget.timezone,
);
final currentDayIndex = weatherController.getDay(
widget.timeDaily,
widget.timezone,
);
return Card(
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 20),
child: Row(
children: [
_buildWeatherInfo(context, currentTimeIndex, currentDayIndex),
const Gap(5),
_buildWeatherImage(currentTimeIndex, currentDayIndex),
],
),
),
);
}
Widget _buildWeatherInfo(
BuildContext context,
int currentTimeIndex,
int currentDayIndex,
) {
return Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
statusData.getDegree(
widget.degree[currentTimeIndex].round().toInt(),
),
style: context.textTheme.titleLarge?.copyWith(
fontSize: 22,
fontWeight: FontWeight.w600,
),
),
const Gap(7),
Text(
statusWeather.getText(widget.weather[currentTimeIndex]),
style: context.textTheme.titleMedium?.copyWith(
color: Colors.grey,
fontWeight: FontWeight.w400,
),
),
],
),
const Gap(10),
_buildLocationText(),
const Gap(5),
_buildCurrentTimeText(context),
],
),
);
}
Widget _buildLocationText() {
String locationText;
if (widget.district.isEmpty) {
locationText = widget.city;
} else if (widget.city.isEmpty) {
locationText = widget.district;
} else if (widget.city == widget.district) {
locationText = widget.city;
} else {
locationText = '${widget.city}, ${widget.district}';
}
return Text(
locationText,
style: context.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w500,
),
);
}
Widget _buildCurrentTimeText(BuildContext context) {
return StreamBuilder(
stream: Stream.periodic(const Duration(seconds: 1)),
builder: (context, snapshot) {
return Text(
'${'time'.tr}: ${statusData.getTimeFormatTz(tz.TZDateTime.now(tz.getLocation(widget.timezone)))}',
style: context.textTheme.titleMedium?.copyWith(
color: Colors.grey,
fontWeight: FontWeight.w400,
),
);
},
);
}
Widget _buildWeatherImage(int currentTimeIndex, int currentDayIndex) {
return Image.asset(
statusWeather.getImageNow(
widget.weather[currentTimeIndex],
widget.time[currentTimeIndex],
widget.timeDay[currentDayIndex],
widget.timeNight[currentDayIndex],
),
scale: 6.5,
);
}
}

View file

@ -0,0 +1,155 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/data/db.dart';
import 'package:rain/app/ui/places/view/place_info.dart';
import 'package:rain/app/ui/places/widgets/place_card.dart';
class PlaceCardList extends StatefulWidget {
const PlaceCardList({super.key, required this.searchCity});
final String searchCity;
@override
State<PlaceCardList> createState() => _PlaceCardListState();
}
class _PlaceCardListState extends State<PlaceCardList> {
final weatherController = Get.put(WeatherController());
@override
Widget build(BuildContext context) {
final textTheme = context.textTheme;
final titleMedium = textTheme.titleMedium;
final weatherCards = _filterWeatherCards(
weatherController.weatherCards,
widget.searchCity,
);
return ReorderableListView(
onReorder:
(oldIndex, newIndex) => weatherController.reorder(oldIndex, newIndex),
children: _buildWeatherCardList(
weatherCards,
context,
textTheme,
titleMedium,
),
);
}
List<WeatherCard> _filterWeatherCards(
List<WeatherCard> weatherCards,
String searchCity,
) {
return weatherCards
.where(
(weatherCard) =>
(searchCity.isEmpty ||
weatherCard.city!.toLowerCase().contains(searchCity)),
)
.toList();
}
List<Widget> _buildWeatherCardList(
List<WeatherCard> weatherCards,
BuildContext context,
TextTheme textTheme,
TextStyle? titleMedium,
) {
return weatherCards
.map(
(weatherCardList) => _buildDismissibleCard(
context,
weatherCardList,
textTheme,
titleMedium,
),
)
.toList();
}
Widget _buildDismissibleCard(
BuildContext context,
WeatherCard weatherCardList,
TextTheme textTheme,
TextStyle? titleMedium,
) {
return Dismissible(
key: ValueKey(weatherCardList),
direction: DismissDirection.endToStart,
background: _buildDismissibleBackground(),
confirmDismiss:
(DismissDirection direction) =>
_showDeleteConfirmationDialog(context, textTheme, titleMedium),
onDismissed: (DismissDirection direction) async {
await weatherController.deleteCardWeather(weatherCardList);
},
child: _buildCardGestureDetector(weatherCardList),
);
}
Widget _buildDismissibleBackground() {
return Container(
alignment: Alignment.centerRight,
child: const Padding(
padding: EdgeInsets.only(right: 15),
child: Icon(IconsaxPlusLinear.trash_square, color: Colors.red),
),
);
}
Future<bool> _showDeleteConfirmationDialog(
BuildContext context,
TextTheme textTheme,
TextStyle? titleMedium,
) async {
return await showAdaptiveDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog.adaptive(
title: Text('deletedCardWeather'.tr, style: textTheme.titleLarge),
content: Text('deletedCardWeatherQuery'.tr, style: titleMedium),
actions: [
TextButton(
onPressed: () => Get.back(result: false),
child: Text(
'cancel'.tr,
style: titleMedium?.copyWith(color: Colors.blueAccent),
),
),
TextButton(
onPressed: () => Get.back(result: true),
child: Text(
'delete'.tr,
style: titleMedium?.copyWith(color: Colors.red),
),
),
],
);
},
);
}
Widget _buildCardGestureDetector(WeatherCard weatherCardList) {
return GestureDetector(
onTap:
() => Get.to(
() => PlaceInfo(weatherCard: weatherCardList),
transition: Transition.downToUp,
),
child: PlaceCard(
time: weatherCardList.time!,
timeDaily: weatherCardList.timeDaily!,
timeDay: weatherCardList.sunrise!,
timeNight: weatherCardList.sunset!,
weather: weatherCardList.weathercode!,
degree: weatherCardList.temperature2M!,
district: weatherCardList.district!,
city: weatherCardList.city!,
timezone: weatherCardList.timezone!,
),
);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,107 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
class SettingCard extends StatelessWidget {
const SettingCard({
super.key,
required this.icon,
required this.text,
this.switcher = false,
this.dropdown = false,
this.info = false,
this.infoSettings = false,
this.elevation,
this.dropdownName,
this.dropdownList,
this.dropdownChange,
this.value,
this.onPressed,
this.onChange,
this.infoWidget,
});
final Widget icon;
final String text;
final bool switcher;
final bool dropdown;
final bool info;
final bool infoSettings;
final Widget? infoWidget;
final String? dropdownName;
final List<String>? dropdownList;
final ValueChanged<String?>? dropdownChange;
final bool? value;
final VoidCallback? onPressed;
final ValueChanged<bool>? onChange;
final double? elevation;
@override
Widget build(BuildContext context) {
return Card(
elevation: elevation ?? 1,
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: ListTile(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
onTap: onPressed,
leading: icon,
title: Text(
text,
style: context.textTheme.titleMedium,
overflow: TextOverflow.visible,
),
trailing: _buildTrailingWidget(context),
),
);
}
Widget _buildTrailingWidget(BuildContext context) {
if (switcher) {
return _buildSwitchWidget();
} else if (dropdown) {
return _buildDropdownWidget();
} else if (info) {
return _buildInfoWidget();
} else {
return const Icon(IconsaxPlusLinear.arrow_right_3, size: 18);
}
}
Widget _buildSwitchWidget() {
return Transform.scale(
scale: 0.8,
child: Switch(value: value!, onChanged: onChange),
);
}
Widget _buildDropdownWidget() {
return DropdownButton<String>(
icon: const Padding(
padding: EdgeInsets.only(left: 7),
child: Icon(IconsaxPlusLinear.arrow_down),
),
iconSize: 15,
alignment: AlignmentDirectional.centerEnd,
borderRadius: const BorderRadius.all(Radius.circular(15)),
underline: Container(),
value: dropdownName,
items: dropdownList!.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(value: value, child: Text(value));
}).toList(),
onChanged: dropdownChange,
);
}
Widget _buildInfoWidget() {
if (infoSettings) {
return Wrap(
children: [
infoWidget!,
const Icon(IconsaxPlusLinear.arrow_right_3, size: 18),
],
);
} else {
return infoWidget!;
}
}
}

37
lib/app/ui/widgets/button.dart Executable file
View file

@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class MyTextButton extends StatelessWidget {
const MyTextButton({
super.key,
required this.buttonName,
required this.onPressed,
this.height = 50.0,
});
final String buttonName;
final VoidCallback? onPressed;
final double height;
@override
Widget build(BuildContext context) {
return SizedBox(
height: height,
width: double.infinity,
child: ElevatedButton(
style: _buildButtonStyle(context),
onPressed: onPressed,
child: Text(buttonName, style: context.textTheme.titleMedium),
),
);
}
ButtonStyle _buildButtonStyle(BuildContext context) {
return ButtonStyle(
shadowColor: const WidgetStatePropertyAll(Colors.transparent),
backgroundColor: WidgetStatePropertyAll(
context.theme.colorScheme.secondaryContainer.withAlpha(80),
),
);
}
}

View file

@ -3,25 +3,21 @@ import 'package:get/get.dart';
import 'package:shimmer/shimmer.dart'; import 'package:shimmer/shimmer.dart';
class MyShimmer extends StatelessWidget { class MyShimmer extends StatelessWidget {
const MyShimmer({ const MyShimmer({super.key, required this.height, this.margin});
super.key,
required this.hight, final double height;
this.edgeInsetsMargin, final EdgeInsets? margin;
});
final double hight;
final EdgeInsets? edgeInsetsMargin;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Shimmer.fromColors( return Shimmer.fromColors(
baseColor: context.theme.cardColor, baseColor: context.theme.cardColor,
highlightColor: context.theme.primaryColor, highlightColor: context.theme.primaryColor,
child: Card( child: _buildShimmerCard(),
margin: edgeInsetsMargin,
child: SizedBox(
height: hight,
),
),
); );
} }
Widget _buildShimmerCard() {
return Card(margin: margin, child: SizedBox(height: height));
}
} }

View file

@ -15,6 +15,7 @@ class MyTextForm extends StatelessWidget {
this.focusNode, this.focusNode,
this.onChanged, this.onChanged,
}); });
final String labelText; final String labelText;
final TextInputType type; final TextInputType type;
final Icon icon; final Icon icon;
@ -31,23 +32,28 @@ class MyTextForm extends StatelessWidget {
return Card( return Card(
elevation: elevation, elevation: elevation,
margin: margin, margin: margin,
child: TextFormField( child: _buildTextFormField(context),
focusNode: focusNode, );
controller: controller, }
keyboardType: type,
style: context.textTheme.labelLarge, Widget _buildTextFormField(BuildContext context) {
decoration: InputDecoration( return TextFormField(
contentPadding: const EdgeInsets.symmetric( focusNode: focusNode,
horizontal: 12.5, controller: controller,
vertical: 0, keyboardType: type,
), style: context.textTheme.labelLarge,
prefixIcon: icon, decoration: _buildInputDecoration(),
suffixIcon: iconButton, validator: validator,
labelText: labelText, onChanged: onChanged,
), );
validator: validator, }
onChanged: onChanged,
), InputDecoration _buildInputDecoration() {
return InputDecoration(
contentPadding: const EdgeInsets.symmetric(horizontal: 12.5, vertical: 0),
prefixIcon: icon,
suffixIcon: iconButton,
labelText: labelText,
); );
} }
} }

View file

@ -0,0 +1,99 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:rain/app/ui/widgets/weather/status/status_weather.dart';
import 'package:rain/app/ui/widgets/weather/status/status_data.dart';
import 'package:rain/main.dart';
class DailyCard extends StatefulWidget {
const DailyCard({
super.key,
required this.timeDaily,
required this.weathercodeDaily,
required this.temperature2MMax,
required this.temperature2MMin,
});
final DateTime timeDaily;
final int? weathercodeDaily;
final double? temperature2MMax;
final double? temperature2MMin;
@override
State<DailyCard> createState() => _DailyCardState();
}
class _DailyCardState extends State<DailyCard> {
final statusWeather = StatusWeather();
final statusData = StatusData();
@override
Widget build(BuildContext context) {
if (widget.weathercodeDaily == null) {
return Container();
}
return Card(
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 20),
child: Row(
children: [
_buildTemperatureInfo(context),
const Gap(5),
_buildWeatherImage(),
],
),
),
);
}
Widget _buildTemperatureInfo(BuildContext context) {
return Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${statusData.getDegree(widget.temperature2MMin?.round())} / ${statusData.getDegree(widget.temperature2MMax?.round())}',
style: context.textTheme.titleLarge?.copyWith(
fontSize: 22,
fontWeight: FontWeight.w600,
),
),
const Gap(5),
_buildDateText(context),
const Gap(5),
_buildWeatherDescription(context),
],
),
);
}
Widget _buildDateText(BuildContext context) {
return Text(
DateFormat.MMMMEEEEd(locale.languageCode).format(widget.timeDaily),
style: context.textTheme.titleMedium?.copyWith(
color: Colors.grey,
fontWeight: FontWeight.w400,
),
);
}
Widget _buildWeatherDescription(BuildContext context) {
return Text(
statusWeather.getText(widget.weathercodeDaily),
style: context.textTheme.titleMedium?.copyWith(
color: Colors.grey,
fontWeight: FontWeight.w400,
),
);
}
Widget _buildWeatherImage() {
return Image.asset(
statusWeather.getImageNowDaily(widget.weathercodeDaily),
scale: 6.5,
);
}
}

View file

@ -0,0 +1,348 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:intl/intl.dart';
import 'package:rain/app/data/db.dart';
import 'package:rain/app/ui/widgets/weather/desc/desc_container.dart';
import 'package:rain/app/ui/widgets/weather/desc/message.dart';
import 'package:rain/app/ui/widgets/weather/hourly.dart';
import 'package:rain/app/ui/widgets/weather/now.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/app/ui/widgets/weather/sunset_sunrise.dart';
import 'package:rain/main.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
class DailyCardInfo extends StatefulWidget {
const DailyCardInfo({
super.key,
required this.weatherData,
required this.index,
});
final WeatherCard weatherData;
final int index;
@override
State<DailyCardInfo> createState() => _DailyCardInfoState();
}
class _DailyCardInfoState extends State<DailyCardInfo> {
final statusWeather = StatusWeather();
final statusData = StatusData();
final message = Message();
late PageController pageController;
int pageIndex = 0;
int hourOfDay = 0;
@override
void initState() {
pageController = PageController(initialPage: widget.index);
pageIndex = widget.index;
super.initState();
}
@override
void dispose() {
pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final weatherData = widget.weatherData;
final timeDaily = weatherData.timeDaily ?? [];
final textTheme = context.textTheme;
return Scaffold(
appBar: _buildAppBar(context, textTheme, timeDaily),
body: SafeArea(
child: PageView.builder(
controller: pageController,
onPageChanged: (index) {
setState(() {
pageIndex = index;
hourOfDay = 0;
});
},
itemCount: timeDaily.length,
itemBuilder: (context, index) {
return _buildPageContent(context, weatherData, index);
},
),
),
);
}
AppBar _buildAppBar(
BuildContext context,
TextTheme textTheme,
List<DateTime> timeDaily,
) {
return AppBar(
automaticallyImplyLeading: false,
centerTitle: true,
leading: IconButton(
onPressed: () => Get.back(),
icon: const Icon(IconsaxPlusLinear.arrow_left_3, size: 20),
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
title: Text(
DateFormat.MMMMEEEEd(locale.languageCode).format(timeDaily[pageIndex]),
style: textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
);
}
Widget _buildPageContent(
BuildContext context,
WeatherCard weatherData,
int index,
) {
final weatherCodeDaily = weatherData.weathercodeDaily?[index];
if (weatherCodeDaily == null) {
return Container();
}
final startIndex = index * 24;
final temperature2MMin = weatherData.temperature2MMin?[index];
final temperature2MMax = weatherData.temperature2MMax?[index];
final apparentTemperatureMin = weatherData.apparentTemperatureMin?[index];
final apparentTemperatureMax = weatherData.apparentTemperatureMax?[index];
final uvIndexMax = weatherData.uvIndexMax?[index];
final windDirection10MDominant =
weatherData.winddirection10MDominant?[index];
final windSpeed10MMax = weatherData.windspeed10MMax?[index];
final windGusts10MMax = weatherData.windgusts10MMax?[index];
final precipitationProbabilityMax =
weatherData.precipitationProbabilityMax?[index];
final rainSum = weatherData.rainSum?[index];
final precipitationSum = weatherData.precipitationSum?[index];
final sunrise = weatherData.sunrise?[index];
final sunset = weatherData.sunset?[index];
if (sunrise == null || sunset == null) {
return Container();
}
return Container(
margin: const EdgeInsets.symmetric(horizontal: 10),
child: ListView(
children: [
_buildNowWidget(
weatherData,
index,
startIndex,
hourOfDay,
sunrise,
sunset,
),
_buildHourlyList(context, weatherData, startIndex, sunrise, sunset),
_buildSunsetSunriseWidget(sunrise, sunset),
_buildHourlyDescContainer(weatherData, startIndex, hourOfDay),
_buildDailyDescContainer(
weatherData,
temperature2MMin,
temperature2MMax,
apparentTemperatureMin,
apparentTemperatureMax,
uvIndexMax,
windDirection10MDominant,
windSpeed10MMax,
windGusts10MMax,
precipitationProbabilityMax,
rainSum,
precipitationSum,
),
],
),
);
}
Widget _buildNowWidget(
WeatherCard weatherData,
int index,
int startIndex,
int hourOfDay,
String sunrise,
String sunset,
) {
final weatherCode = weatherData.weathercode?[startIndex + hourOfDay];
final temperature = weatherData.temperature2M?[startIndex + hourOfDay];
final feels = weatherData.apparentTemperature?[startIndex + hourOfDay];
final time = weatherData.time?[startIndex + hourOfDay];
final tempMax = weatherData.temperature2MMax?[index];
final tempMin = weatherData.temperature2MMin?[index];
if (weatherCode == null ||
temperature == null ||
feels == null ||
time == null ||
tempMax == null ||
tempMin == null) {
return Container();
}
return Now(
weather: weatherCode,
degree: temperature,
feels: feels,
time: time,
timeDay: sunrise,
timeNight: sunset,
tempMax: tempMax,
tempMin: tempMin,
);
}
Widget _buildHourlyList(
BuildContext context,
WeatherCard weatherData,
int startIndex,
String sunrise,
String sunset,
) {
return Card(
margin: const EdgeInsets.only(bottom: 15),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: SizedBox(
height: 135,
child: ScrollablePositionedList.separated(
separatorBuilder: (BuildContext context, int index) {
return const VerticalDivider(
width: 10,
indent: 40,
endIndent: 40,
);
},
scrollDirection: Axis.horizontal,
itemCount: 24,
itemBuilder: (ctx, i) {
return _buildHourlyItem(
context,
weatherData,
startIndex,
i,
sunrise,
sunset,
);
},
),
),
),
);
}
Widget _buildHourlyItem(
BuildContext context,
WeatherCard weatherData,
int startIndex,
int i,
String sunrise,
String sunset,
) {
int hourlyIndex = startIndex + i;
bool isSelected = i == hourOfDay;
final time = weatherData.time?[hourlyIndex];
final weatherCode = weatherData.weathercode?[hourlyIndex];
final temperature = weatherData.temperature2M?[hourlyIndex];
if (time == null || weatherCode == null || temperature == null) {
return Container();
}
return GestureDetector(
onTap: () {
setState(() {
hourOfDay = i;
});
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 5),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
decoration: BoxDecoration(
color: isSelected
? context.theme.colorScheme.secondaryContainer
: Colors.transparent,
borderRadius: const BorderRadius.all(Radius.circular(20)),
),
child: Hourly(
time: time,
weather: weatherCode,
degree: temperature,
timeDay: sunrise,
timeNight: sunset,
),
),
);
}
Widget _buildSunsetSunriseWidget(String sunrise, String sunset) {
return SunsetSunrise(timeSunrise: sunrise, timeSunset: sunset);
}
Widget _buildHourlyDescContainer(
WeatherCard weatherData,
int startIndex,
int hourOfDay,
) {
final hourlyIndex = startIndex + hourOfDay;
return DescContainer(
humidity: weatherData.relativehumidity2M?[hourlyIndex],
wind: weatherData.windspeed10M?[hourlyIndex],
visibility: weatherData.visibility?[hourlyIndex],
feels: weatherData.apparentTemperature?[hourlyIndex],
evaporation: weatherData.evapotranspiration?[hourlyIndex],
precipitation: weatherData.precipitation?[hourlyIndex],
direction: weatherData.winddirection10M?[hourlyIndex],
pressure: weatherData.surfacePressure?[hourlyIndex],
rain: weatherData.rain?[hourlyIndex],
cloudcover: weatherData.cloudcover?[hourlyIndex],
windgusts: weatherData.windgusts10M?[hourlyIndex],
uvIndex: weatherData.uvIndex?[hourlyIndex],
dewpoint2M: weatherData.dewpoint2M?[hourlyIndex],
precipitationProbability:
weatherData.precipitationProbability?[hourlyIndex],
shortwaveRadiation: weatherData.shortwaveRadiation?[hourlyIndex],
initiallyExpanded: true,
title: 'hourlyVariables'.tr,
);
}
Widget _buildDailyDescContainer(
WeatherCard weatherData,
double? temperature2MMin,
double? temperature2MMax,
double? apparentTemperatureMin,
double? apparentTemperatureMax,
double? uvIndexMax,
int? windDirection10MDominant,
double? windSpeed10MMax,
double? windGusts10MMax,
int? precipitationProbabilityMax,
double? rainSum,
double? precipitationSum,
) {
return DescContainer(
apparentTemperatureMin: apparentTemperatureMin,
apparentTemperatureMax: apparentTemperatureMax,
uvIndexMax: uvIndexMax,
windDirection10MDominant: windDirection10MDominant,
windSpeed10MMax: windSpeed10MMax,
windGusts10MMax: windGusts10MMax,
precipitationProbabilityMax: precipitationProbabilityMax,
rainSum: rainSum,
precipitationSum: precipitationSum,
initiallyExpanded: true,
title: 'dailyVariables'.tr,
);
}
}

View file

@ -0,0 +1,84 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax_plus/iconsax_plus.dart';
import 'package:rain/app/data/db.dart';
import 'package:rain/app/ui/widgets/weather/daily/daily_card_info.dart';
import 'package:rain/app/ui/widgets/weather/daily/daily_card.dart';
class DailyCardList extends StatefulWidget {
const DailyCardList({super.key, required this.weatherData});
final WeatherCard weatherData;
@override
State<DailyCardList> createState() => _DailyCardListState();
}
class _DailyCardListState extends State<DailyCardList> {
@override
Widget build(BuildContext context) {
final weatherData = widget.weatherData;
final timeDaily = weatherData.timeDaily ?? [];
return Scaffold(
appBar: _buildAppBar(context),
body: SafeArea(
child: ListView.builder(
itemCount: timeDaily.length,
itemBuilder: (context, index) =>
_buildDailyCardItem(context, weatherData, index),
),
),
);
}
AppBar _buildAppBar(BuildContext context) {
return AppBar(
automaticallyImplyLeading: false,
centerTitle: true,
leading: IconButton(
onPressed: () => Get.back(),
icon: const Icon(IconsaxPlusLinear.arrow_left_3, size: 20),
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
title: Text(
'weatherMore'.tr,
style: context.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
);
}
Widget _buildDailyCardItem(
BuildContext context,
WeatherCard weatherData,
int index,
) {
final timeDaily = weatherData.timeDaily?[index];
final weathercodeDaily = weatherData.weathercodeDaily?[index];
final temperature2MMax = weatherData.temperature2MMax?[index];
final temperature2MMin = weatherData.temperature2MMin?[index];
if (timeDaily == null ||
weathercodeDaily == null ||
temperature2MMax == null ||
temperature2MMin == null) {
return Container();
}
return GestureDetector(
onTap: () => Get.to(
() => DailyCardInfo(weatherData: weatherData, index: index),
transition: Transition.downToUp,
),
child: DailyCard(
timeDaily: timeDaily,
weathercodeDaily: weathercodeDaily,
temperature2MMax: temperature2MMax,
temperature2MMin: temperature2MMin,
),
);
}
}

View file

@ -0,0 +1,206 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:rain/app/data/db.dart';
import 'package:rain/app/ui/widgets/weather/daily/daily_card_info.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';
class DailyContainer extends StatefulWidget {
const DailyContainer({
super.key,
required this.weatherData,
required this.onTap,
});
final WeatherCard weatherData;
final VoidCallback onTap;
@override
State<DailyContainer> createState() => _DailyContainerState();
}
class _DailyContainerState extends State<DailyContainer> {
final statusWeather = StatusWeather();
final statusData = StatusData();
@override
Widget build(BuildContext context) {
final splashColor = context.theme.colorScheme.primary.withValues(
alpha: 0.4,
);
const inkWellBorderRadius = BorderRadius.all(Radius.circular(16));
final weatherData = widget.weatherData;
final weatherCodeDaily = weatherData.weathercodeDaily ?? [];
final textTheme = context.textTheme;
final labelLarge = textTheme.labelLarge;
return Card(
margin: const EdgeInsets.only(bottom: 15),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5),
child: Column(
children: [
_buildDailyListView(
context,
weatherData,
weatherCodeDaily,
labelLarge,
),
const Divider(),
_buildMoreInfoButton(context, splashColor, inkWellBorderRadius),
],
),
),
);
}
Widget _buildDailyListView(
BuildContext context,
WeatherCard weatherData,
List<int?> weatherCodeDaily,
TextStyle? labelLarge,
) {
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: 7,
itemBuilder: (ctx, index) {
return _buildDailyItem(
context,
weatherData,
weatherCodeDaily,
index,
labelLarge,
);
},
);
}
Widget _buildDailyItem(
BuildContext context,
WeatherCard weatherData,
List<int?> weatherCodeDaily,
int index,
TextStyle? labelLarge,
) {
final splashColor = context.theme.colorScheme.primary.withValues(
alpha: 0.4,
);
const inkWellBorderRadius = BorderRadius.all(Radius.circular(16));
return InkWell(
splashColor: splashColor,
borderRadius: inkWellBorderRadius,
onTap: () => Get.to(
() => DailyCardInfo(weatherData: weatherData, index: index),
transition: Transition.downToUp,
),
child: Container(
margin: const EdgeInsets.symmetric(vertical: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_buildDayText(weatherData, index, labelLarge),
_buildWeatherInfo(weatherCodeDaily, index, labelLarge),
_buildTemperatureRange(weatherData, index, labelLarge),
],
),
),
);
}
Widget _buildDayText(
WeatherCard weatherData,
int index,
TextStyle? labelLarge,
) {
return Expanded(
child: Text(
DateFormat.EEEE(
locale.languageCode,
).format((weatherData.timeDaily ?? [])[index]),
style: labelLarge,
overflow: TextOverflow.ellipsis,
),
);
}
Widget _buildWeatherInfo(
List<int?> weatherCodeDaily,
int index,
TextStyle? labelLarge,
) {
final weatherCode = weatherCodeDaily[index];
if (weatherCode == null) {
return const Expanded(child: SizedBox.shrink());
}
return Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(statusWeather.getImage7Day(weatherCode), scale: 3),
const Gap(5),
Expanded(
child: Text(
statusWeather.getText(weatherCode),
style: labelLarge,
overflow: TextOverflow.ellipsis,
),
),
],
),
);
}
Widget _buildTemperatureRange(
WeatherCard weatherData,
int index,
TextStyle? labelLarge,
) {
return Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
statusData.getDegree(
(weatherData.temperature2MMax ?? [])[index]?.round(),
),
style: labelLarge,
),
Text(' / ', style: labelLarge),
Text(
statusData.getDegree(
(weatherData.temperature2MMin ?? [])[index]?.round(),
),
style: labelLarge,
),
],
),
);
}
Widget _buildMoreInfoButton(
BuildContext context,
Color splashColor,
BorderRadius inkWellBorderRadius,
) {
return InkWell(
splashColor: splashColor,
borderRadius: inkWellBorderRadius,
onTap: widget.onTap,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Text(
'weatherMore'.tr,
style: context.textTheme.titleMedium,
overflow: TextOverflow.ellipsis,
),
),
);
}
}

View file

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
class DescWeather extends StatefulWidget { class DescWeather extends StatefulWidget {
@ -9,6 +10,7 @@ class DescWeather extends StatefulWidget {
required this.desc, required this.desc,
this.message = '', this.message = '',
}); });
final String imageName; final String imageName;
final String value; final String value;
final String desc; final String desc;
@ -25,36 +27,42 @@ class _DescWeatherState extends State<DescWeather> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final textTheme = context.textTheme; final textTheme = context.textTheme;
return GestureDetector( return GestureDetector(
onTap: () => setState(() => hide = !hide), onTap: _toggleDescriptionVisibility,
child: Tooltip( child: Tooltip(
message: widget.message, message: widget.message,
child: SizedBox( child: SizedBox(
height: 90, height: 90,
width: 100, width: 100,
child: Column( child: _buildContent(textTheme),
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
widget.imageName,
scale: 20,
),
const SizedBox(height: 5),
Text(
widget.value,
style: textTheme.labelLarge,
),
Expanded(
child: Text(
widget.desc,
style: textTheme.bodySmall,
overflow: hide ? TextOverflow.ellipsis : TextOverflow.visible,
textAlign: TextAlign.center,
),
),
],
),
), ),
), ),
); );
} }
void _toggleDescriptionVisibility() {
setState(() => hide = !hide);
}
Widget _buildContent(TextTheme textTheme) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(widget.imageName, scale: 20),
const Gap(5),
Text(
widget.value,
style: textTheme.labelLarge,
overflow: TextOverflow.ellipsis,
),
Expanded(
child: Text(
widget.desc,
style: textTheme.bodySmall,
overflow: hide ? TextOverflow.ellipsis : TextOverflow.visible,
textAlign: TextAlign.center,
),
),
],
);
}
} }

View file

@ -0,0 +1,263 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:rain/app/ui/widgets/weather/desc/desc.dart';
import 'package:rain/app/ui/widgets/weather/desc/message.dart';
import 'package:rain/app/ui/widgets/weather/status/status_data.dart';
class DescContainer extends StatefulWidget {
const DescContainer({
super.key,
this.humidity,
this.wind,
this.visibility,
this.feels,
this.evaporation,
this.precipitation,
this.direction,
this.pressure,
this.rain,
this.cloudcover,
this.windgusts,
this.uvIndex,
this.dewpoint2M,
this.precipitationProbability,
this.shortwaveRadiation,
this.apparentTemperatureMin,
this.apparentTemperatureMax,
this.uvIndexMax,
this.windDirection10MDominant,
this.windSpeed10MMax,
this.windGusts10MMax,
this.precipitationProbabilityMax,
this.rainSum,
this.precipitationSum,
required this.initiallyExpanded,
required this.title,
});
final int? humidity;
final double? wind;
final double? visibility;
final double? feels;
final double? evaporation;
final double? precipitation;
final int? direction;
final double? pressure;
final double? rain;
final int? cloudcover;
final double? windgusts;
final double? uvIndex;
final double? dewpoint2M;
final int? precipitationProbability;
final double? shortwaveRadiation;
final double? apparentTemperatureMin;
final double? apparentTemperatureMax;
final double? uvIndexMax;
final int? windDirection10MDominant;
final double? windSpeed10MMax;
final double? windGusts10MMax;
final int? precipitationProbabilityMax;
final double? rainSum;
final double? precipitationSum;
final bool initiallyExpanded;
final String title;
@override
State<DescContainer> createState() => _DescContainerState();
}
class _DescContainerState extends State<DescContainer> {
final statusData = StatusData();
final message = Message();
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(bottom: 15),
child: ExpansionTile(
shape: const Border(),
title: Text(widget.title, style: context.textTheme.labelLarge),
initiallyExpanded: widget.initiallyExpanded,
children: [
Padding(
padding: const EdgeInsets.only(top: 20, bottom: 5),
child: Wrap(
alignment: WrapAlignment.spaceEvenly,
spacing: 5,
children: _buildWeatherDescriptions(context),
),
),
],
),
);
}
List<Widget> _buildWeatherDescriptions(BuildContext context) {
final List<Widget> descriptions = [];
void addDescriptionIfNotNull({
required dynamic value,
required String imageName,
required String desc,
String? message,
}) {
if (value != null &&
value != '' &&
value != 'null°C' &&
value != 'null°F' &&
value != 'null°' &&
value != 'null%' &&
value != 'null ${'W/m2'.tr}') {
descriptions.add(
DescWeather(
imageName: imageName,
value: value.toString(),
desc: desc,
message: message ?? '',
),
);
} else {
descriptions.add(Container());
}
}
final weatherData = [
{
'value': statusData.getDegree(widget.apparentTemperatureMin?.round()),
'imageName': 'assets/images/cold.png',
'desc': 'apparentTemperatureMin'.tr,
},
{
'value': statusData.getDegree(widget.apparentTemperatureMax?.round()),
'imageName': 'assets/images/hot.png',
'desc': 'apparentTemperatureMax'.tr,
},
{
'value': widget.uvIndexMax?.round(),
'imageName': 'assets/images/uv.png',
'desc': 'uvIndex'.tr,
'message': message.getUvIndex(widget.uvIndexMax?.round()),
},
{
'value': '${widget.windDirection10MDominant}°',
'imageName': 'assets/images/windsock.png',
'desc': 'direction'.tr,
'message': message.getDirection(widget.windDirection10MDominant),
},
{
'value': statusData.getSpeed(widget.windSpeed10MMax?.round()),
'imageName': 'assets/images/wind.png',
'desc': 'wind'.tr,
},
{
'value': statusData.getSpeed(widget.windGusts10MMax?.round()),
'imageName': 'assets/images/windgusts.png',
'desc': 'windgusts'.tr,
},
{
'value': '${widget.precipitationProbabilityMax}%',
'imageName': 'assets/images/precipitation_probability.png',
'desc': 'precipitationProbability'.tr,
},
{
'value': statusData.getPrecipitation(widget.rainSum),
'imageName': 'assets/images/water.png',
'desc': 'rain'.tr,
},
{
'value': statusData.getPrecipitation(widget.precipitationSum),
'imageName': 'assets/images/rainfall.png',
'desc': 'precipitation'.tr,
},
{
'value': statusData.getDegree(widget.dewpoint2M?.round()),
'imageName': 'assets/images/dew.png',
'desc': 'dewpoint'.tr,
},
{
'value': statusData.getDegree(widget.feels?.round()),
'imageName': 'assets/images/temperature.png',
'desc': 'feels'.tr,
},
{
'value': statusData.getVisibility(widget.visibility),
'imageName': 'assets/images/fog.png',
'desc': 'visibility'.tr,
},
{
'value': '${widget.direction}°',
'imageName': 'assets/images/windsock.png',
'desc': 'direction'.tr,
'message': message.getDirection(widget.direction),
},
{
'value': statusData.getSpeed(widget.wind?.round()),
'imageName': 'assets/images/wind.png',
'desc': 'wind'.tr,
},
{
'value': statusData.getSpeed(widget.windgusts?.round()),
'imageName': 'assets/images/windgusts.png',
'desc': 'windgusts'.tr,
},
{
'value': statusData.getPrecipitation(widget.evaporation?.abs()),
'imageName': 'assets/images/evaporation.png',
'desc': 'evaporation'.tr,
},
{
'value': statusData.getPrecipitation(widget.precipitation),
'imageName': 'assets/images/rainfall.png',
'desc': 'precipitation'.tr,
},
{
'value': statusData.getPrecipitation(widget.rain),
'imageName': 'assets/images/water.png',
'desc': 'rain'.tr,
},
{
'value': '${widget.precipitationProbability}%',
'imageName': 'assets/images/precipitation_probability.png',
'desc': 'precipitationProbability'.tr,
},
{
'value': '${widget.humidity}%',
'imageName': 'assets/images/humidity.png',
'desc': 'humidity'.tr,
},
{
'value': '${widget.cloudcover}%',
'imageName': 'assets/images/cloudy.png',
'desc': 'cloudcover'.tr,
},
{
'value': statusData.getPressure(widget.pressure?.round()),
'imageName': 'assets/images/atmospheric.png',
'desc': 'pressure'.tr,
'message': message.getPressure(widget.pressure?.round()),
},
{
'value': widget.uvIndex?.round(),
'imageName': 'assets/images/uv.png',
'desc': 'uvIndex'.tr,
'message': message.getUvIndex(widget.uvIndex?.round()),
},
{
'value': '${widget.shortwaveRadiation?.round()} ${'W/m2'.tr}',
'imageName': 'assets/images/shortwave_radiation.png',
'desc': 'shortwaveRadiation'.tr,
},
];
for (var data in weatherData) {
addDescriptionIfNotNull(
value: data['value'],
imageName: '${data['imageName']}',
desc: '${data['desc']}',
message: '${data['message']}',
);
}
return descriptions;
}
}

View file

@ -0,0 +1,65 @@
import 'package:get/get.dart';
class Message {
String getPressure(int? pressure) {
return _getPressureDescription(pressure);
}
String getUvIndex(int? uvIndex) {
return _getUvIndexDescription(uvIndex);
}
String getDirection(int? direction) {
return _getDirectionDescription(direction);
}
String _getPressureDescription(int? pressure) {
if (pressure == null) return '';
if (pressure < 1000) {
return 'low'.tr;
} else if (pressure > 1020) {
return 'high'.tr;
} else {
return 'normal'.tr;
}
}
String _getUvIndexDescription(int? uvIndex) {
if (uvIndex == null) return '';
if (uvIndex < 3) {
return 'uvLow'.tr;
} else if (uvIndex < 6) {
return 'uvAverage'.tr;
} else if (uvIndex < 8) {
return 'uvHigh'.tr;
} else if (uvIndex < 11) {
return 'uvVeryHigh'.tr;
} else {
return 'uvExtreme'.tr;
}
}
String _getDirectionDescription(int? direction) {
if (direction == null) return '';
if (direction >= 337.5 || direction < 22.5) {
return 'north'.tr;
} else if (direction >= 22.5 && direction < 67.5) {
return 'northeast'.tr;
} else if (direction >= 67.5 && direction < 112.5) {
return 'east'.tr;
} else if (direction >= 112.5 && direction < 157.5) {
return 'southeast'.tr;
} else if (direction >= 157.5 && direction < 202.5) {
return 'south'.tr;
} else if (direction >= 202.5 && direction < 247.5) {
return 'southwest'.tr;
} else if (direction >= 247.5 && direction < 292.5) {
return 'west'.tr;
} else {
return 'northwest'.tr;
}
}
}

View file

@ -0,0 +1,77 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.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';
class Hourly extends StatefulWidget {
const Hourly({
super.key,
required this.time,
required this.weather,
required this.degree,
required this.timeDay,
required this.timeNight,
});
final String time;
final String timeDay;
final String timeNight;
final int weather;
final double degree;
@override
State<Hourly> createState() => _HourlyState();
}
class _HourlyState extends State<Hourly> {
final statusWeather = StatusWeather();
final statusData = StatusData();
@override
Widget build(BuildContext context) {
final textTheme = context.textTheme;
final time = widget.time;
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildTimeText(textTheme, time),
_buildWeatherImage(),
_buildTemperatureText(textTheme),
],
);
}
Widget _buildTimeText(TextTheme textTheme, String time) {
return Column(
children: [
Text(statusData.getTimeFormat(time), style: textTheme.labelLarge),
Text(
DateFormat('E', locale.languageCode).format(DateTime.tryParse(time)!),
style: textTheme.labelLarge?.copyWith(color: Colors.grey),
),
],
);
}
Widget _buildWeatherImage() {
return Image.asset(
statusWeather.getImageToday(
widget.weather,
widget.time,
widget.timeDay,
widget.timeNight,
),
scale: 3,
);
}
Widget _buildTemperatureText(TextTheme textTheme) {
return Text(
statusData.getDegree(widget.degree.round()),
style: textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600),
);
}
}

View file

@ -0,0 +1,182 @@
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:get/get.dart';
import 'package:intl/intl.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';
class Now extends StatefulWidget {
const Now({
super.key,
required this.weather,
required this.degree,
required this.time,
required this.timeDay,
required this.timeNight,
required this.tempMax,
required this.tempMin,
required this.feels,
});
final String time;
final String timeDay;
final String timeNight;
final int weather;
final double degree;
final double tempMax;
final double tempMin;
final double feels;
@override
State<Now> createState() => _NowState();
}
class _NowState extends State<Now> {
final statusWeather = StatusWeather();
final statusData = StatusData();
@override
Widget build(BuildContext context) {
return largeElement
? _buildLargeElementLayout(context)
: _buildCompactElementLayout(context);
}
Widget _buildLargeElementLayout(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 15),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Gap(15),
_buildWeatherImage(200),
_buildTemperatureText(context, widget.degree, 90),
Text(
statusWeather.getText(widget.weather),
style: context.textTheme.titleLarge,
),
const Gap(5),
_buildDateText(context),
],
),
);
}
Widget _buildCompactElementLayout(BuildContext context) {
return Card(
margin: const EdgeInsets.only(bottom: 15),
child: Padding(
padding: const EdgeInsets.only(
top: 18,
bottom: 18,
left: 25,
right: 15,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildDateText(context),
const Gap(5),
Text(
statusWeather.getText(widget.weather),
style: context.textTheme.titleLarge?.copyWith(fontSize: 20),
),
_buildFeelsLikeText(context),
const Gap(30),
_buildTemperatureCompactText(context, widget.degree),
const Gap(5),
_buildMinMaxTemperatureText(context),
],
),
),
_buildWeatherImage(140),
],
),
),
);
}
Widget _buildWeatherImage(double height) {
return Image(
image: AssetImage(
statusWeather.getImageNow(
widget.weather,
widget.time,
widget.timeDay,
widget.timeNight,
),
),
fit: BoxFit.fill,
height: height,
);
}
Widget _buildTemperatureText(
BuildContext context,
double degree,
double? fontSize,
) {
return Text(
'${roundDegree ? degree.round() : degree}',
style: context.textTheme.displayLarge?.copyWith(
fontSize: fontSize,
fontWeight: FontWeight.w800,
shadows: const [Shadow(blurRadius: 15, offset: Offset(5, 5))],
),
);
}
Widget _buildTemperatureCompactText(BuildContext context, double degree) {
return Text(
statusData.getDegree(roundDegree ? widget.degree.round() : widget.degree),
style: context.textTheme.displayMedium?.copyWith(
fontWeight: FontWeight.w800,
),
);
}
Widget _buildDateText(BuildContext context) {
return Text(
DateFormat.MMMMEEEEd(
locale.languageCode,
).format(DateTime.parse(widget.time)),
style: context.textTheme.labelLarge?.copyWith(color: Colors.grey),
);
}
Widget _buildFeelsLikeText(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('feels'.tr, style: context.textTheme.bodyMedium),
Text('', style: context.textTheme.bodyMedium),
Text(
statusData.getDegree(widget.feels.round()),
style: context.textTheme.bodyMedium,
),
],
);
}
Widget _buildMinMaxTemperatureText(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
statusData.getDegree((widget.tempMin.round())),
style: context.textTheme.labelLarge,
),
Text(' / ', style: context.textTheme.labelLarge),
Text(
statusData.getDegree((widget.tempMax.round())),
style: context.textTheme.labelLarge,
),
],
);
}
}

View file

@ -0,0 +1,127 @@
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:rain/main.dart';
import 'package:timezone/timezone.dart';
class StatusData {
String getDegree(dynamic degree) {
return _formatDegree(degree);
}
String getSpeed(int? speed) {
return _formatSpeed(speed);
}
String getPressure(int? pressure) {
return _formatPressure(pressure);
}
String getVisibility(double? length) {
return _formatVisibility(length);
}
String getPrecipitation(double? precipitation) {
return _formatPrecipitation(precipitation);
}
String getTimeFormat(String time) {
return _formatTime(time);
}
String getTimeFormatTz(TZDateTime time) {
return _formatTimeTz(time);
}
String _formatDegree(dynamic degree) {
switch (settings.degrees) {
case 'celsius':
return '$degree°C';
case 'fahrenheit':
return '$degree°F';
default:
return '$degree°C';
}
}
String _formatSpeed(int? speed) {
if (speed == null) return '';
switch (settings.measurements) {
case 'metric':
return settings.wind == 'm/s'
? '${(speed * (5 / 18)).toPrecision(1)} ${'m/s'.tr}'
: '$speed ${'kph'.tr}';
case 'imperial':
return '$speed ${'mph'.tr}';
default:
return '$speed ${'kph'.tr}';
}
}
String _formatPressure(int? pressure) {
if (pressure == null) return '';
return settings.pressure == 'mmHg'
? '${(pressure * (3 / 4)).toPrecision(1)} ${'mmHg'.tr}'
: '$pressure ${'hPa'.tr}';
}
String _formatVisibility(double? length) {
if (length == null) return '';
switch (settings.measurements) {
case 'metric':
return _formatMetricVisibility(length);
case 'imperial':
return _formatImperialVisibility(length);
default:
return _formatMetricVisibility(length);
}
}
String _formatMetricVisibility(double length) {
return '${length > 1000 ? (length / 1000).round() : (length / 1000).toStringAsFixed(2)} ${'km'.tr}';
}
String _formatImperialVisibility(double length) {
return '${length > 5280 ? (length / 5280).round() : (length / 5280).toStringAsFixed(2)} ${'mi'.tr}';
}
String _formatPrecipitation(double? precipitation) {
if (precipitation == null) return '';
switch (settings.measurements) {
case 'metric':
return '$precipitation ${'mm'.tr}';
case 'imperial':
return '$precipitation ${'inch'.tr}';
default:
return '$precipitation ${'mm'.tr}';
}
}
String _formatTime(String time) {
final parsedTime = DateTime.tryParse(time);
if (parsedTime == null) return '';
switch (settings.timeformat) {
case '12':
return DateFormat.jm(locale.languageCode).format(parsedTime);
case '24':
return DateFormat.Hm(locale.languageCode).format(parsedTime);
default:
return DateFormat.Hm(locale.languageCode).format(parsedTime);
}
}
String _formatTimeTz(TZDateTime time) {
switch (settings.timeformat) {
case '12':
return DateFormat.jm(locale.languageCode).format(time);
case '24':
return DateFormat.Hm(locale.languageCode).format(time);
default:
return DateFormat.Hm(locale.languageCode).format(time);
}
}
}

View file

@ -0,0 +1,385 @@
import 'package:get/get.dart';
const assetImageRoot = 'assets/images/';
class StatusWeather {
String getImageNow(
int weather,
String time,
String timeDay,
String timeNight,
) {
return _getImageBasedOnTime(
weather,
time,
timeDay,
timeNight,
_getDayNightImagePaths,
);
}
String getImageNowDaily(int? weather) {
return _getDailyImage(weather);
}
String getImageToday(
int weather,
String time,
String timeDay,
String timeNight,
) {
return _getImageBasedOnTime(
weather,
time,
timeDay,
timeNight,
_getTodayImagePaths,
);
}
String getImage7Day(int? weather) {
return _getDailyImage(weather, isDay: true);
}
String getText(int? weather) {
return _getWeatherText(weather);
}
String getImageNotification(
int weather,
String time,
String timeDay,
String timeNight,
) {
return _getImageBasedOnTime(
weather,
time,
timeDay,
timeNight,
_getNotificationImagePaths,
);
}
String _getImageBasedOnTime(
int weather,
String time,
String timeDay,
String timeNight,
Map<int, Map<bool, String>> imagePaths,
) {
final currentTime = DateTime.parse(time);
final day = DateTime.parse(timeDay);
final night = DateTime.parse(timeNight);
final dayTime = DateTime(
day.year,
day.month,
day.day,
day.hour,
day.minute,
);
final nightTime = DateTime(
night.year,
night.month,
night.day,
night.hour,
night.minute,
);
final isDayTime =
currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime);
return imagePaths[weather]?[isDayTime] ?? '';
}
String _getDailyImage(int? weather, {bool isDay = false}) {
switch (weather) {
case 0:
return '$assetImageRoot${isDay ? 'clear_day' : 'sun'}.png';
case 1:
case 2:
case 3:
return '$assetImageRoot${isDay ? 'cloudy_day' : 'cloud'}.png';
case 45:
case 48:
return '${assetImageRoot}fog${isDay ? '_day' : ''}.png';
case 51:
case 53:
case 55:
case 56:
case 57:
case 61:
case 63:
case 65:
case 66:
case 67:
case 80:
case 81:
case 82:
return '${assetImageRoot}rain${isDay ? '_day' : ''}.png';
case 71:
case 73:
case 75:
case 77:
case 85:
case 86:
return '${assetImageRoot}snow${isDay ? '_day' : ''}.png';
case 95:
case 96:
case 99:
return '${assetImageRoot}thunder${isDay ? '_day' : ''}.png';
default:
return '';
}
}
String _getWeatherText(int? weather) {
switch (weather) {
case 0:
return 'clear_sky'.tr;
case 1:
case 2:
return 'cloudy'.tr;
case 3:
return 'overcast'.tr;
case 45:
case 48:
return 'fog'.tr;
case 51:
case 53:
case 55:
return 'drizzle'.tr;
case 56:
case 57:
return 'drizzling_rain'.tr;
case 61:
case 63:
case 65:
return 'rain'.tr;
case 66:
case 67:
return 'freezing_rain'.tr;
case 80:
case 81:
case 82:
return 'heavy_rains'.tr;
case 71:
case 73:
case 75:
case 77:
case 85:
case 86:
return 'snow'.tr;
case 95:
case 96:
case 99:
return 'thunderstorm'.tr;
default:
return '';
}
}
final Map<int, Map<bool, String>> _getDayNightImagePaths = {
0: {
true: '${assetImageRoot}sun.png',
false: '${assetImageRoot}full-moon.png',
},
1: {true: '${assetImageRoot}cloud.png', false: '${assetImageRoot}moon.png'},
2: {true: '${assetImageRoot}cloud.png', false: '${assetImageRoot}moon.png'},
3: {true: '${assetImageRoot}cloud.png', false: '${assetImageRoot}moon.png'},
45: {
true: '${assetImageRoot}fog.png',
false: '${assetImageRoot}fog_moon.png',
},
48: {
true: '${assetImageRoot}fog.png',
false: '${assetImageRoot}fog_moon.png',
},
51: {true: '${assetImageRoot}rain.png', false: '${assetImageRoot}rain.png'},
53: {true: '${assetImageRoot}rain.png', false: '${assetImageRoot}rain.png'},
55: {true: '${assetImageRoot}rain.png', false: '${assetImageRoot}rain.png'},
56: {true: '${assetImageRoot}rain.png', false: '${assetImageRoot}rain.png'},
57: {true: '${assetImageRoot}rain.png', false: '${assetImageRoot}rain.png'},
61: {true: '${assetImageRoot}rain.png', false: '${assetImageRoot}rain.png'},
63: {true: '${assetImageRoot}rain.png', false: '${assetImageRoot}rain.png'},
65: {true: '${assetImageRoot}rain.png', false: '${assetImageRoot}rain.png'},
66: {true: '${assetImageRoot}rain.png', false: '${assetImageRoot}rain.png'},
67: {true: '${assetImageRoot}rain.png', false: '${assetImageRoot}rain.png'},
80: {
true: '${assetImageRoot}rain-fall.png',
false: '${assetImageRoot}rain-fall.png',
},
81: {
true: '${assetImageRoot}rain-fall.png',
false: '${assetImageRoot}rain-fall.png',
},
82: {
true: '${assetImageRoot}rain-fall.png',
false: '${assetImageRoot}rain-fall.png',
},
71: {true: '${assetImageRoot}snow.png', false: '${assetImageRoot}snow.png'},
73: {true: '${assetImageRoot}snow.png', false: '${assetImageRoot}snow.png'},
75: {true: '${assetImageRoot}snow.png', false: '${assetImageRoot}snow.png'},
77: {true: '${assetImageRoot}snow.png', false: '${assetImageRoot}snow.png'},
85: {true: '${assetImageRoot}snow.png', false: '${assetImageRoot}snow.png'},
86: {true: '${assetImageRoot}snow.png', false: '${assetImageRoot}snow.png'},
95: {
true: '${assetImageRoot}thunder.png',
false: '${assetImageRoot}thunder.png',
},
96: {
true: '${assetImageRoot}storm.png',
false: '${assetImageRoot}storm.png',
},
99: {
true: '${assetImageRoot}storm.png',
false: '${assetImageRoot}storm.png',
},
};
final Map<int, Map<bool, String>> _getTodayImagePaths = {
0: {
true: '${assetImageRoot}clear_day.png',
false: '${assetImageRoot}clear_night.png',
},
1: {
true: '${assetImageRoot}cloudy_day.png',
false: '${assetImageRoot}cloudy_night.png',
},
2: {
true: '${assetImageRoot}cloudy_day.png',
false: '${assetImageRoot}cloudy_night.png',
},
3: {
true: '${assetImageRoot}cloudy_day.png',
false: '${assetImageRoot}cloudy_night.png',
},
45: {
true: '${assetImageRoot}fog_day.png',
false: '${assetImageRoot}fog_night.png',
},
48: {
true: '${assetImageRoot}fog_day.png',
false: '${assetImageRoot}fog_night.png',
},
51: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
53: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
55: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
56: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
57: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
61: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
63: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
65: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
66: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
67: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
80: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
81: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
82: {
true: '${assetImageRoot}rain_day.png',
false: '${assetImageRoot}rain_night.png',
},
71: {
true: '${assetImageRoot}snow_day.png',
false: '${assetImageRoot}snow_night.png',
},
73: {
true: '${assetImageRoot}snow_day.png',
false: '${assetImageRoot}snow_night.png',
},
75: {
true: '${assetImageRoot}snow_day.png',
false: '${assetImageRoot}snow_night.png',
},
77: {
true: '${assetImageRoot}snow_day.png',
false: '${assetImageRoot}snow_night.png',
},
85: {
true: '${assetImageRoot}snow_day.png',
false: '${assetImageRoot}snow_night.png',
},
86: {
true: '${assetImageRoot}snow_day.png',
false: '${assetImageRoot}snow_night.png',
},
95: {
true: '${assetImageRoot}thunder_day.png',
false: '${assetImageRoot}thunder_night.png',
},
96: {
true: '${assetImageRoot}thunder_day.png',
false: '${assetImageRoot}thunder_night.png',
},
99: {
true: '${assetImageRoot}thunder_day.png',
false: '${assetImageRoot}thunder_night.png',
},
};
final Map<int, Map<bool, String>> _getNotificationImagePaths = {
0: {true: 'sun.png', false: 'full-moon.png'},
1: {true: 'cloud.png', false: 'moon.png'},
2: {true: 'cloud.png', false: 'moon.png'},
3: {true: 'cloud.png', false: 'moon.png'},
45: {true: 'fog.png', false: 'fog_moon.png'},
48: {true: 'fog.png', false: 'fog_moon.png'},
51: {true: 'rain.png', false: 'rain.png'},
53: {true: 'rain.png', false: 'rain.png'},
55: {true: 'rain.png', false: 'rain.png'},
56: {true: 'rain.png', false: 'rain.png'},
57: {true: 'rain.png', false: 'rain.png'},
61: {true: 'rain.png', false: 'rain.png'},
63: {true: 'rain.png', false: 'rain.png'},
65: {true: 'rain.png', false: 'rain.png'},
66: {true: 'rain.png', false: 'rain.png'},
67: {true: 'rain.png', false: 'rain.png'},
80: {true: 'rain-fall.png', false: 'rain-fall.png'},
81: {true: 'rain-fall.png', false: 'rain-fall.png'},
82: {true: 'rain-fall.png', false: 'rain-fall.png'},
71: {true: 'snow.png', false: 'snow.png'},
73: {true: 'snow.png', false: 'snow.png'},
75: {true: 'snow.png', false: 'snow.png'},
77: {true: 'snow.png', false: 'snow.png'},
85: {true: 'snow.png', false: 'snow.png'},
86: {true: 'snow.png', false: 'snow.png'},
95: {true: 'thunder.png', false: 'thunder.png'},
96: {true: 'storm.png', false: 'storm.png'},
99: {true: 'storm.png', false: 'storm.png'},
};
}

View file

@ -0,0 +1,85 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:gap/gap.dart';
import 'package:rain/app/ui/widgets/weather/status/status_data.dart';
class SunsetSunrise extends StatefulWidget {
const SunsetSunrise({
super.key,
required this.timeSunrise,
required this.timeSunset,
});
final String timeSunrise;
final String timeSunset;
@override
State<SunsetSunrise> createState() => _SunsetSunriseState();
}
class _SunsetSunriseState extends State<SunsetSunrise> {
final statusData = StatusData();
@override
Widget build(BuildContext context) {
final textTheme = context.textTheme;
final titleSmall = textTheme.titleSmall;
final titleLarge = textTheme.titleLarge;
return Card(
margin: const EdgeInsets.only(bottom: 15),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
child: Row(
children: [
_buildSunTimeColumn(
context,
'sunrise'.tr,
statusData.getTimeFormat(widget.timeSunrise),
'assets/images/sunrise.png',
titleSmall,
titleLarge,
),
_buildSunTimeColumn(
context,
'sunset'.tr,
statusData.getTimeFormat(widget.timeSunset),
'assets/images/sunset.png',
titleSmall,
titleLarge,
),
],
),
),
);
}
Widget _buildSunTimeColumn(
BuildContext context,
String label,
String time,
String imagePath,
TextStyle? labelStyle,
TextStyle? timeStyle,
) {
return Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: labelStyle, overflow: TextOverflow.ellipsis),
const Gap(2),
Text(time, style: timeStyle),
],
),
),
const Gap(5),
Flexible(child: Image.asset(imagePath, scale: 10)),
],
),
);
}
}

View file

@ -0,0 +1,26 @@
import 'dart:ui';
extension HexColor on Color {
/// String is in the format "aabbcc" or "ffaabbcc" with an optional leading "#".
static Color fromHex(String hexString) {
final buffer = StringBuffer();
if (hexString.length == 6 || hexString.length == 7) buffer.write('ff');
buffer.write(hexString.replaceFirst('#', ''));
return Color(int.parse(buffer.toString(), radix: 16));
}
/// Prefixes a hash sign if [leadingHashSign] is set to `true` (default is `true`).
String toHex({bool leadingHashSign = true}) {
final argb = toARGB32(); // Get 32-bit integer representation
final a = (argb >> 24) & 0xFF;
final r = (argb >> 16) & 0xFF;
final g = (argb >> 8) & 0xFF;
final b = argb & 0xFF;
return '${leadingHashSign ? '#' : ''}'
'${a.toRadixString(16).padLeft(2, '0')}'
'${r.toRadixString(16).padLeft(2, '0')}'
'${g.toRadixString(16).padLeft(2, '0')}'
'${b.toRadixString(16).padLeft(2, '0')}';
}
}

31
lib/app/utils/device_info.dart Executable file
View file

@ -0,0 +1,31 @@
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
class DeviceFeature {
DeviceFeature._internal();
static final DeviceFeature _singleton = DeviceFeature._internal();
factory DeviceFeature() {
return _singleton;
}
final _deviceInfoPlugin = DeviceInfoPlugin();
AndroidDeviceInfo? _androidDeviceInfo;
Future<void> init() async {
try {
_androidDeviceInfo = await _deviceInfoPlugin.androidInfo;
} catch (e) {
if (kDebugMode) {
print('Error initializing device info: $e');
}
}
}
bool isEdgeToEdgeAvailable() {
return _androidDeviceInfo != null &&
_androidDeviceInfo!.version.sdkInt > 28;
}
}

58
lib/app/utils/notification.dart Executable file
View file

@ -0,0 +1,58 @@
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:rain/app/controller/controller.dart';
import 'package:rain/main.dart';
import 'package:timezone/timezone.dart' as tz;
class NotificationShow {
static const String _channelId = 'Rain';
static const String _channelName = 'DARK NIGHT';
Future<void> showNotification(
int id,
String title,
String body,
DateTime date,
String icon,
) async {
try {
final imagePath = await _getLocalImagePath(icon);
final notificationDetails = await _buildNotificationDetails(imagePath);
final scheduledTime = _getScheduledTime(date);
await flutterLocalNotificationsPlugin.zonedSchedule(
id,
title,
body,
scheduledTime,
notificationDetails,
androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle,
payload: imagePath,
);
} catch (e) {
print('Error showing notification: $e');
}
}
Future<String> _getLocalImagePath(String icon) async {
return await WeatherController().getLocalImagePath(icon);
}
Future<NotificationDetails> _buildNotificationDetails(
String imagePath,
) async {
final androidNotificationDetails = AndroidNotificationDetails(
_channelId,
_channelName,
priority: Priority.high,
importance: Importance.max,
playSound: false,
enableVibration: false,
largeIcon: FilePathAndroidBitmap(imagePath),
);
return NotificationDetails(android: androidNotificationDetails);
}
tz.TZDateTime _getScheduledTime(DateTime date) {
return tz.TZDateTime.from(date, tz.local);
}
}

View file

@ -0,0 +1,17 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
final GlobalKey<ScaffoldMessengerState> globalKey =
GlobalKey<ScaffoldMessengerState>();
void showSnackBar({required String content, VoidCallback? onPressed}) {
globalKey.currentState?.showSnackBar(
SnackBar(
content: Text(content),
action:
onPressed != null
? SnackBarAction(label: 'settings'.tr, onPressed: onPressed)
: null,
),
);
}

View file

@ -1,27 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class MyTextButton extends StatelessWidget {
const MyTextButton({
super.key,
required this.buttonName,
required this.onPressed,
});
final String buttonName;
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
return SizedBox(
height: 50,
width: double.infinity,
child: ElevatedButton(
onPressed: onPressed,
child: Text(
buttonName,
style: context.textTheme.titleMedium,
),
),
);
}
}

View file

@ -1,248 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax/iconsax.dart';
import 'package:intl/intl.dart';
import 'package:rain/app/data/weather.dart';
import 'package:rain/app/widgets/desc/desc_container.dart';
import 'package:rain/app/widgets/desc/message.dart';
import 'package:rain/app/widgets/hourly/weather_hourly.dart';
import 'package:rain/app/widgets/now/weather_now.dart';
import 'package:rain/app/widgets/status/status_data.dart';
import 'package:rain/app/widgets/status/status_weather.dart';
import 'package:rain/app/widgets/sun_moon/sunset_sunrise.dart';
import 'package:rain/main.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
class InfoDailyCard extends StatefulWidget {
const InfoDailyCard({
super.key,
required this.weatherData,
required this.index,
});
final WeatherCard weatherData;
final int index;
@override
State<InfoDailyCard> createState() => _InfoDailyCardState();
}
class _InfoDailyCardState extends State<InfoDailyCard> {
final statusWeather = StatusWeather();
final statusData = StatusData();
final message = Message();
late PageController pageController;
int pageIndex = 0;
int hourOfDay = 0;
@override
void initState() {
pageController = PageController(initialPage: widget.index);
pageIndex = widget.index;
super.initState();
}
@override
void dispose() {
pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final weatherData = widget.weatherData;
final timeDaily = weatherData.timeDaily ?? [];
final weatherCodeDaily = weatherData.weathercodeDaily ?? [];
final textTheme = context.textTheme;
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
centerTitle: true,
leading: IconButton(
onPressed: () {
Get.back();
},
icon: const Icon(
Iconsax.arrow_left_1,
size: 20,
),
splashColor: Colors.transparent,
highlightColor: Colors.transparent,
),
title: Text(
DateFormat.MMMMEEEEd(locale.languageCode)
.format(timeDaily[pageIndex]),
style: textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
),
body: SafeArea(
child: PageView.builder(
controller: pageController,
onPageChanged: (index) {
setState(() {
pageIndex = index;
hourOfDay = 0;
});
},
itemCount: timeDaily.length,
itemBuilder: (context, index) {
final indexedWeatherCodeDaily = weatherCodeDaily[index];
final temperature2MMin = weatherData.temperature2MMin?[index];
final temperature2MMax = weatherData.temperature2MMax?[index];
final apparentTemperatureMin =
weatherData.apparentTemperatureMin?[index];
final apparentTemperatureMax =
weatherData.apparentTemperatureMax?[index];
final uvIndexMax = weatherData.uvIndexMax?[index];
final windDirection10MDominant =
weatherData.winddirection10MDominant?[index];
final windSpeed10MMax = weatherData.windspeed10MMax?[index];
final windGusts10MMax = weatherData.windgusts10MMax?[index];
final precipitationProbabilityMax =
weatherData.precipitationProbabilityMax?[index];
final rainSum = weatherData.rainSum?[index];
final precipitationSum = weatherData.precipitationSum?[index];
final sunrise = weatherData.sunrise![index];
final sunset = weatherData.sunset![index];
final startIndex = index * 24;
return indexedWeatherCodeDaily == null
? null
: Container(
margin: const EdgeInsets.symmetric(horizontal: 10),
child: ListView(
children: [
WeatherNow(
weather:
weatherData.weathercode![startIndex + hourOfDay],
degree: weatherData
.temperature2M![startIndex + hourOfDay],
time: weatherData.time![startIndex + hourOfDay],
timeDay: sunrise,
timeNight: sunset,
tempMax: temperature2MMax!,
tempMin: temperature2MMin!,
),
Card(
margin: const EdgeInsets.only(bottom: 15),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 5),
child: SizedBox(
height: 135,
child: ScrollablePositionedList.separated(
separatorBuilder:
(BuildContext context, int index) {
return const VerticalDivider(
width: 10,
indent: 40,
endIndent: 40,
);
},
scrollDirection: Axis.horizontal,
itemCount: 24,
itemBuilder: (ctx, i) {
int hourlyIndex = startIndex + i;
return GestureDetector(
onTap: () {
hourOfDay = i;
setState(() {});
},
child: Container(
margin: const EdgeInsets.symmetric(
vertical: 5),
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 5,
),
decoration: BoxDecoration(
color: i == hourOfDay
? context.theme.colorScheme
.secondaryContainer
: Colors.transparent,
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
),
child: WeatherHourly(
time: weatherData.time![hourlyIndex],
weather: weatherData
.weathercode![hourlyIndex],
degree: weatherData
.temperature2M![hourlyIndex],
timeDay: sunrise,
timeNight: sunset,
),
),
);
},
),
),
),
),
SunsetSunrise(
timeSunrise: sunrise,
timeSunset: sunset,
),
DescContainer(
humidity: weatherData
.relativehumidity2M?[startIndex + hourOfDay],
wind:
weatherData.windspeed10M?[startIndex + hourOfDay],
visibility:
weatherData.visibility?[startIndex + hourOfDay],
feels: weatherData
.apparentTemperature?[startIndex + hourOfDay],
evaporation: weatherData
.evapotranspiration?[startIndex + hourOfDay],
precipitation: weatherData
.precipitation?[startIndex + hourOfDay],
direction: weatherData
.winddirection10M?[startIndex + hourOfDay],
pressure: weatherData
.surfacePressure?[startIndex + hourOfDay],
rain: weatherData.rain?[startIndex + hourOfDay],
cloudcover:
weatherData.cloudcover?[startIndex + hourOfDay],
windgusts:
weatherData.windgusts10M?[startIndex + hourOfDay],
uvIndex: weatherData.uvIndex?[startIndex + hourOfDay],
dewpoint2M:
weatherData.dewpoint2M?[startIndex + hourOfDay],
precipitationProbability:
weatherData.precipitationProbability?[
startIndex + hourOfDay],
shortwaveRadiation: weatherData
.shortwaveRadiation?[startIndex + hourOfDay],
initiallyExpanded: true,
title: 'hourlyVariables'.tr,
),
DescContainer(
apparentTemperatureMin: apparentTemperatureMin,
apparentTemperatureMax: apparentTemperatureMax,
uvIndexMax: uvIndexMax,
windDirection10MDominant: windDirection10MDominant,
windSpeed10MMax: windSpeed10MMax,
windGusts10MMax: windGusts10MMax,
precipitationProbabilityMax:
precipitationProbabilityMax,
rainSum: rainSum,
precipitationSum: precipitationSum,
initiallyExpanded: true,
title: 'dailyVariables'.tr,
),
],
),
);
},
),
),
);
}
}

View file

@ -1,80 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:rain/app/widgets/status/status_weather.dart';
import 'package:rain/app/widgets/status/status_data.dart';
import 'package:rain/main.dart';
class ListDailyCard extends StatefulWidget {
const ListDailyCard({
super.key,
required this.timeDaily,
required this.weathercodeDaily,
required this.temperature2MMax,
required this.temperature2MMin,
});
final DateTime timeDaily;
final int? weathercodeDaily;
final double? temperature2MMax;
final double? temperature2MMin;
@override
State<ListDailyCard> createState() => _ListDailyCardState();
}
class _ListDailyCardState extends State<ListDailyCard> {
final statusWeather = StatusWeather();
final statusData = StatusData();
@override
Widget build(BuildContext context) {
return widget.weathercodeDaily == null
? Container()
: Card(
margin: const EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 20),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${statusData.getDegree(widget.temperature2MMin?.round())} / ${statusData.getDegree(widget.temperature2MMax?.round())}',
style: context.textTheme.titleLarge?.copyWith(
fontSize: 22,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 5),
Text(
DateFormat.MMMMEEEEd(locale.languageCode)
.format(widget.timeDaily),
style: context.textTheme.titleMedium?.copyWith(
color: Colors.grey,
fontWeight: FontWeight.w400,
),
),
const SizedBox(height: 5),
Text(
statusWeather.getText(widget.weathercodeDaily),
style: context.textTheme.titleMedium?.copyWith(
color: Colors.grey,
fontWeight: FontWeight.w400,
),
),
],
),
),
const SizedBox(width: 5),
Image.asset(
statusWeather.getImageNowDaily(widget.weathercodeDaily),
scale: 6.5,
),
],
),
),
);
}
}

View file

@ -1,146 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:rain/app/data/weather.dart';
import 'package:rain/app/widgets/daily/info_daily_card.dart';
import 'package:rain/app/widgets/status/status_data.dart';
import 'package:rain/app/widgets/status/status_weather.dart';
import 'package:rain/main.dart';
class WeatherDaily extends StatefulWidget {
const WeatherDaily({
super.key,
required this.weatherData,
required this.onTap,
});
final WeatherCard weatherData;
final VoidCallback onTap;
@override
State<WeatherDaily> createState() => _WeatherDailyState();
}
class _WeatherDailyState extends State<WeatherDaily> {
final statusWeather = StatusWeather();
final statusData = StatusData();
@override
Widget build(BuildContext context) {
final splashColor = context.theme.colorScheme.primary.withOpacity(0.4);
const inkWellBorderRadius = BorderRadius.all(
Radius.circular(16),
);
final weatherData = widget.weatherData;
final weatherCodeDaily = weatherData.weathercodeDaily ?? [];
final textTheme = context.textTheme;
final labelLarge = textTheme.labelLarge;
final bodyMediumGrey = textTheme.bodyMedium?.copyWith(
color: Colors.grey,
);
return Card(
margin: const EdgeInsets.only(bottom: 15),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5),
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: 7,
itemBuilder: (ctx, index) {
return InkWell(
splashColor: splashColor,
borderRadius: inkWellBorderRadius,
onTap: () => Get.to(
() => InfoDailyCard(
weatherData: weatherData,
index: index,
),
transition: Transition.downToUp,
),
child: Container(
margin: const EdgeInsets.symmetric(vertical: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
DateFormat.EEEE(locale.languageCode)
.format((weatherData.timeDaily ?? [])[index]),
style: labelLarge,
overflow: TextOverflow.ellipsis,
),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
statusWeather
.getImage7Day(weatherCodeDaily[index]),
scale: 3,
),
const SizedBox(width: 5),
Expanded(
child: Text(
statusWeather
.getText(weatherCodeDaily[index]),
style: labelLarge,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
statusData.getDegree(
(weatherData.temperature2MMin ?? [])[index]
?.round()),
style: labelLarge,
),
Text(
' / ',
style: bodyMediumGrey,
),
Text(
statusData.getDegree(
(weatherData.temperature2MMax ?? [])[index]
?.round()),
style: labelLarge,
),
],
),
),
],
),
),
);
},
),
const Divider(),
InkWell(
splashColor: splashColor,
borderRadius: inkWellBorderRadius,
onTap: widget.onTap,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Text(
'weatherMore'.tr,
style: textTheme.titleMedium,
overflow: TextOverflow.ellipsis,
),
),
),
],
),
),
);
}
}

View file

@ -1,71 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:iconsax/iconsax.dart';
import 'package:rain/app/data/weather.dart';
import 'package:rain/app/widgets/daily/info_daily_card.dart';
import 'package:rain/app/widgets/daily/list_daily_card.dart';
class WeatherMore extends StatefulWidget {
const WeatherMore({
super.key,
required this.weatherData,
});
final WeatherCard weatherData;
@override
State<WeatherMore> createState() => _WeatherMoreState();
}
class _WeatherMoreState extends State<WeatherMore> {
@override
Widget build(BuildContext context) {
const transparent = Colors.transparent;
final weatherData = widget.weatherData;
final timeDaily = weatherData.timeDaily ?? [];
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
centerTitle: true,
leading: IconButton(
onPressed: () {
Get.back();
},
icon: const Icon(
Iconsax.arrow_left_1,
size: 20,
),
splashColor: transparent,
highlightColor: transparent,
),
title: Text(
'weatherMore'.tr,
style: context.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
),
body: SafeArea(
child: ListView.builder(
itemCount: timeDaily.length,
itemBuilder: (context, index) => GestureDetector(
onTap: () => Get.to(
() => InfoDailyCard(
weatherData: weatherData,
index: index,
),
transition: Transition.downToUp,
),
child: ListDailyCard(
timeDaily: timeDaily[index],
weathercodeDaily: weatherData.weathercodeDaily![index],
temperature2MMax: weatherData.temperature2MMax![index],
temperature2MMin: weatherData.temperature2MMin![index],
),
),
),
),
);
}
}

View file

@ -1,306 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:rain/app/widgets/desc/desc.dart';
import 'package:rain/app/widgets/desc/message.dart';
import 'package:rain/app/widgets/status/status_data.dart';
class DescContainer extends StatefulWidget {
const DescContainer({
super.key,
this.humidity,
this.wind,
this.visibility,
this.feels,
this.evaporation,
this.precipitation,
this.direction,
this.pressure,
this.rain,
this.cloudcover,
this.windgusts,
this.uvIndex,
this.dewpoint2M,
this.precipitationProbability,
this.shortwaveRadiation,
this.apparentTemperatureMin,
this.apparentTemperatureMax,
this.uvIndexMax,
this.windDirection10MDominant,
this.windSpeed10MMax,
this.windGusts10MMax,
this.precipitationProbabilityMax,
this.rainSum,
this.precipitationSum,
required this.initiallyExpanded,
required this.title,
});
final int? humidity;
final double? wind;
final double? visibility;
final double? feels;
final double? evaporation;
final double? precipitation;
final int? direction;
final double? pressure;
final double? rain;
final int? cloudcover;
final double? windgusts;
final double? uvIndex;
final double? dewpoint2M;
final int? precipitationProbability;
final double? shortwaveRadiation;
final double? apparentTemperatureMin;
final double? apparentTemperatureMax;
final double? uvIndexMax;
final int? windDirection10MDominant;
final double? windSpeed10MMax;
final double? windGusts10MMax;
final int? precipitationProbabilityMax;
final double? rainSum;
final double? precipitationSum;
final bool initiallyExpanded;
final String title;
@override
State<DescContainer> createState() => _DescContainerState();
}
class _DescContainerState extends State<DescContainer> {
final statusData = StatusData();
final message = Message();
@override
Widget build(BuildContext context) {
final dewpoint2M = widget.dewpoint2M?.round();
final feels = widget.feels;
final visibility = widget.visibility;
final direction = widget.direction;
final wind = widget.wind;
final windgusts = widget.windgusts;
final evaporation = widget.evaporation;
final precipitation = widget.precipitation;
final rain = widget.rain;
final precipitationProbability = widget.precipitationProbability;
final humidity = widget.humidity;
final cloudcover = widget.cloudcover;
final pressure = widget.pressure;
final uvIndex = widget.uvIndex;
final shortwaveRadiation = widget.shortwaveRadiation;
final apparentTemperatureMin = widget.apparentTemperatureMin;
final apparentTemperatureMax = widget.apparentTemperatureMax;
final uvIndexMax = widget.uvIndexMax;
final windDirection10MDominant = widget.windDirection10MDominant;
final windSpeed10MMax = widget.windSpeed10MMax;
final windGusts10MMax = widget.windGusts10MMax;
final precipitationProbabilityMax = widget.precipitationProbabilityMax;
final rainSum = widget.rainSum;
final precipitationSum = widget.precipitationSum;
final initiallyExpanded = widget.initiallyExpanded;
final title = widget.title;
return Card(
margin: const EdgeInsets.only(bottom: 15),
child: ExpansionTile(
shape: const Border(),
title: Text(
title,
style: context.textTheme.labelLarge,
),
initiallyExpanded: initiallyExpanded,
children: [
Padding(
padding: const EdgeInsets.only(top: 20, bottom: 5),
child: Wrap(
alignment: WrapAlignment.spaceEvenly,
spacing: 5,
children: [
apparentTemperatureMin == null
? Container()
: DescWeather(
imageName: 'assets/images/cold.png',
value: statusData
.getDegree(apparentTemperatureMin.round()),
desc: 'apparentTemperatureMin'.tr,
),
apparentTemperatureMax == null
? Container()
: DescWeather(
imageName: 'assets/images/hot.png',
value: statusData
.getDegree(apparentTemperatureMax.round()),
desc: 'apparentTemperatureMax'.tr,
),
uvIndexMax == null
? Container()
: DescWeather(
imageName: 'assets/images/uv.png',
value: '${uvIndexMax.round()}',
desc: 'uvIndex'.tr,
message: message.getUvIndex(uvIndexMax.round()),
),
windDirection10MDominant == null
? Container()
: DescWeather(
imageName: 'assets/images/windsock.png',
value: '$windDirection10MDominant°',
desc: 'direction'.tr,
message: message.getDirection(windDirection10MDominant),
),
windSpeed10MMax == null
? Container()
: DescWeather(
imageName: 'assets/images/wind.png',
value: statusData.getSpeed(windSpeed10MMax.round()),
desc: 'wind'.tr,
),
windGusts10MMax == null
? Container()
: DescWeather(
imageName: 'assets/images/windgusts.png',
value: statusData.getSpeed(windGusts10MMax.round()),
desc: 'windgusts'.tr,
),
precipitationProbabilityMax == null
? Container()
: DescWeather(
imageName:
'assets/images/precipitation_probability.png',
value: '$precipitationProbabilityMax%',
desc: 'precipitationProbability'.tr,
),
rainSum == null
? Container()
: DescWeather(
imageName: 'assets/images/water.png',
value: statusData.getPrecipitation(rainSum),
desc: 'rain'.tr,
),
precipitationSum == null
? Container()
: DescWeather(
imageName: 'assets/images/rainfall.png',
value: statusData.getPrecipitation(precipitationSum),
desc: 'precipitation'.tr,
),
dewpoint2M == null
? Container()
: DescWeather(
imageName: 'assets/images/dew.png',
value: statusData.getDegree(dewpoint2M.round()),
desc: 'dewpoint'.tr,
),
feels == null
? Container()
: DescWeather(
imageName: 'assets/images/temperature.png',
value: statusData.getDegree(feels.round()),
desc: 'feels'.tr,
),
visibility == null
? Container()
: DescWeather(
imageName: 'assets/images/fog.png',
value: statusData.getVisibility(visibility),
desc: 'visibility'.tr,
),
direction == null
? Container()
: DescWeather(
imageName: 'assets/images/windsock.png',
value: '$direction°',
desc: 'direction'.tr,
message: message.getDirection(direction),
),
wind == null
? Container()
: DescWeather(
imageName: 'assets/images/wind.png',
value: statusData.getSpeed(wind.round()),
desc: 'wind'.tr,
),
windgusts == null
? Container()
: DescWeather(
imageName: 'assets/images/windgusts.png',
value: statusData.getSpeed(windgusts.round()),
desc: 'windgusts'.tr,
),
evaporation == null
? Container()
: DescWeather(
imageName: 'assets/images/evaporation.png',
value: statusData.getPrecipitation(evaporation.abs()),
desc: 'evaporation'.tr,
),
precipitation == null
? Container()
: DescWeather(
imageName: 'assets/images/rainfall.png',
value: statusData.getPrecipitation(precipitation),
desc: 'precipitation'.tr,
),
rain == null
? Container()
: DescWeather(
imageName: 'assets/images/water.png',
value: statusData.getPrecipitation(rain),
desc: 'rain'.tr,
),
precipitationProbability == null
? Container()
: DescWeather(
imageName:
'assets/images/precipitation_probability.png',
value: '$precipitationProbability%',
desc: 'precipitationProbability'.tr,
),
humidity == null
? Container()
: DescWeather(
imageName: 'assets/images/humidity.png',
value: '$humidity%',
desc: 'humidity'.tr,
),
cloudcover == null
? Container()
: DescWeather(
imageName: 'assets/images/cloudy.png',
value: '$cloudcover%',
desc: 'cloudcover'.tr,
),
pressure == null
? Container()
: DescWeather(
imageName: 'assets/images/atmospheric.png',
value: '${pressure.round()} ${'hPa'.tr}',
desc: 'pressure'.tr,
message: message.getPressure(pressure.round()),
),
uvIndex == null
? Container()
: DescWeather(
imageName: 'assets/images/uv.png',
value: '${uvIndex.round()}',
desc: 'uvIndex'.tr,
message: message.getUvIndex(uvIndex.round()),
),
shortwaveRadiation == null
? Container()
: DescWeather(
imageName: 'assets/images/shortwave_radiation.png',
value: '${shortwaveRadiation.round()} ${'W/m2'.tr}',
desc: 'shortwaveRadiation'.tr,
),
],
),
),
],
),
);
}
}

View file

@ -1,59 +0,0 @@
import 'package:get/get.dart';
class Message {
String getPressure(int? pressure) {
if (pressure != null) {
if (pressure < 1000) {
return 'low'.tr;
} else if (pressure > 1020) {
return 'high'.tr;
} else {
return 'normal'.tr;
}
} else {
return '';
}
}
String getUvIndex(int? uvIndex) {
if (uvIndex != null) {
if (uvIndex < 3) {
return 'uvLow'.tr;
} else if (uvIndex < 6) {
return 'uvAverage'.tr;
} else if (uvIndex < 8) {
return 'uvHigh'.tr;
} else if (uvIndex < 11) {
return 'uvVeryHigh'.tr;
} else {
return 'uvExtreme'.tr;
}
} else {
return '';
}
}
String getDirection(int? direction) {
if (direction != null) {
if (direction >= 337.5 || direction < 22.5) {
return 'north'.tr;
} else if (direction >= 22.5 && direction < 67.5) {
return 'northeast'.tr;
} else if (direction >= 67.5 && direction < 112.5) {
return 'east'.tr;
} else if (direction >= 112.5 && direction < 157.5) {
return 'southeast'.tr;
} else if (direction >= 157.5 && direction < 202.5) {
return 'south'.tr;
} else if (direction >= 202.5 && direction < 247.5) {
return 'southwest'.tr;
} else if (direction >= 247.5 && direction < 292.5) {
return 'west'.tr;
} else {
return 'northwest'.tr;
}
} else {
return '';
}
}
}

View file

@ -1,71 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:rain/app/widgets/status/status_data.dart';
import 'package:rain/app/widgets/status/status_weather.dart';
import 'package:rain/main.dart';
class WeatherHourly extends StatefulWidget {
const WeatherHourly({
super.key,
required this.time,
required this.weather,
required this.degree,
required this.timeDay,
required this.timeNight,
});
final String time;
final String timeDay;
final String timeNight;
final int weather;
final double degree;
@override
State<WeatherHourly> createState() => _WeatherHourlyState();
}
class _WeatherHourlyState extends State<WeatherHourly> {
final statusWeather = StatusWeather();
final statusData = StatusData();
@override
Widget build(BuildContext context) {
final textTheme = context.textTheme;
final time = widget.time;
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
Text(
statusData.getTimeFormat(time),
style: textTheme.labelLarge,
),
Text(
DateFormat('E', locale.languageCode)
.format(DateTime.tryParse(time)!),
style: textTheme.labelLarge?.copyWith(
color: Colors.grey,
),
),
],
),
Image.asset(
statusWeather.getImageToday(
widget.weather,
time,
widget.timeDay,
widget.timeNight,
),
scale: 3,
),
Text(
statusData.getDegree(widget.degree.round()),
style: textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
],
);
}
}

View file

@ -1,97 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:rain/app/widgets/status/status_data.dart';
import 'package:rain/app/widgets/status/status_weather.dart';
import 'package:rain/main.dart';
class WeatherNow extends StatefulWidget {
const WeatherNow({
super.key,
required this.weather,
required this.degree,
required this.time,
required this.timeDay,
required this.timeNight,
required this.tempMax,
required this.tempMin,
});
final String time;
final String timeDay;
final String timeNight;
final int weather;
final double degree;
final double tempMax;
final double tempMin;
@override
State<WeatherNow> createState() => _WeatherNowState();
}
class _WeatherNowState extends State<WeatherNow> {
final statusWeather = StatusWeather();
final statusData = StatusData();
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(bottom: 15),
child: Padding(
padding:
const EdgeInsets.only(top: 18, bottom: 18, left: 25, right: 15),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
DateFormat.MMMMEEEEd(locale.languageCode).format(
DateTime.parse(widget.time),
),
style: context.textTheme.labelLarge?.copyWith(
color: Colors.grey,
),
),
const SizedBox(height: 5),
Text(
statusWeather.getText(widget.weather),
style: context.textTheme.titleLarge?.copyWith(fontSize: 20),
),
const SizedBox(height: 30),
Text(
statusData.getDegree(
roundDegree ? widget.degree.round() : widget.degree),
style: context.textTheme.displayMedium?.copyWith(
fontWeight: FontWeight.w800,
),
),
const SizedBox(height: 5),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(statusData.getDegree((widget.tempMin.round())),
style: context.textTheme.labelLarge),
Text(' / ',
style: context.textTheme.labelLarge
?.copyWith(color: Colors.grey)),
Text(statusData.getDegree((widget.tempMax.round())),
style: context.textTheme.labelLarge),
],
),
],
),
),
Image(
image: AssetImage(statusWeather.getImageNow(widget.weather,
widget.time, widget.timeDay, widget.timeNight)),
fit: BoxFit.fill,
height: 140,
),
],
),
),
);
}
}

View file

@ -1,79 +0,0 @@
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:rain/main.dart';
import 'package:timezone/timezone.dart';
class StatusData {
String getDegree(degree) {
switch (settings.degrees) {
case 'celsius':
return '$degree°C';
case 'fahrenheit':
return '$degree°F';
default:
return '$degree°C';
}
}
String getSpeed(int? speed) {
switch (settings.measurements) {
case 'metric':
return '$speed ${'kph'.tr}';
case 'imperial':
return '$speed ${'mph'.tr}';
default:
return '$speed ${'kph'.tr}';
}
}
String getVisibility(double? length) {
if (length != null) {
switch (settings.measurements) {
case 'metric':
return '${length > 1000 ? (length / 1000).round() : (length / 1000).toStringAsFixed(2)} ${'km'.tr}';
case 'imperial':
return '${length > 5280 ? (length / 5280).round() : (length / 5280).toStringAsFixed(2)} ${'mi'.tr}';
default:
return '${length > 1000 ? (length / 1000).round() : (length / 1000).toStringAsFixed(2)} ${'km'.tr}';
}
} else {
return '';
}
}
String getPrecipitation(double? precipitation) {
switch (settings.measurements) {
case 'metric':
return '$precipitation ${'mm'.tr}';
case 'imperial':
return '$precipitation ${'inch'.tr}';
default:
return '$precipitation ${'mm'.tr}';
}
}
String getTimeFormat(String time) {
switch (settings.timeformat) {
case '12':
return DateFormat.jm(locale.languageCode)
.format(DateTime.tryParse(time)!);
case '24':
return DateFormat.Hm(locale.languageCode)
.format(DateTime.tryParse(time)!);
default:
return DateFormat.Hm(locale.languageCode)
.format(DateTime.tryParse(time)!);
}
}
String getTimeFormatTz(TZDateTime time) {
switch (settings.timeformat) {
case '12':
return DateFormat.jm(locale.languageCode).format(time);
case '24':
return DateFormat.Hm(locale.languageCode).format(time);
default:
return DateFormat.Hm(locale.languageCode).format(time);
}
}
}

View file

@ -1,340 +0,0 @@
import 'package:get/get.dart';
const assetImageRoot = 'assets/images/';
class StatusWeather {
String getImageNow(
int weather, String time, String timeDay, String timeNight) {
final currentTime = DateTime.parse(time);
final day = DateTime.parse(timeDay);
final night = DateTime.parse(timeNight);
final dayTime =
DateTime(day.year, day.month, day.day, day.hour, day.minute);
final nightTime =
DateTime(night.year, night.month, night.day, night.hour, night.minute);
switch (weather) {
case 0:
if (currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime)) {
return '${assetImageRoot}sun.png';
} else {
return '${assetImageRoot}full-moon.png';
}
case 1:
case 2:
case 3:
if (currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime)) {
return '${assetImageRoot}cloud.png';
} else {
return '${assetImageRoot}moon.png';
}
case 45:
case 48:
if (currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime)) {
return '${assetImageRoot}fog.png';
} else {
return '${assetImageRoot}fog_moon.png';
}
case 51:
case 53:
case 55:
case 56:
case 57:
case 61:
case 63:
case 65:
case 66:
case 67:
return '${assetImageRoot}rain.png';
case 80:
case 81:
case 82:
return '${assetImageRoot}rain-fall.png';
case 71:
case 73:
case 75:
case 77:
case 85:
case 86:
return '${assetImageRoot}snow.png';
case 95:
return '${assetImageRoot}thunder.png';
case 96:
case 99:
return '${assetImageRoot}storm.png';
default:
return '';
}
}
String getImageNowDaily(int? weather) {
switch (weather) {
case 0:
return '${assetImageRoot}sun.png';
case 1:
case 2:
case 3:
return '${assetImageRoot}cloud.png';
case 45:
case 48:
return '${assetImageRoot}fog.png';
case 51:
case 53:
case 55:
case 56:
case 57:
case 61:
case 63:
case 65:
case 66:
case 67:
return '${assetImageRoot}rain.png';
case 80:
case 81:
case 82:
return '${assetImageRoot}rain-fall.png';
case 71:
case 73:
case 75:
case 77:
case 85:
case 86:
return '${assetImageRoot}snow.png';
case 95:
return '${assetImageRoot}thunder.png';
case 96:
case 99:
return '${assetImageRoot}storm.png';
default:
return '';
}
}
String getImageToday(
int weather, String time, String timeDay, String timeNight) {
final currentTime = DateTime.parse(time);
final day = DateTime.parse(timeDay);
final night = DateTime.parse(timeNight);
final dayTime =
DateTime(day.year, day.month, day.day, day.hour, day.minute);
final nightTime =
DateTime(night.year, night.month, night.day, night.hour, night.minute);
switch (weather) {
case 0:
if (currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime)) {
return '${assetImageRoot}clear_day.png';
} else {
return '${assetImageRoot}clear_night.png';
}
case 1:
case 2:
case 3:
if (currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime)) {
return '${assetImageRoot}cloudy_day.png';
} else {
return '${assetImageRoot}cloudy_night.png';
}
case 45:
case 48:
if (currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime)) {
return '${assetImageRoot}fog_day.png';
} else {
return '${assetImageRoot}fog_night.png';
}
case 51:
case 53:
case 55:
case 56:
case 57:
case 61:
case 63:
case 65:
case 66:
case 67:
case 80:
case 81:
case 82:
if (currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime)) {
return '${assetImageRoot}rain_day.png';
} else {
return '${assetImageRoot}rain_night.png';
}
case 71:
case 73:
case 75:
case 77:
case 85:
case 86:
if (currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime)) {
return '${assetImageRoot}snow_day.png';
} else {
return '${assetImageRoot}snow_night.png';
}
case 95:
case 96:
case 99:
if (currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime)) {
return '${assetImageRoot}thunder_day.png';
} else {
return '${assetImageRoot}thunder_night.png';
}
default:
return '';
}
}
String getImage7Day(int? weather) {
switch (weather) {
case 0:
return '${assetImageRoot}clear_day.png';
case 1:
case 2:
case 3:
return '${assetImageRoot}cloudy_day.png';
case 45:
case 48:
return '${assetImageRoot}fog_day.png';
case 51:
case 53:
case 55:
case 56:
case 57:
case 61:
case 63:
case 65:
case 66:
case 67:
case 80:
case 81:
case 82:
return '${assetImageRoot}rain_day.png';
case 71:
case 73:
case 75:
case 77:
case 85:
case 86:
return '${assetImageRoot}snow_day.png';
case 95:
case 96:
case 99:
return '${assetImageRoot}thunder_day.png';
default:
return '';
}
}
String getText(int? weather) {
switch (weather) {
case 0:
return 'clear_sky'.tr;
case 1:
case 2:
return 'cloudy'.tr;
case 3:
return 'overcast'.tr;
case 45:
case 48:
return 'fog'.tr;
case 51:
case 53:
case 55:
return 'drizzle'.tr;
case 56:
case 57:
return 'drizzling_rain'.tr;
case 61:
case 63:
case 65:
return 'rain'.tr;
case 66:
case 67:
return 'freezing_rain'.tr;
case 80:
case 81:
case 82:
return 'heavy_rains'.tr;
case 71:
case 73:
case 75:
case 77:
case 85:
case 86:
return 'snow'.tr;
case 95:
case 96:
case 99:
return 'thunderstorm'.tr;
default:
return '';
}
}
String getImageNotification(
int weather, String time, String timeDay, String timeNight) {
final currentTime = DateTime.parse(time);
final day = DateTime.parse(timeDay);
final night = DateTime.parse(timeNight);
final dayTime =
DateTime(day.year, day.month, day.day, day.hour, day.minute);
final nightTime =
DateTime(night.year, night.month, night.day, night.hour, night.minute);
switch (weather) {
case 0:
if (currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime)) {
return 'sun.png';
} else {
return 'full-moon.png';
}
case 1:
case 2:
case 3:
if (currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime)) {
return 'cloud.png';
} else {
return 'moon.png';
}
case 45:
case 48:
if (currentTime.isAfter(dayTime) && currentTime.isBefore(nightTime)) {
return 'fog.png';
} else {
return 'fog_moon.png';
}
case 51:
case 53:
case 55:
case 56:
case 57:
case 61:
case 63:
case 65:
case 66:
case 67:
return 'rain.png';
case 80:
case 81:
case 82:
return 'rain-fall.png';
case 71:
case 73:
case 75:
case 77:
case 85:
case 86:
return 'snow.png';
case 95:
return 'thunder.png';
case 96:
case 99:
return 'storm.png';
default:
return '';
}
}
}

View file

@ -1,104 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:rain/app/widgets/status/status_data.dart';
class SunsetSunrise extends StatefulWidget {
const SunsetSunrise({
super.key,
required this.timeSunrise,
required this.timeSunset,
});
final String timeSunrise;
final String timeSunset;
@override
State<SunsetSunrise> createState() => _SunsetSunriseState();
}
class _SunsetSunriseState extends State<SunsetSunrise> {
final statusData = StatusData();
@override
Widget build(BuildContext context) {
const crossAxisCenterAlignment = CrossAxisAlignment.center;
final textTheme = context.textTheme;
final titleSmall = textTheme.titleSmall;
final titleLarge = textTheme.titleLarge;
return Card(
margin: const EdgeInsets.only(bottom: 15),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
child: Row(
children: [
Expanded(
child: Row(
crossAxisAlignment: crossAxisCenterAlignment,
children: [
Expanded(
child: Column(
crossAxisAlignment: crossAxisCenterAlignment,
children: [
Text(
'sunrise'.tr,
style: titleSmall,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
),
const SizedBox(height: 2),
Text(
statusData.getTimeFormat(widget.timeSunrise),
style: titleLarge,
),
],
),
),
const SizedBox(width: 5),
Flexible(
child: Image.asset(
'assets/images/sunrise.png',
scale: 10,
),
),
],
),
),
Expanded(
child: Row(
crossAxisAlignment: crossAxisCenterAlignment,
children: [
Expanded(
child: Column(
crossAxisAlignment: crossAxisCenterAlignment,
children: [
Text(
'sunset'.tr,
style: titleSmall,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
),
const SizedBox(height: 2),
Text(
statusData.getTimeFormat(widget.timeSunset),
style: titleLarge,
),
],
),
),
const SizedBox(width: 5),
Flexible(
child: Image.asset(
'assets/images/sunset.png',
scale: 10,
),
),
],
),
),
],
),
),
);
}
}

378
lib/main.dart Normal file → Executable file
View file

@ -14,30 +14,32 @@ import 'package:internet_connection_checker_plus/internet_connection_checker_plu
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:rain/app/controller/controller.dart'; import 'package:rain/app/controller/controller.dart';
import 'package:rain/app/modules/geolocation.dart'; import 'package:rain/app/data/db.dart';
import 'package:rain/app/modules/home.dart'; import 'package:rain/app/ui/geolocation.dart';
import 'package:rain/app/modules/onboarding.dart'; import 'package:rain/app/ui/home.dart';
import 'package:rain/app/ui/onboarding.dart';
import 'package:rain/theme/theme.dart'; import 'package:rain/theme/theme.dart';
import 'package:time_machine/time_machine.dart'; import 'package:rain/theme/theme_controller.dart';
import 'package:rain/translation/translation.dart';
import 'package:rain/app/utils/device_info.dart';
import 'package:timezone/data/latest_all.dart' as tz; import 'package:timezone/data/latest_all.dart' as tz;
import 'package:timezone/timezone.dart' as tz; import 'package:timezone/timezone.dart' as tz;
import 'package:workmanager/workmanager.dart'; import 'package:workmanager/workmanager.dart';
import 'app/data/weather.dart';
import 'theme/theme_controller.dart';
import 'translation/translation.dart';
late Isar isar; late Isar isar;
late Settings settings; late Settings settings;
late LocationCache locationCache; late LocationCache locationCache;
final ValueNotifier<Future<bool>> isOnline = final ValueNotifier<Future<bool>> isOnline = ValueNotifier(
ValueNotifier(InternetConnection().hasInternetAccess); InternetConnection().hasInternetAccess,
);
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin(); FlutterLocalNotificationsPlugin();
bool amoledTheme = false; bool amoledTheme = false;
bool materialColor = false; bool materialColor = false;
bool roundDegree = false; bool roundDegree = false;
bool largeElement = false;
Locale locale = const Locale('en', 'US'); Locale locale = const Locale('en', 'US');
int timeRange = 1; int timeRange = 1;
String timeStart = '09:00'; String timeStart = '09:00';
@ -45,36 +47,36 @@ String timeEnd = '21:00';
String widgetBackgroundColor = ''; String widgetBackgroundColor = '';
String widgetTextColor = ''; String widgetTextColor = '';
final List appLanguages = [
{'name': 'বাংলা', 'locale': const Locale('bn', 'IN')},
{'name': 'Čeština', 'locale': const Locale('cs', 'CZ')},
{'name': 'Dansk', 'locale': const Locale('da', 'DK')},
{'name': 'Deutsch', 'locale': const Locale('de', 'DE')},
{'name': 'English', 'locale': const Locale('en', 'US')},
{'name': 'Español', 'locale': const Locale('es', 'ES')},
{'name': 'Français', 'locale': const Locale('fr', 'FR')},
// {'name': 'Gaeilge', 'locale': const Locale('ga', 'IE')},
{'name': 'हिन्दी', 'locale': const Locale('hi', 'IN')},
{'name': 'Magyar', 'locale': const Locale('hu', 'HU')},
{'name': 'Italiano', 'locale': const Locale('it', 'IT')},
{'name': '한국어', 'locale': const Locale('ko', 'KR')},
{'name': 'فارسی', 'locale': const Locale('fa', 'IR')},
{'name': 'ქართული', 'locale': const Locale('ka', 'GE')},
{'name': 'Nederlands', 'locale': const Locale('nl', 'NL')},
{'name': 'Polski', 'locale': const Locale('pl', 'PL')},
{'name': 'Português (Brasil)', 'locale': const Locale('pt', 'BR')},
{'name': 'Română', 'locale': const Locale('ro', 'RO')},
{'name': 'Русский', 'locale': const Locale('ru', 'RU')},
{'name': 'Slovenčina', 'locale': const Locale('sk', 'SK')},
{'name': 'Türkçe', 'locale': const Locale('tr', 'TR')},
{'name': 'اردو', 'locale': const Locale('ur', 'PK')},
{'name': '中文(简体)', 'locale': const Locale('zh', 'CN')},
{'name': '中文(繁體)', 'locale': const Locale('zh', 'TW')},
];
const String appGroupId = 'DARK NIGHT'; const String appGroupId = 'DARK NIGHT';
const String androidWidgetName = 'OreoWidget'; const String androidWidgetName = 'OreoWidget';
const List<Map<String, dynamic>> appLanguages = [
{'name': 'বাংলা', 'locale': Locale('bn', 'IN')},
{'name': 'Čeština', 'locale': Locale('cs', 'CZ')},
{'name': 'Dansk', 'locale': Locale('da', 'DK')},
{'name': 'Deutsch', 'locale': Locale('de', 'DE')},
{'name': 'English', 'locale': Locale('en', 'US')},
{'name': 'Español', 'locale': Locale('es', 'ES')},
{'name': 'Français', 'locale': Locale('fr', 'FR')},
// {'name': 'Gaeilge', 'locale': Locale('ga', 'IE')},
{'name': 'हिन्दी', 'locale': Locale('hi', 'IN')},
{'name': 'Magyar', 'locale': Locale('hu', 'HU')},
{'name': 'Italiano', 'locale': Locale('it', 'IT')},
{'name': '한국어', 'locale': Locale('ko', 'KR')},
{'name': 'فارسی', 'locale': Locale('fa', 'IR')},
{'name': 'ქართული', 'locale': Locale('ka', 'GE')},
{'name': 'Nederlands', 'locale': Locale('nl', 'NL')},
{'name': 'Polski', 'locale': Locale('pl', 'PL')},
{'name': 'Português (Brasil)', 'locale': Locale('pt', 'BR')},
{'name': 'Română', 'locale': Locale('ro', 'RO')},
{'name': 'Русский', 'locale': Locale('ru', 'RU')},
{'name': 'Slovenčina', 'locale': Locale('sk', 'SK')},
{'name': 'Türkçe', 'locale': Locale('tr', 'TR')},
{'name': 'اردو', 'locale': Locale('ur', 'PK')},
{'name': '中文(简体)', 'locale': Locale('zh', 'CN')},
{'name': '中文(繁體)', 'locale': Locale('zh', 'TW')},
];
@pragma('vm:entry-point') @pragma('vm:entry-point')
void callbackDispatcher() { void callbackDispatcher() {
Workmanager().executeTask((task, inputData) { Workmanager().executeTask((task, inputData) {
@ -83,59 +85,40 @@ void callbackDispatcher() {
} }
void main() async { void main() async {
final String timeZoneName;
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
Connectivity() await initializeApp();
.onConnectivityChanged
.listen((List<ConnectivityResult> result) {
result.contains(ConnectivityResult.none)
? isOnline.value = Future(() => false)
: isOnline.value = InternetConnection().hasInternetAccess;
});
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(systemNavigationBarColor: Colors.black));
if (Platform.isAndroid) {
Workmanager().initialize(callbackDispatcher, isInDebugMode: kDebugMode);
await setOptimalDisplayMode();
}
if (Platform.isAndroid || Platform.isIOS) {
timeZoneName = await FlutterTimezone.getLocalTimezone();
} else {
timeZoneName = '${DateTimeZone.local}';
}
tz.initializeTimeZones();
tz.setLocalLocation(tz.getLocation(timeZoneName));
await isarInit();
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
const DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings();
const LinuxInitializationSettings initializationSettingsLinux =
LinuxInitializationSettings(defaultActionName: 'Rain');
const InitializationSettings initializationSettings = InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
linux: initializationSettingsLinux,
);
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
runApp(const MyApp()); runApp(const MyApp());
} }
Future<void> setOptimalDisplayMode() async { Future<void> initializeApp() async {
final List<DisplayMode> supported = await FlutterDisplayMode.supported; setupConnectivityListener();
final DisplayMode active = await FlutterDisplayMode.active; await initializeTimeZone();
final List<DisplayMode> sameResolution = supported await initializeIsar();
.where((DisplayMode m) => await initializeNotifications();
m.width == active.width && m.height == active.height) if (Platform.isAndroid) {
.toList() await setOptimalDisplayMode();
..sort((DisplayMode a, DisplayMode b) => Workmanager().initialize(callbackDispatcher, isInDebugMode: kDebugMode);
b.refreshRate.compareTo(a.refreshRate)); HomeWidget.setAppGroupId(appGroupId);
final DisplayMode mostOptimalMode = }
sameResolution.isNotEmpty ? sameResolution.first : active; DeviceFeature().init();
await FlutterDisplayMode.setPreferredMode(mostOptimalMode);
} }
Future<void> isarInit() async { void setupConnectivityListener() {
Connectivity().onConnectivityChanged.listen((result) {
isOnline.value =
result.contains(ConnectivityResult.none)
? Future.value(false)
: InternetConnection().hasInternetAccess;
});
}
Future<void> initializeTimeZone() async {
final timeZoneName = await FlutterTimezone.getLocalTimezone();
tz.initializeTimeZones();
tz.setLocalLocation(tz.getLocation(timeZoneName));
}
Future<void> initializeIsar() async {
isar = await Isar.open([ isar = await Isar.open([
SettingsSchema, SettingsSchema,
MainWeatherCacheSchema, MainWeatherCacheSchema,
@ -157,6 +140,28 @@ Future<void> isarInit() async {
} }
} }
Future<void> initializeNotifications() async {
const initializationSettings = InitializationSettings(
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
iOS: DarwinInitializationSettings(),
linux: LinuxInitializationSettings(defaultActionName: 'Rain'),
);
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
}
Future<void> setOptimalDisplayMode() async {
final supported = await FlutterDisplayMode.supported;
final active = await FlutterDisplayMode.active;
final sameResolution =
supported
.where((m) => m.width == active.width && m.height == active.height)
.toList()
..sort((a, b) => b.refreshRate.compareTo(a.refreshRate));
final mostOptimalMode =
sameResolution.isNotEmpty ? sameResolution.first : active;
await FlutterDisplayMode.setPreferredMode(mostOptimalMode);
}
class MyApp extends StatefulWidget { class MyApp extends StatefulWidget {
const MyApp({super.key}); const MyApp({super.key});
@ -165,6 +170,7 @@ class MyApp extends StatefulWidget {
bool? newAmoledTheme, bool? newAmoledTheme,
bool? newMaterialColor, bool? newMaterialColor,
bool? newRoundDegree, bool? newRoundDegree,
bool? newLargeElement,
Locale? newLocale, Locale? newLocale,
int? newTimeRange, int? newTimeRange,
String? newTimeStart, String? newTimeStart,
@ -174,27 +180,14 @@ class MyApp extends StatefulWidget {
}) async { }) async {
final state = context.findAncestorStateOfType<_MyAppState>()!; final state = context.findAncestorStateOfType<_MyAppState>()!;
if (newAmoledTheme != null) { if (newAmoledTheme != null) state.changeAmoledTheme(newAmoledTheme);
state.changeAmoledTheme(newAmoledTheme); if (newMaterialColor != null) state.changeMarerialTheme(newMaterialColor);
} if (newRoundDegree != null) state.changeRoundDegree(newRoundDegree);
if (newMaterialColor != null) { if (newLargeElement != null) state.changeLargeElement(newLargeElement);
state.changeMarerialTheme(newMaterialColor); if (newLocale != null) state.changeLocale(newLocale);
} if (newTimeRange != null) state.changeTimeRange(newTimeRange);
if (newRoundDegree != null) { if (newTimeStart != null) state.changeTimeStart(newTimeStart);
state.changeRoundDegree(newRoundDegree); if (newTimeEnd != null) state.changeTimeEnd(newTimeEnd);
}
if (newLocale != null) {
state.changeLocale(newLocale);
}
if (newTimeRange != null) {
state.changeTimeRange(newTimeRange);
}
if (newTimeStart != null) {
state.changeTimeStart(newTimeStart);
}
if (newTimeEnd != null) {
state.changeTimeEnd(newTimeEnd);
}
if (newWidgetBackgroundColor != null) { if (newWidgetBackgroundColor != null) {
state.changeWidgetBackgroundColor(newWidgetBackgroundColor); state.changeWidgetBackgroundColor(newWidgetBackgroundColor);
} }
@ -210,108 +203,112 @@ class MyApp extends StatefulWidget {
class _MyAppState extends State<MyApp> { class _MyAppState extends State<MyApp> {
final themeController = Get.put(ThemeController()); final themeController = Get.put(ThemeController());
void changeAmoledTheme(bool newAmoledTheme) { void changeAmoledTheme(bool newAmoledTheme) =>
setState(() { setState(() => amoledTheme = newAmoledTheme);
amoledTheme = newAmoledTheme; void changeMarerialTheme(bool newMaterialColor) =>
}); setState(() => materialColor = newMaterialColor);
} void changeRoundDegree(bool newRoundDegree) =>
setState(() => roundDegree = newRoundDegree);
void changeMarerialTheme(bool newMaterialColor) { void changeLargeElement(bool newLargeElement) =>
setState(() { setState(() => largeElement = newLargeElement);
materialColor = newMaterialColor; void changeTimeRange(int newTimeRange) =>
}); setState(() => timeRange = newTimeRange);
} void changeTimeStart(String newTimeStart) =>
setState(() => timeStart = newTimeStart);
void changeRoundDegree(bool newRoundDegree) { void changeTimeEnd(String newTimeEnd) => setState(() => timeEnd = newTimeEnd);
setState(() { void changeLocale(Locale newLocale) => setState(() => locale = newLocale);
roundDegree = newRoundDegree; void changeWidgetBackgroundColor(String newWidgetBackgroundColor) =>
}); setState(() => widgetBackgroundColor = newWidgetBackgroundColor);
} void changeWidgetTextColor(String newWidgetTextColor) =>
setState(() => widgetTextColor = newWidgetTextColor);
void changeTimeRange(int newTimeRange) {
setState(() {
timeRange = newTimeRange;
});
}
void changeTimeStart(String newTimeStart) {
setState(() {
timeStart = newTimeStart;
});
}
void changeTimeEnd(String newTimeEnd) {
setState(() {
timeEnd = newTimeEnd;
});
}
void changeLocale(Locale newLocale) {
setState(() {
locale = newLocale;
});
}
void changeWidgetBackgroundColor(String newWidgetBackgroundColor) {
setState(() {
widgetBackgroundColor = newWidgetBackgroundColor;
});
}
void changeWidgetTextColor(String newWidgetTextColor) {
setState(() {
widgetTextColor = newWidgetTextColor;
});
}
@override @override
void initState() { void initState() {
super.initState();
amoledTheme = settings.amoledTheme; amoledTheme = settings.amoledTheme;
materialColor = settings.materialColor; materialColor = settings.materialColor;
roundDegree = settings.roundDegree; roundDegree = settings.roundDegree;
largeElement = settings.largeElement;
locale = Locale( locale = Locale(
settings.language!.substring(0, 2), settings.language!.substring(3)); settings.language!.substring(0, 2),
settings.language!.substring(3),
);
timeRange = settings.timeRange ?? 1; timeRange = settings.timeRange ?? 1;
timeStart = settings.timeStart ?? '09:00'; timeStart = settings.timeStart ?? '09:00';
timeEnd = settings.timeEnd ?? '21:00'; timeEnd = settings.timeEnd ?? '21:00';
widgetBackgroundColor = settings.widgetBackgroundColor ?? ''; widgetBackgroundColor = settings.widgetBackgroundColor ?? '';
widgetTextColor = settings.widgetTextColor ?? ''; widgetTextColor = settings.widgetTextColor ?? '';
if (Platform.isAndroid) {
HomeWidget.setAppGroupId(appGroupId);
}
super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final edgeToEdgeAvailable = DeviceFeature().isEdgeToEdgeAvailable();
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
return GestureDetector( return GestureDetector(
onTap: () => FocusManager.instance.primaryFocus?.unfocus(), onTap: () => FocusManager.instance.primaryFocus?.unfocus(),
child: DynamicColorBuilder( child: DynamicColorBuilder(
builder: (lightColorScheme, darkColorScheme) { builder: (lightColorScheme, darkColorScheme) {
final lightMaterialTheme = final lightMaterialTheme = lightTheme(
lightTheme(lightColorScheme?.surface, lightColorScheme); lightColorScheme?.surface,
final darkMaterialTheme = lightColorScheme,
darkTheme(darkColorScheme?.surface, darkColorScheme); edgeToEdgeAvailable,
final darkMaterialThemeOled = darkTheme(oledColor, darkColorScheme); );
final darkMaterialTheme = darkTheme(
darkColorScheme?.surface,
darkColorScheme,
edgeToEdgeAvailable,
);
final darkMaterialThemeOled = darkTheme(
oledColor,
darkColorScheme,
edgeToEdgeAvailable,
);
return GetMaterialApp( return GetMaterialApp(
themeMode: themeController.theme, themeMode: themeController.theme,
theme: materialColor theme:
? lightColorScheme != null materialColor
? lightMaterialTheme ? lightColorScheme != null
: lightTheme(lightColor, colorSchemeLight) ? lightMaterialTheme
: lightTheme(lightColor, colorSchemeLight), : lightTheme(
darkTheme: amoledTheme lightColor,
? materialColor colorSchemeLight,
? darkColorScheme != null edgeToEdgeAvailable,
? darkMaterialThemeOled )
: darkTheme(oledColor, colorSchemeDark) : lightTheme(
: darkTheme(oledColor, colorSchemeDark) lightColor,
: materialColor colorSchemeLight,
edgeToEdgeAvailable,
),
darkTheme:
amoledTheme
? materialColor
? darkColorScheme != null
? darkMaterialThemeOled
: darkTheme(
oledColor,
colorSchemeDark,
edgeToEdgeAvailable,
)
: darkTheme(
oledColor,
colorSchemeDark,
edgeToEdgeAvailable,
)
: materialColor
? darkColorScheme != null ? darkColorScheme != null
? darkMaterialTheme ? darkMaterialTheme
: darkTheme(darkColor, colorSchemeDark) : darkTheme(
: darkTheme(darkColor, colorSchemeDark), darkColor,
colorSchemeDark,
edgeToEdgeAvailable,
)
: darkTheme(
darkColor,
colorSchemeDark,
edgeToEdgeAvailable,
),
localizationsDelegates: const [ localizationsDelegates: const [
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, GlobalWidgetsLocalizations.delegate,
@ -323,14 +320,15 @@ class _MyAppState extends State<MyApp> {
supportedLocales: supportedLocales:
appLanguages.map((e) => e['locale'] as Locale).toList(), appLanguages.map((e) => e['locale'] as Locale).toList(),
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
home: settings.onboard home:
? (locationCache.city == null) || settings.onboard
(locationCache.district == null) || ? (locationCache.city == null ||
(locationCache.lat == null) || locationCache.district == null ||
(locationCache.lon == null) locationCache.lat == null ||
? const SelectGeolocation(isStart: true) locationCache.lon == null)
: const HomePage() ? const SelectGeolocation(isStart: true)
: const OnBording(), : const HomePage()
: const OnBording(),
title: 'Rain', title: 'Rain',
); );
}, },

223
lib/theme/theme.dart Normal file → Executable file
View file

@ -1,8 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:dynamic_color/dynamic_color.dart'; import 'package:dynamic_color/dynamic_color.dart';
final ThemeData baseLigth = ThemeData.light(useMaterial3: true); final ThemeData baseLight = ThemeData.light(useMaterial3: true);
final ThemeData baseDark = ThemeData.dark(useMaterial3: true); final ThemeData baseDark = ThemeData.dark(useMaterial3: true);
const Color lightColor = Colors.white; const Color lightColor = Colors.white;
@ -13,118 +14,146 @@ ColorScheme colorSchemeLight = ColorScheme.fromSeed(
seedColor: Colors.deepPurple, seedColor: Colors.deepPurple,
brightness: Brightness.light, brightness: Brightness.light,
); );
ColorScheme colorSchemeDark = ColorScheme.fromSeed( ColorScheme colorSchemeDark = ColorScheme.fromSeed(
seedColor: Colors.deepPurple, seedColor: Colors.deepPurple,
brightness: Brightness.dark, brightness: Brightness.dark,
); );
ThemeData lightTheme(Color? color, ColorScheme? colorScheme) { ThemeData lightTheme(
return baseLigth.copyWith( Color? color,
ColorScheme? colorScheme,
bool edgeToEdgeAvailable,
) {
return _buildTheme(
baseTheme: baseLight,
brightness: Brightness.light, brightness: Brightness.light,
colorScheme: colorScheme color: color,
?.copyWith( colorScheme: colorScheme,
brightness: Brightness.light, edgeToEdgeAvailable: edgeToEdgeAvailable,
surface: baseLigth.colorScheme.surface,
)
.harmonized(),
textTheme: GoogleFonts.ubuntuTextTheme(baseLigth.textTheme),
appBarTheme: AppBarTheme(
backgroundColor: color,
foregroundColor: baseLigth.colorScheme.onSurface,
shadowColor: Colors.transparent,
surfaceTintColor: Colors.transparent,
elevation: 0,
),
primaryColor: color,
canvasColor: color,
scaffoldBackgroundColor: color,
cardTheme: baseLigth.cardTheme.copyWith(
color: color,
surfaceTintColor:
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
shadowColor: Colors.transparent,
),
bottomSheetTheme: baseLigth.bottomSheetTheme.copyWith(
backgroundColor: color,
surfaceTintColor:
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
),
navigationRailTheme: baseLigth.navigationRailTheme.copyWith(
backgroundColor: color,
),
navigationBarTheme: baseLigth.navigationBarTheme.copyWith(
backgroundColor: color,
surfaceTintColor:
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
),
inputDecorationTheme: baseLigth.inputDecorationTheme.copyWith(
labelStyle: WidgetStateTextStyle.resolveWith(
(Set<WidgetState> states) {
return const TextStyle(fontSize: 14);
},
),
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
),
indicatorColor: Colors.black,
); );
} }
ThemeData darkTheme(Color? color, ColorScheme? colorScheme) { ThemeData darkTheme(
return baseDark.copyWith( Color? color,
ColorScheme? colorScheme,
bool edgeToEdgeAvailable,
) {
return _buildTheme(
baseTheme: baseDark,
brightness: Brightness.dark, brightness: Brightness.dark,
colorScheme: colorScheme color: color,
?.copyWith( colorScheme: colorScheme,
brightness: Brightness.dark, edgeToEdgeAvailable: edgeToEdgeAvailable,
surface: baseDark.colorScheme.surface, );
) }
.harmonized(),
textTheme: GoogleFonts.ubuntuTextTheme(baseDark.textTheme), ThemeData _buildTheme({
appBarTheme: AppBarTheme( required ThemeData baseTheme,
backgroundColor: color, required Brightness brightness,
foregroundColor: baseDark.colorScheme.onSurface, required Color? color,
shadowColor: Colors.transparent, required ColorScheme? colorScheme,
surfaceTintColor: Colors.transparent, required bool edgeToEdgeAvailable,
elevation: 0, }) {
final harmonizedColorScheme =
colorScheme
?.copyWith(
brightness: brightness,
surface: baseTheme.colorScheme.surface,
)
.harmonized();
return baseTheme.copyWith(
brightness: brightness,
colorScheme: harmonizedColorScheme,
textTheme: GoogleFonts.ubuntuTextTheme(baseTheme.textTheme),
appBarTheme: _buildAppBarTheme(
color,
baseTheme.colorScheme.onSurface,
edgeToEdgeAvailable,
brightness,
harmonizedColorScheme,
), ),
primaryColor: color, primaryColor: color,
canvasColor: color, canvasColor: color,
scaffoldBackgroundColor: color, scaffoldBackgroundColor: color,
cardTheme: baseDark.cardTheme.copyWith( cardTheme: _buildCardTheme(color, harmonizedColorScheme),
color: color, bottomSheetTheme: _buildBottomSheetTheme(color, harmonizedColorScheme),
surfaceTintColor: navigationRailTheme: baseTheme.navigationRailTheme.copyWith(
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
shadowColor: Colors.transparent,
),
bottomSheetTheme: baseDark.bottomSheetTheme.copyWith(
backgroundColor: color,
surfaceTintColor:
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
),
navigationRailTheme: baseDark.navigationRailTheme.copyWith(
backgroundColor: color, backgroundColor: color,
), ),
navigationBarTheme: baseDark.navigationBarTheme.copyWith( navigationBarTheme: _buildNavigationBarTheme(color, harmonizedColorScheme),
backgroundColor: color, inputDecorationTheme: _buildInputDecorationTheme(),
surfaceTintColor: );
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint, }
),
inputDecorationTheme: baseDark.inputDecorationTheme.copyWith( AppBarTheme _buildAppBarTheme(
labelStyle: WidgetStateTextStyle.resolveWith( Color? color,
(Set<WidgetState> states) { Color? onSurfaceColor,
return const TextStyle(fontSize: 14); bool edgeToEdgeAvailable,
}, Brightness brightness,
), ColorScheme? colorScheme,
border: InputBorder.none, ) {
focusedBorder: InputBorder.none, return AppBarTheme(
enabledBorder: InputBorder.none, backgroundColor: color,
foregroundColor: onSurfaceColor,
shadowColor: Colors.transparent,
surfaceTintColor: Colors.transparent,
elevation: 0,
systemOverlayStyle: SystemUiOverlayStyle(
statusBarIconBrightness:
brightness == Brightness.light ? Brightness.dark : Brightness.light,
statusBarColor: Colors.transparent,
systemStatusBarContrastEnforced: false,
systemNavigationBarContrastEnforced: false,
systemNavigationBarDividerColor: Colors.transparent,
systemNavigationBarIconBrightness:
brightness == Brightness.light ? Brightness.dark : Brightness.light,
systemNavigationBarColor:
edgeToEdgeAvailable ? Colors.transparent : colorScheme?.surface,
), ),
); );
} }
CardThemeData _buildCardTheme(Color? color, ColorScheme? colorScheme) {
return CardThemeData(
color: color,
surfaceTintColor:
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
shadowColor: Colors.transparent,
);
}
BottomSheetThemeData _buildBottomSheetTheme(
Color? color,
ColorScheme? colorScheme,
) {
return BottomSheetThemeData(
backgroundColor: color,
surfaceTintColor:
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
);
}
NavigationBarThemeData _buildNavigationBarTheme(
Color? color,
ColorScheme? colorScheme,
) {
return NavigationBarThemeData(
backgroundColor: color,
surfaceTintColor:
color == oledColor ? Colors.transparent : colorScheme?.surfaceTint,
);
}
InputDecorationTheme _buildInputDecorationTheme() {
return InputDecorationTheme(
labelStyle: WidgetStateTextStyle.resolveWith((Set<WidgetState> states) {
return const TextStyle(fontSize: 14);
}),
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
);
}

33
lib/theme/theme_controller.dart Normal file → Executable file
View file

@ -1,31 +1,40 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:rain/app/data/weather.dart'; import 'package:rain/app/data/db.dart';
import 'package:rain/main.dart'; import 'package:rain/main.dart';
class ThemeController extends GetxController { class ThemeController extends GetxController {
ThemeMode get theme => settings.theme == 'system' ThemeMode get theme => _getThemeMode();
? ThemeMode.system
: settings.theme == 'dark'
? ThemeMode.dark
: ThemeMode.light;
void saveOledTheme(bool isOled) { void saveOledTheme(bool isOled) {
settings.amoledTheme = isOled; _updateSetting((settings) => settings.amoledTheme = isOled);
isar.writeTxnSync(() => isar.settings.putSync(settings));
} }
void saveMaterialTheme(bool isMaterial) { void saveMaterialTheme(bool isMaterial) {
settings.materialColor = isMaterial; _updateSetting((settings) => settings.materialColor = isMaterial);
isar.writeTxnSync(() => isar.settings.putSync(settings));
} }
void saveTheme(String themeMode) { void saveTheme(String themeMode) {
settings.theme = themeMode; _updateSetting((settings) => settings.theme = themeMode);
isar.writeTxnSync(() => isar.settings.putSync(settings));
} }
void changeTheme(ThemeData theme) => Get.changeTheme(theme); void changeTheme(ThemeData theme) => Get.changeTheme(theme);
void changeThemeMode(ThemeMode themeMode) => Get.changeThemeMode(themeMode); void changeThemeMode(ThemeMode themeMode) => Get.changeThemeMode(themeMode);
ThemeMode _getThemeMode() {
switch (settings.theme) {
case 'system':
return ThemeMode.system;
case 'dark':
return ThemeMode.dark;
default:
return ThemeMode.light;
}
}
void _updateSetting(void Function(Settings) update) {
update(settings);
isar.writeTxnSync(() => isar.settings.putSync(settings));
}
} }

267
lib/translation/bn_in.dart Normal file → Executable file
View file

@ -1,132 +1,141 @@
class BnIn { class BnIn {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'শুরু করুন', 'start': 'শুরু করুন',
'description': 'description':
'প্রতি ঘণ্টায়, দিনে এবং সপ্তাহের জন্য প্রতিষ্ঠানের জন্য সক্রিয় পূর্বাভাস সহ আবহাওয়া অ্যাপ্লিকেশন।', 'প্রতি ঘণ্টায়, দিনে এবং সপ্তাহের জন্য প্রতিষ্ঠানের জন্য সক্রিয় পূর্বাভাস সহ আবহাওয়া অ্যাপ্লিকেশন।',
'name': 'আবহাওয়া', 'name': 'আবহাওয়া',
'name2': 'সুবিধাজনক ডিজাইন', 'name2': 'সুবিধাজনক ডিজাইন',
'name3': 'আমাদের সাথে যোগাযোগ করুন', 'name3': 'আমাদের সাথে যোগাযোগ করুন',
'description2': 'description2':
'সমস্ত নেভিগেশনটি এমনভাবে তৈরি করা হয়েছে যাতে আপনি অ্যাপ্লিকেশনে সর্বোত্তম সুবিধায় এবং দ্রুত ইন্টারঅ্যাক্ট করতে পারেন।', 'সমস্ত নেভিগেশনটি এমনভাবে তৈরি করা হয়েছে যাতে আপনি অ্যাপ্লিকেশনে সর্বোত্তম সুবিধায় এবং দ্রুত ইন্টারঅ্যাক্ট করতে পারেন।',
'description3': 'description3':
'আপনার যদি কোনও সমস্যা হয়, অনুগ্রহ করে ইমেল বা অ্যাপ্লিকেশন পর্যালোচনার মাধ্যমে আমাদের সাথে যোগাযোগ করুন।', 'আপনার যদি কোনও সমস্যা হয়, অনুগ্রহ করে ইমেল বা অ্যাপ্লিকেশন পর্যালোচনার মাধ্যমে আমাদের সাথে যোগাযোগ করুন।',
'next': 'পরবর্তী', 'next': 'পরবর্তী',
'search': 'অনুসন্ধান...', 'search': 'অনুসন্ধান...',
'loading': 'লোড হচ্ছে...', 'loading': 'লোড হচ্ছে...',
'searchCity': 'আপনার শহর খুঁজুন', 'searchCity': 'আপনার শহর খুঁজুন',
'humidity': 'আর্দ্ধমন্দ', 'humidity': 'আর্দ্ধমন্দ',
'wind': 'বায়ু', 'wind': 'বায়ু',
'visibility': 'দৃশ্যতা', 'visibility': 'দৃশ্যতা',
'feels': 'অনুভব', 'feels': 'অনুভব',
'evaporation': 'অবপাত ও প্রবাহ', 'evaporation': 'অবপাত ও প্রবাহ',
'precipitation': 'বৃষ্টিপাত', 'precipitation': 'বৃষ্টিপাত',
'direction': 'দিশা', 'direction': 'দিশা',
'pressure': 'চাপ', 'pressure': 'চাপ',
'rain': 'বৃষ্টি', 'rain': 'বৃষ্টি',
'clear_sky': 'পরিষ্কার আকাশ', 'clear_sky': 'পরিষ্কার আকাশ',
'cloudy': 'মেঘলা', 'cloudy': 'মেঘলা',
'overcast': 'মেঘাচ্ছন্ন', 'overcast': 'মেঘাচ্ছন্ন',
'fog': 'কুয়াশা', 'fog': 'কুয়াশা',
'drizzle': 'বৃষ্টি বৃষ্টি', 'drizzle': 'বৃষ্টি বৃষ্টি',
'freezing_drizzle': 'শীতল বৃষ্টি', 'freezing_drizzle': 'শীতল বৃষ্টি',
'freezing_rain': 'শীতল বৃষ্টি', 'freezing_rain': 'শীতল বৃষ্টি',
'rain_showers': 'বৃষ্টির বৃষ্টি', 'rain_showers': 'বৃষ্টির বৃষ্টি',
'snow': 'তুষার', 'snow': 'তুষার',
'thunderstorm': 'বজ্রপাত', 'thunderstorm': 'বজ্রপাত',
'kph': 'কিমি/ঘণ্টা', 'kph': 'কিমি/ঘণ্টা',
'mph': 'মাইল/ঘণ্টা', 'mph': 'মাইল/ঘণ্টা',
'mi': 'মাইল', 'm/s': 'মি/সে',
'km': 'কিমি', 'mmHg': 'মিমি Hg',
'inch': 'ইঞ্চ', 'mi': 'মাইল',
'mm': 'মিমি', 'km': 'কিমি',
'hPa': 'হেক্টোপাস্কল', 'inch': 'ইঞ্চ',
'settings': 'সেটিংস', 'mm': 'মিমি',
'no_inter': 'ইন্টারনেট নেই', 'hPa': 'হেক্টোপাস্কল',
'on_inter': 'মেটিয়োরোলজিক তথ্য পেতে ইন্টারনেট চালু করুন।', 'settings': 'সেটিংস',
'location': 'অবস্থান', 'no_inter': 'ইন্টারনেট নেই',
'no_location': 'on_inter': 'মেটিয়োরোলজিক তথ্য পেতে ইন্টারনেট চালু করুন।',
'বর্তমান অবস্থানের জন্য আবহাওয়া ডেটা পেতে অবস্থান সেবা সক্রিয় করুন।', 'location': 'অবস্থান',
'theme': 'থিম', 'no_location':
'low': 'নিম্ন', 'বর্তমান অবস্থানের জন্য আবহাওয়া ডেটা পেতে অবস্থান সেবা সক্রিয় করুন।',
'high': 'উচ্চ', 'theme': 'থিম',
'normal': 'সাধারণ', 'low': 'নিম্ন',
'lat': 'অক্ষাংশ', 'high': 'উচ্চ',
'lon': 'দ্রাঘিমাংশ', 'normal': 'সাধারণ',
'create': 'তৈরি করুন', 'lat': 'অক্ষাংশ',
'city': 'শহর', 'lon': 'দ্রাঘিমাংশ',
'district': 'জেলা', 'create': 'তৈরি করুন',
'noWeatherCard': 'একটি শহর যোগ করুন', 'city': 'শহর',
'deletedCardWeather': 'একটি শহর মুছে ফেলা হচ্ছে', 'district': 'জেলা',
'deletedCardWeatherQuery': 'আপনি কি নিশ্চিত যে আপনি শহরটি মুছতে চান?', 'noWeatherCard': 'একটি শহর যোগ করুন',
'delete': 'মুছে ফেলুন', 'deletedCardWeather': 'একটি শহর মুছে ফেলা হচ্ছে',
'cancel': 'বাতিল করুন', 'deletedCardWeatherQuery': 'আপনি কি নিশ্চিত যে আপনি শহরটি মুছতে চান?',
'time': 'শহরে সময়', 'delete': 'মুছে ফেলুন',
'validateName': 'দয়া করে নাম লিখুন', 'cancel': 'বাতিল করুন',
'measurements': 'মাপনের সিস্টেম', 'time': 'শহরে সময়',
'degrees': 'ডিগ্রি', 'validateName': 'দয়া করে নাম লিখুন',
'celsius': 'সেলসিয়াস', 'measurements': 'মাপনের সিস্টেম',
'fahrenheit': 'ফারেনহাইট', 'degrees': 'ডিগ্রি',
'imperial': 'ইমপেরিয়াল', 'celsius': 'সেলসিয়াস',
'metric': 'মেট্রিক', 'fahrenheit': 'ফারেনহাইট',
'validateValue': 'দয়া করে একটি মান লিখুন', 'imperial': 'ইমপেরিয়াল',
'validateNumber': 'দয়া করে একটি বৈধ সংখ্যা লিখুন', 'metric': 'মেট্রিক',
'validate90': 'মান -৯০ থেকে ৯০ মধ্যে হতে হবে', 'validateValue': 'দয়া করে একটি মান লিখুন',
'validate180': 'মান -১৮০ থেকে ১৮০ মধ্যে হতে হবে', 'validateNumber': 'দয়া করে একটি বৈধ সংখ্যা লিখুন',
'notifications': 'বিজ্ঞপ্তি', 'validate90': 'মান -৯০ থেকে ৯০ মধ্যে হতে হবে',
'sunrise': 'সূর্যোদয়', 'validate180': 'মান -১৮০ থেকে ১৮০ মধ্যে হতে হবে',
'sunset': 'সূর্যাস্ত', 'notifications': 'বিজ্ঞপ্তি',
'timeformat': 'সময় বিন্যাস', 'sunrise': 'সূর্যোদয়',
'12': '১২-ঘণ্টা', 'sunset': 'সূর্যাস্ত',
'24': '২৪-ঘণ্টা', 'timeformat': 'সময় বিন্যাস',
'cloudcover': 'মেঘপর্দা', '12': '১২-ঘণ্টা',
'uvIndex': 'আল্ট্রাভায়োলেট-সূচী', '24': '২৪-ঘণ্টা',
'materialColor': 'গতিবিধির রঙ', 'cloudcover': 'মেঘপর্দা',
'uvLow': 'নিম্ন', 'uvIndex': 'আল্ট্রাভায়োলেট-সূচী',
'uvAverage': 'মধ্যম', 'materialColor': 'গতিবিধির রঙ',
'uvHigh': 'উচ্চ', 'uvLow': 'নিম্ন',
'uvVeryHigh': 'অত্যন্ত উচ্চ', 'uvAverage': 'মধ্যম',
'uvExtreme': 'একাধিক', 'uvHigh': 'উচ্চ',
'weatherMore': '১২-দিনের আবহাওয়া পূর্বানুমান', 'uvVeryHigh': 'অত্যন্ত উচ্চ',
'windgusts': 'ঝংকার', 'uvExtreme': 'একাধিক',
'north': 'উত্তর', 'weatherMore': '১২-দিনের আবহাওয়া পূর্বানুমান',
'northeast': 'উত্তরপূর্ব', 'windgusts': 'ঝংকার',
'east': 'পূর্ব', 'north': 'উত্তর',
'southeast': 'দক্ষিণপূর্ব', 'northeast': 'উত্তরপূর্ব',
'south': 'দক্ষিণ', 'east': 'পূর্ব',
'southwest': 'দক্ষিণপশ্চিম', 'southeast': 'দক্ষিণপূর্ব',
'west': 'পশ্চিম', 'south': 'দক্ষিণ',
'northwest': 'উত্তরপশ্চিম', 'southwest': 'দক্ষিণপশ্চিম',
'project': 'প্রকল্প', 'west': 'পশ্চিম',
'version': 'অ্যাপ্লিকেশন সংস্করণ', 'northwest': 'উত্তরপশ্চিম',
'precipitationProbability': 'বৃষ্টিপাতের সম্ভাবনা', 'project': 'প্রকল্প',
'apparentTemperatureMin': 'version': 'অ্যাপ্লিকেশন সংস্করণ',
'ন্যায্য ন্যায্য তাপমাত্রা ন্যায্য ন্যায্য ন্যায্য ন্যায্য ন্যায্য ন্যায্য ন্যায্য', 'precipitationProbability': 'বৃষ্টিপাতের সম্ভাবনা',
'apparentTemperatureMax': 'সর্বাধিক ন্যায্য তাপমাত্রা', 'apparentTemperatureMin':
'amoledTheme': 'এমোলেড-থিম', 'ন্যায্য ন্যায্য তাপমাত্রা ন্যায্য ন্যায্য ন্যায্য ন্যায্য ন্যায্য ন্যায্য ন্যায্য',
'appearance': 'উপস্থিতি', 'apparentTemperatureMax': 'সর্বাধিক ন্যায্য তাপমাত্রা',
'functions': 'কার্য', 'amoledTheme': 'এমোলেড-থিম',
'data': 'ডেটা', 'appearance': 'উপস্থিতি',
'language': 'ভাষা', 'functions': 'কার্য',
'timeRange': 'সময় পরিস্থিতি (ঘণ্টায়)', 'data': 'ডেটা',
'timeStart': 'শুরুর সময়', 'language': 'ভাষা',
'timeEnd': 'শেষ সময়', 'timeRange': 'সময় পরিস্থিতি (ঘণ্টায়)',
'support': 'সাহায্য', 'timeStart': 'শুরুর সময়',
'system': 'সিস্টেম', 'timeEnd': 'শেষ সময়',
'dark': 'ডার্ক', 'support': 'সাহায্য',
'light': 'আলো', 'system': 'সিস্টেম',
'license': 'লাইসেন্স', 'dark': 'ডার্ক',
'widget': 'উইজেট', 'light': 'আলো',
'widgetBackground': 'উইজেট পেশা', 'license': 'লাইসেন্স',
'widgetText': 'উইজেট টেক্সট', 'widget': 'উইজেট',
'dewpoint': 'তুষার বিন্দু', 'widgetBackground': 'উইজেট পেশা',
'shortwaveRadiation': 'সংক্ষেপণ তরঙ্গ প্রকৃতি', 'widgetText': 'উইজেট টেক্সট',
'W/m2': 'ডব্লিউ/মিটার বর্গ', 'dewpoint': 'তুষার বিন্দু',
'roundDegree': 'ডিগ্রি রাউন্ড করুন', 'shortwaveRadiation': 'সংক্ষেপণ তরঙ্গ প্রকৃতি',
'settings_full': 'সেটিংস', 'W/m2': 'ডব্লিউ/মিটার বর্গ',
'cities': 'শহর', 'roundDegree': 'ডিগ্রি রাউন্ড করুন',
'groups': 'আমাদের দলগুলি', 'settings_full': 'সেটিংস',
'openMeteo': 'Open-Meteo থেকে ডেটা (CC-BY 4.0)', 'cities': 'শহর',
'hourlyVariables': 'ঘণ্টায় আবহাওয়ার পরিবর্তনশীল', 'groups': 'আমাদের দলগুলি',
'dailyVariables': 'দৈনিক আবহাওয়ার পরিবর্তনশীল', 'openMeteo': 'Open-Meteo থেকে ডেটা (CC-BY 4.0)',
}; 'hourlyVariables': 'ঘণ্টায় আবহাওয়ার পরিবর্তনশীল',
'dailyVariables': 'দৈনিক আবহাওয়ার পরিবর্তনশীল',
'largeElement': 'বড় আবহাওয়া ডিসপ্লে',
'map': 'মানচিত্র',
'clearCacheStore': 'ক্যাশ পরিষ্কার করুন',
'deletedCacheStore': 'ক্যাশ পরিষ্কার করা হচ্ছে',
'deletedCacheStoreQuery': 'আপনি কি সত্যিই ক্যাশ পরিষ্কার করতে চান?',
'addWidget': 'উইজেট যোগ করুন',
'hideMap': 'মানচিত্র লুকান',
};
} }

267
lib/translation/cs_cz.dart Normal file → Executable file
View file

@ -1,132 +1,141 @@
class CsCz { class CsCz {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Začít', 'start': 'Začít',
'description': 'description':
'Aplikace počasí s aktuálním předpovědí na každou hodinu, den a týden pro libovolné místo.', 'Aplikace počasí s aktuálním předpovědí na každou hodinu, den a týden pro libovolné místo.',
'name': 'Počasí', 'name': 'Počasí',
'name2': 'Pohodlný design', 'name2': 'Pohodlný design',
'name3': 'Kontaktujte nás', 'name3': 'Kontaktujte nás',
'description2': 'description2':
'Celá navigace je navržena tak, aby bylo možné s aplikací co nejpohodlněji a nejrychleji interagovat.', 'Celá navigace je navržena tak, aby bylo možné s aplikací co nejpohodlněji a nejrychleji interagovat.',
'description3': 'description3':
'Pokud narazíte na nějaké potíže, kontaktujte nás prosím e-mailem nebo v recenzích aplikace.', 'Pokud narazíte na nějaké potíže, kontaktujte nás prosím e-mailem nebo v recenzích aplikace.',
'next': 'Další', 'next': 'Další',
'search': 'Hledat...', 'search': 'Hledat...',
'loading': 'Načítá se...', 'loading': 'Načítá se...',
'searchCity': 'Najděte své místo', 'searchCity': 'Najděte své místo',
'humidity': 'Vlhkost', 'humidity': 'Vlhkost',
'wind': 'Vítr', 'wind': 'Vítr',
'visibility': 'Viditelnost', 'visibility': 'Viditelnost',
'feels': 'Pocitová teplota', 'feels': 'Pocitová teplota',
'evaporation': 'Evapotranspirace', 'evaporation': 'Evapotranspirace',
'precipitation': 'Srážky', 'precipitation': 'Srážky',
'direction': 'Směr', 'direction': 'Směr',
'pressure': 'Tlak', 'pressure': 'Tlak',
'rain': 'Déšť', 'rain': 'Déšť',
'clear_sky': 'Jasno', 'clear_sky': 'Jasno',
'cloudy': 'Oblačno', 'cloudy': 'Oblačno',
'overcast': 'Zataženo', 'overcast': 'Zataženo',
'fog': 'Mlha', 'fog': 'Mlha',
'drizzle': 'Mrholení', 'drizzle': 'Mrholení',
'drizzling_rain': 'Mrznúce mrholení', 'drizzling_rain': 'Mrznúce mrholení',
'freezing_rain': 'Mrazivý déšť', 'freezing_rain': 'Mrazivý déšť',
'heavy_rains': 'Přeháňky', 'heavy_rains': 'Přeháňky',
'snow': 'Sníh', 'snow': 'Sníh',
'thunderstorm': 'Bouřka', 'thunderstorm': 'Bouřka',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'inch', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'inch',
'settings': 'Nast.', 'mm': 'mm',
'no_inter': 'Žádný internet', 'hPa': 'hPa',
'on_inter': 'Připojte se k internetu a získejte meteorologické údaje.', 'settings': 'Nast.',
'location': 'Poloha', 'no_inter': 'Žádný internet',
'no_location': 'on_inter': 'Připojte se k internetu a získejte meteorologické údaje.',
'Chcete-li získat údaje o počasí pro aktuální polohu, povolte službu určování polohy.', 'location': 'Poloha',
'theme': 'Téma', 'no_location':
'low': 'Nízký', 'Chcete-li získat údaje o počasí pro aktuální polohu, povolte službu určování polohy.',
'high': 'Vysoký', 'theme': 'Téma',
'normal': 'Normální', 'low': 'Nízký',
'lat': 'Zeměpisná šířka', 'high': 'Vysoký',
'lon': 'Zemepisná délka', 'normal': 'Normální',
'create': 'Vytvořit', 'lat': 'Zeměpisná šířka',
'city': 'Místo', 'lon': 'Zemepisná délka',
'district': 'Okres', 'create': 'Vytvořit',
'noWeatherCard': 'Přidat město', 'city': 'Místo',
'deletedCardWeather': 'Vymazat město', 'district': 'Okres',
'deletedCardWeatherQuery': 'Opravdu chcete odstranit město?', 'noWeatherCard': 'Přidat město',
'delete': 'Odstranit', 'deletedCardWeather': 'Vymazat město',
'cancel': 'Zrušit', 'deletedCardWeatherQuery': 'Opravdu chcete odstranit město?',
'time': 'Čas ve městě', 'delete': 'Odstranit',
'validateName': 'Prosím zadejte název', 'cancel': 'Zrušit',
'measurements': 'Jednotky měření', 'time': 'Čas ve městě',
'degrees': 'Stupně', 'validateName': 'Prosím zadejte název',
'celsius': 'Celzius', 'measurements': 'Jednotky měření',
'fahrenheit': 'Fahrenheit', 'degrees': 'Stupně',
'imperial': 'Imperiální', 'celsius': 'Celzius',
'metric': 'Metrické', 'fahrenheit': 'Fahrenheit',
'validateValue': 'Zadejte hodnotu', 'imperial': 'Imperiální',
'validateNumber': 'Zadejte platné číslo', 'metric': 'Metrické',
'validate90': 'Hodnota musí být mezi -90 a 90', 'validateValue': 'Zadejte hodnotu',
'validate180': 'Hodnota musí být mezi -180 a 180', 'validateNumber': 'Zadejte platné číslo',
'notifications': 'Notifikace', 'validate90': 'Hodnota musí být mezi -90 a 90',
'sunrise': 'Východ slunce', 'validate180': 'Hodnota musí být mezi -180 a 180',
'sunset': 'Západ slunce', 'notifications': 'Notifikace',
'timeformat': 'Formát času', 'sunrise': 'Východ slunce',
'12': '12-hodinový', 'sunset': 'Západ slunce',
'24': '24-hodinový', 'timeformat': 'Formát času',
'cloudcover': 'Oblačnost', '12': '12-hodinový',
'uvIndex': 'UV-index', '24': '24-hodinový',
'materialColor': 'Dynamické Barvy', 'cloudcover': 'Oblačnost',
'uvLow': 'Nízký', 'uvIndex': 'UV-index',
'uvAverage': 'Mírný', 'materialColor': 'Dynamické Barvy',
'uvHigh': 'Vysoký', 'uvLow': 'Nízký',
'uvVeryHigh': 'Velmi vysoký', 'uvAverage': 'Mírný',
'uvExtreme': 'Extrémní', 'uvHigh': 'Vysoký',
'weatherMore': 'Předpověď počasí na 12 dní', 'uvVeryHigh': 'Velmi vysoký',
'windgusts': 'Nárazy větru', 'uvExtreme': 'Extrémní',
'north': 'Sever', 'weatherMore': 'Předpověď počasí na 12 dní',
'northeast': 'Severo-Východ', 'windgusts': 'Nárazy větru',
'east': 'Východ', 'north': 'Sever',
'southeast': 'Juhovýchod', 'northeast': 'Severo-Východ',
'south': 'Juž', 'east': 'Východ',
'southwest': 'Juhozápad', 'southeast': 'Juhovýchod',
'west': 'Západ', 'south': 'Juž',
'northwest': 'Severo-Západ', 'southwest': 'Juhozápad',
'project': 'Projekt na', 'west': 'Západ',
'version': 'Verzia aplikace', 'northwest': 'Severo-Západ',
'precipitationProbability': 'Pravděpodobnost srážek', 'project': 'Projekt na',
'apparentTemperatureMin': 'Minimální pocitová teplota', 'version': 'Verzia aplikace',
'apparentTemperatureMax': 'Maximální pocitová teplota', 'precipitationProbability': 'Pravděpodobnost srážek',
'amoledTheme': 'AMOLED-téma', 'apparentTemperatureMin': 'Minimální pocitová teplota',
'appearance': 'Vzhled', 'apparentTemperatureMax': 'Maximální pocitová teplota',
'functions': 'Funkce', 'amoledTheme': 'AMOLED-téma',
'data': 'Data', 'appearance': 'Vzhled',
'language': 'Jazyk', 'functions': 'Funkce',
'timeRange': 'Frekvence (v hodinách)', 'data': 'Data',
'timeStart': 'Čas začátku', 'language': 'Jazyk',
'timeEnd': 'Čas ukončení', 'timeRange': 'Frekvence (v hodinách)',
'support': 'Podpora', 'timeStart': 'Čas začátku',
'system': 'Systém', 'timeEnd': 'Čas ukončení',
'dark': 'Tmavá', 'support': 'Podpora',
'light': 'Světlá', 'system': 'Systém',
'license': 'Licence', 'dark': 'Tmavá',
'widget': 'Widget', 'light': 'Světlá',
'widgetBackground': 'Pozadí widgetu', 'license': 'Licence',
'widgetText': 'Text widgetu', 'widget': 'Widget',
'dewpoint': 'Rosný bod', 'widgetBackground': 'Pozadí widgetu',
'shortwaveRadiation': 'Krátká vlnová radiace', 'widgetText': 'Text widgetu',
'roundDegree': 'Zaokrouhlit stupně', 'dewpoint': 'Rosný bod',
'settings_full': 'Nastavení', 'shortwaveRadiation': 'Krátká vlnová radiace',
'cities': 'Města', 'roundDegree': 'Zaokrouhlit stupně',
'searchMethod': 'Použijte hledání nebo geolokaci', 'settings_full': 'Nastavení',
'done': 'Hotovo', 'cities': 'Města',
'groups': 'Naše skupiny', 'searchMethod': 'Použijte hledání nebo geolokaci',
'openMeteo': 'Data z Open-Meteo (CC-BY 4.0)', 'done': 'Hotovo',
'hourlyVariables': 'Hodinové meteorologické proměnné', 'groups': 'Naše skupiny',
'dailyVariables': 'Denní meteorologické proměnné', 'openMeteo': 'Data z Open-Meteo (CC-BY 4.0)',
}; 'hourlyVariables': 'Hodinové meteorologické proměnné',
'dailyVariables': 'Denní meteorologické proměnné',
'largeElement': 'Velké zobrazení počasí',
'map': 'Mapa',
'clearCacheStore': 'Vymazat mezipaměť',
'deletedCacheStore': 'Čištění mezipaměti',
'deletedCacheStoreQuery': 'Opravdu chcete vymazat mezipaměť?',
'addWidget': 'Přidat widget',
'hideMap': 'Skrýt mapu',
};
} }

269
lib/translation/da_dk.dart Normal file → Executable file
View file

@ -1,133 +1,142 @@
class DaDk { class DaDk {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Kom i gang', 'start': 'Kom i gang',
'description': 'description':
'Vejr app med en opdateret vejrudsigt for hver time, dag og uge for ethvert sted.', 'Vejr app med en opdateret vejrudsigt for hver time, dag og uge for ethvert sted.',
'name': 'Vejr', 'name': 'Vejr',
'name2': 'Praktisk design', 'name2': 'Praktisk design',
'name3': 'Kontakt os', 'name3': 'Kontakt os',
'description2': 'description2':
'Al navigation er designet til at interagere med appen så bekvemt og hurtigt som muligt.', 'Al navigation er designet til at interagere med appen så bekvemt og hurtigt som muligt.',
'description3': 'description3':
'Hvis du støder på problemer, må du meget gerne kontakte os via e-mail eller i app anmeldelserne.', 'Hvis du støder på problemer, må du meget gerne kontakte os via e-mail eller i app anmeldelserne.',
'next': 'Næste', 'next': 'Næste',
'search': 'Søg...', 'search': 'Søg...',
'loading': 'Henter...', 'loading': 'Henter...',
'searchCity': 'Find din by', 'searchCity': 'Find din by',
'humidity': 'Luftfugtighed', 'humidity': 'Luftfugtighed',
'wind': 'Vind', 'wind': 'Vind',
'visibility': 'Sigtbarhed', 'visibility': 'Sigtbarhed',
'feels': 'Føles som', 'feels': 'Føles som',
'evaporation': 'Fordampning', 'evaporation': 'Fordampning',
'precipitation': 'Nedbør', 'precipitation': 'Nedbør',
'direction': 'Retning', 'direction': 'Retning',
'pressure': 'Tryk', 'pressure': 'Tryk',
'rain': 'Regn', 'rain': 'Regn',
'clear_sky': 'Skyfri himmel', 'clear_sky': 'Skyfri himmel',
'cloudy': 'Skyet', 'cloudy': 'Skyet',
'overcast': 'Overskyet', 'overcast': 'Overskyet',
'fog': 'Tåge', 'fog': 'Tåge',
'drizzle': 'Støv regn', 'drizzle': 'Støv regn',
'drizzling_rain': 'Frysende støvregn', 'drizzling_rain': 'Frysende støvregn',
'freezing_rain': 'Frostregn', 'freezing_rain': 'Frostregn',
'heavy_rains': 'Regnskyl', 'heavy_rains': 'Regnskyl',
'snow': 'Sne', 'snow': 'Sne',
'thunderstorm': 'Tordenvejr', 'thunderstorm': 'Tordenvejr',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'tommer', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'tommer',
'settings': 'Inds.', 'mm': 'mm',
'no_inter': 'Ingen Internet', 'hPa': 'hPa',
'on_inter': 'Tænd for internettet for at få meteorologisk data.', 'settings': 'Inds.',
'location': 'Placering', 'no_inter': 'Ingen Internet',
'no_location': 'on_inter': 'Tænd for internettet for at få meteorologisk data.',
'Aktiver placeringer for at få vejrdata for den aktuelle placering.', 'location': 'Placering',
'theme': 'Tema', 'no_location':
'low': 'Lav', 'Aktiver placeringer for at få vejrdata for den aktuelle placering.',
'high': 'Høj', 'theme': 'Tema',
'normal': 'Normal', 'low': 'Lav',
'lat': 'Breddegrad', 'high': 'Høj',
'lon': 'Længdegrad', 'normal': 'Normal',
'create': 'Opret', 'lat': 'Breddegrad',
'city': 'By', 'lon': 'Længdegrad',
'district': 'Distrikt', 'create': 'Opret',
'noWeatherCard': 'Tilføj en by', 'city': 'By',
'deletedCardWeather': 'Slet en by', 'district': 'Distrikt',
'deletedCardWeatherQuery': 'Er du sikker på at du vil slette denne by?', 'noWeatherCard': 'Tilføj en by',
'delete': 'Slet', 'deletedCardWeather': 'Slet en by',
'cancel': 'Annullere', 'deletedCardWeatherQuery': 'Er du sikker på at du vil slette denne by?',
'time': 'Tid i byen', 'delete': 'Slet',
'validateName': 'Indtast venligst navnet', 'cancel': 'Annullere',
'measurements': 'Foranstaltningssystemet', 'time': 'Tid i byen',
'degrees': 'Grader', 'validateName': 'Indtast venligst navnet',
'celsius': 'Celsius', 'measurements': 'Foranstaltningssystemet',
'fahrenheit': 'Fahrenheit', 'degrees': 'Grader',
'imperial': 'Imperialistisk', 'celsius': 'Celsius',
'metric': 'Metrisk', 'fahrenheit': 'Fahrenheit',
'validateValue': 'Indtast en værdi', 'imperial': 'Imperialistisk',
'validateNumber': 'Indtast et gyldigt nummer', 'metric': 'Metrisk',
'validate90': 'Værdien skal være mellem -90 og 90', 'validateValue': 'Indtast en værdi',
'validate180': 'Værdien skal være mellem -180 og 180', 'validateNumber': 'Indtast et gyldigt nummer',
'notifications': 'Notifikationer', 'validate90': 'Værdien skal være mellem -90 og 90',
'sunrise': 'Solopgang', 'validate180': 'Værdien skal være mellem -180 og 180',
'sunset': 'Solnedgang', 'notifications': 'Notifikationer',
'timeformat': 'Tids format', 'sunrise': 'Solopgang',
'12': '12-timer', 'sunset': 'Solnedgang',
'24': '24-timer', 'timeformat': 'Tids format',
'cloudcover': 'skydække', '12': '12-timer',
'uvIndex': 'UV-index', '24': '24-timer',
'materialColor': 'Dynamiske farver', 'cloudcover': 'skydække',
'uvLow': 'Lav', 'uvIndex': 'UV-index',
'uvAverage': 'Moderat', 'materialColor': 'Dynamiske farver',
'uvHigh': 'Høj', 'uvLow': 'Lav',
'uvVeryHigh': 'Meget højt', 'uvAverage': 'Moderat',
'uvExtreme': 'Ekstrem', 'uvHigh': 'Høj',
'weatherMore': '12 dages vejrudsigt', 'uvVeryHigh': 'Meget højt',
'windgusts': 'Vindstød', 'uvExtreme': 'Ekstrem',
'north': 'Nord', 'weatherMore': '12 dages vejrudsigt',
'northeast': 'Nordøst', 'windgusts': 'Vindstød',
'east': 'Øst', 'north': 'Nord',
'southeast': 'Sydøst', 'northeast': 'Nordøst',
'south': 'Syd', 'east': 'Øst',
'southwest': 'Sydvest', 'southeast': 'Sydøst',
'west': 'Vest', 'south': 'Syd',
'northwest': 'Nordvest', 'southwest': 'Sydvest',
'project': 'Projektet findes på', 'west': 'Vest',
'version': 'App version', 'northwest': 'Nordvest',
'precipitationProbability': 'Sandsynlighed for nedbør', 'project': 'Projektet findes på',
'apparentTemperatureMin': 'Minimum temperature', 'version': 'App version',
'apparentTemperatureMax': 'Maksimal temperatur', 'precipitationProbability': 'Sandsynlighed for nedbør',
'amoledTheme': 'AMOLED-tema', 'apparentTemperatureMin': 'Minimum temperature',
'appearance': 'Udseende', 'apparentTemperatureMax': 'Maksimal temperatur',
'functions': 'Funktioner', 'amoledTheme': 'AMOLED-tema',
'data': 'Data', 'appearance': 'Udseende',
'language': 'Sprog', 'functions': 'Funktioner',
'timeRange': 'Hyppighed (i timer)', 'data': 'Data',
'timeStart': 'Start tid', 'language': 'Sprog',
'timeEnd': 'Slut tid', 'timeRange': 'Hyppighed (i timer)',
'support': 'Support', 'timeStart': 'Start tid',
'system': 'System', 'timeEnd': 'Slut tid',
'dark': 'Mørk', 'support': 'Support',
'light': 'Lys', 'system': 'System',
'license': 'Licenser', 'dark': 'Mørk',
'widget': 'Widget', 'light': 'Lys',
'widgetBackground': 'Widget baggrund', 'license': 'Licenser',
'widgetText': 'Widget tekst', 'widget': 'Widget',
'dewpoint': 'Dugpunktet', 'widgetBackground': 'Widget baggrund',
'shortwaveRadiation': 'Kortbølgestråling', 'widgetText': 'Widget tekst',
'W/m2': 'W/m2', 'dewpoint': 'Dugpunktet',
'roundDegree': 'Afrundede grader', 'shortwaveRadiation': 'Kortbølgestråling',
'settings_full': 'Indstillinger', 'W/m2': 'W/m2',
'cities': 'Byer', 'roundDegree': 'Afrundede grader',
'searchMethod': 'Brug søgning eller geolokation', 'settings_full': 'Indstillinger',
'done': 'Færdig', 'cities': 'Byer',
'groups': 'Vores grupper', 'searchMethod': 'Brug søgning eller geolokation',
'openMeteo': 'Data fra Open-Meteo (CC-BY 4.0)', 'done': 'Færdig',
'hourlyVariables': 'Timevise vejrfaktorer', 'groups': 'Vores grupper',
'dailyVariables': 'Daglige vejrfaktorer', 'openMeteo': 'Data fra Open-Meteo (CC-BY 4.0)',
}; 'hourlyVariables': 'Timevise vejrfaktorer',
'dailyVariables': 'Daglige vejrfaktorer',
'largeElement': 'Stort vejrdisplay',
'map': 'Kort',
'clearCacheStore': 'Ryd cache',
'deletedCacheStore': 'Rydder cache',
'deletedCacheStoreQuery': 'Er du sikker på, at du vil rydde cachen?',
'addWidget': 'Tilføj widget',
'hideMap': 'Skjul kort',
};
} }

272
lib/translation/de_de.dart Normal file → Executable file
View file

@ -1,134 +1,144 @@
class DeDe { class DeDe {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Los gehts', 'start': 'Los gehts',
'description': 'description':
'Wetteranwendung mit einer aktuellen Prognose für jede Stunde, Tag und Woche für jeden Ort.', 'Wetteranwendung mit einer aktuellen Prognose für jede Stunde, Tag und Woche für jeden Ort.',
'name': 'Wetter', 'name': 'Wetter',
'name2': 'Bequemes Design', 'name2': 'Bequemes Design',
'name3': 'Kontaktiere uns', 'name3': 'Kontaktiere uns',
'description2': 'description2':
'Die gesamte Navigation ist so gestaltet, dass die Interaktion mit der Anwendung so bequem und schnell wie möglich erfolgt.', 'Die gesamte Navigation ist so gestaltet, dass die Interaktion mit der Anwendung so bequem und schnell wie möglich erfolgt.',
'description3': 'description3':
'Wenn Sie auf Probleme stoßen, kontaktieren Sie uns bitte per E-Mail oder in den Bewertungen der Anwendung.', 'Wenn Sie auf Probleme stoßen, kontaktieren Sie uns bitte per E-Mail oder in den Bewertungen der Anwendung.',
'next': 'Weiter', 'next': 'Weiter',
'search': 'Suchen...', 'search': 'Suchen...',
'loading': 'Lädt...', 'loading': 'Lädt...',
'searchCity': 'Finde deine Stadt', 'searchCity': 'Finde deine Stadt',
'humidity': 'Luftfeuchtigkeit', 'humidity': 'Luftfeuchtigkeit',
'wind': 'Wind', 'wind': 'Wind',
'visibility': 'Sichtweite', 'visibility': 'Sichtweite',
'feels': 'Gefühlt', 'feels': 'Gefühlt',
'evaporation': 'Verdunstung', 'evaporation': 'Verdunstung',
'precipitation': 'Niederschlag', 'precipitation': 'Niederschlag',
'direction': 'Richtung', 'direction': 'Richtung',
'pressure': 'Druck', 'pressure': 'Druck',
'rain': 'Regen', 'rain': 'Regen',
'clear_sky': 'Klarer Himmel', 'clear_sky': 'Klarer Himmel',
'cloudy': 'Bewölkt', 'cloudy': 'Bewölkt',
'overcast': 'Bedeckt', 'overcast': 'Bedeckt',
'fog': 'Nebel', 'fog': 'Nebel',
'drizzle': 'Nieselregen', 'drizzle': 'Nieselregen',
'drizzling_rain': 'Gefrierender Nieselregen', 'drizzling_rain': 'Gefrierender Nieselregen',
'freezing_rain': 'Gefrierender Regen', 'freezing_rain': 'Gefrierender Regen',
'heavy_rains': 'Regenschauer', 'heavy_rains': 'Regenschauer',
'snow': 'Schnee', 'snow': 'Schnee',
'thunderstorm': 'Gewitter', 'thunderstorm': 'Gewitter',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'inch', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'inch',
'settings': 'Einstellungen', 'mm': 'mm',
'no_inter': 'Keine Internetverbindung', 'hPa': 'hPa',
'on_inter': 'settings': 'Einstellungen',
'Schalte das Internet ein, um meteorologische Daten zu erhalten.', 'no_inter': 'Keine Internetverbindung',
'location': 'Standort', 'on_inter':
'no_location': 'Schalte das Internet ein, um meteorologische Daten zu erhalten.',
'Aktiviere den Standortdienst, um Wetterdaten für den aktuellen Standort zu erhalten.', 'location': 'Standort',
'theme': 'Thema', 'no_location':
'low': 'Niedrig', 'Aktiviere den Standortdienst, um Wetterdaten für den aktuellen Standort zu erhalten.',
'high': 'Hoch', 'theme': 'Thema',
'normal': 'Normal', 'low': 'Niedrig',
'lat': 'Breitengrad', 'high': 'Hoch',
'lon': 'Längengrad', 'normal': 'Normal',
'create': 'Erstellen', 'lat': 'Breitengrad',
'city': 'Stadt', 'lon': 'Längengrad',
'district': 'Bezirk', 'create': 'Erstellen',
'noWeatherCard': 'Füge eine Stadt hinzu', 'city': 'Stadt',
'deletedCardWeather': 'Stadt löschen', 'district': 'Bezirk',
'deletedCardWeatherQuery': 'noWeatherCard': 'Füge eine Stadt hinzu',
'Sind Sie sicher, dass Sie die Stadt löschen möchten?', 'deletedCardWeather': 'Stadt löschen',
'delete': 'Löschen', 'deletedCardWeatherQuery':
'cancel': 'Abbrechen', 'Sind Sie sicher, dass Sie die Stadt löschen möchten?',
'time': 'Ortszeit', 'delete': 'Löschen',
'validateName': 'Bitte geben Sie den Namen ein', 'cancel': 'Abbrechen',
'measurements': 'Einheitensystem', 'time': 'Ortszeit',
'degrees': 'Grade', 'validateName': 'Bitte geben Sie den Namen ein',
'celsius': 'Celsius', 'measurements': 'Einheitensystem',
'fahrenheit': 'Fahrenheit', 'degrees': 'Grade',
'imperial': 'Imperial', 'celsius': 'Celsius',
'metric': 'Metrisch', 'fahrenheit': 'Fahrenheit',
'validateValue': 'Bitte geben Sie einen Wert ein', 'imperial': 'Imperial',
'validateNumber': 'Bitte geben Sie eine Nummer ein', 'metric': 'Metrisch',
'validate90': 'Der Wert muss zwischen -90 und 90 liegen', 'validateValue': 'Bitte geben Sie einen Wert ein',
'validate180': 'Der Wert muss zwischen -180 und 180 liegen', 'validateNumber': 'Bitte geben Sie eine Nummer ein',
'notifications': 'Benachrichtigungen', 'validate90': 'Der Wert muss zwischen -90 und 90 liegen',
'sunrise': 'Sonnenaufgang', 'validate180': 'Der Wert muss zwischen -180 und 180 liegen',
'sunset': 'Sonnenuntergang', 'notifications': 'Benachrichtigungen',
'timeformat': 'Zeitformat', 'sunrise': 'Sonnenaufgang',
'12': '12-stunden', 'sunset': 'Sonnenuntergang',
'24': '24-stunden', 'timeformat': 'Zeitformat',
'cloudcover': 'Wolkenbedeckung', '12': '12-stunden',
'uvIndex': 'UV-index', '24': '24-stunden',
'materialColor': 'Dynamische Farben', 'cloudcover': 'Wolkenbedeckung',
'uvLow': 'Niedrig', 'uvIndex': 'UV-index',
'uvAverage': 'Mäßig', 'materialColor': 'Dynamische Farben',
'uvHigh': 'Hoch', 'uvLow': 'Niedrig',
'uvVeryHigh': 'Sehr hoch', 'uvAverage': 'Mäßig',
'uvExtreme': 'Extrem', 'uvHigh': 'Hoch',
'weatherMore': '12-Tage-Wettervorhersage', 'uvVeryHigh': 'Sehr hoch',
'windgusts': 'Böe', 'uvExtreme': 'Extrem',
'north': 'Norden', 'weatherMore': '12-Tage-Wettervorhersage',
'northeast': 'Nordosten', 'windgusts': 'Böe',
'east': 'Osten', 'north': 'Norden',
'southeast': 'Südosten', 'northeast': 'Nordosten',
'south': 'Süden', 'east': 'Osten',
'southwest': 'Südwesten', 'southeast': 'Südosten',
'west': 'Westen', 'south': 'Süden',
'northwest': 'Nordwesten', 'southwest': 'Südwesten',
'project': 'Projekt auf', 'west': 'Westen',
'version': 'Anwendungsversion', 'northwest': 'Nordwesten',
'precipitationProbability': 'Niederschlagswahrscheinlichkeit', 'project': 'Projekt auf',
'apparentTemperatureMin': 'Minimale gefühlte Temperatur', 'version': 'Anwendungsversion',
'apparentTemperatureMax': 'Maximale gefühlte Temperatur', 'precipitationProbability': 'Niederschlagswahrscheinlichkeit',
'amoledTheme': 'AMOLED-thema', 'apparentTemperatureMin': 'Minimale gefühlte Temperatur',
'appearance': 'Erscheinungsbild', 'apparentTemperatureMax': 'Maximale gefühlte Temperatur',
'functions': 'Funktionen', 'amoledTheme': 'AMOLED-thema',
'data': 'Daten', 'appearance': 'Erscheinungsbild',
'language': 'Sprache', 'functions': 'Funktionen',
'timeRange': 'Häufigkeit (in Stunden)', 'data': 'Daten',
'timeStart': 'Startzeit', 'language': 'Sprache',
'timeEnd': 'Endzeit', 'timeRange': 'Häufigkeit (in Stunden)',
'support': 'Unterstützung', 'timeStart': 'Startzeit',
'system': 'System', 'timeEnd': 'Endzeit',
'dark': 'Dunkel', 'support': 'Unterstützung',
'light': 'Hell', 'system': 'System',
'license': 'Lizenzen', 'dark': 'Dunkel',
'widget': 'Widget', 'light': 'Hell',
'widgetBackground': 'Widget-Hintergrund', 'license': 'Lizenzen',
'widgetText': 'Widget-Text', 'widget': 'Widget',
'dewpoint': 'Taupunkt', 'widgetBackground': 'Widget-Hintergrund',
'shortwaveRadiation': 'Kurzwellenstrahlung', 'widgetText': 'Widget-Text',
'roundDegree': 'Grad runden', 'dewpoint': 'Taupunkt',
'settings_full': 'Einstellungen', 'shortwaveRadiation': 'Kurzwellenstrahlung',
'cities': 'Städte', 'roundDegree': 'Grad runden',
'searchMethod': 'Verwenden Sie die Suche oder die Geolokalisierung', 'settings_full': 'Einstellungen',
'done': 'Fertig', 'cities': 'Städte',
'groups': 'Unsere gruppen', 'searchMethod': 'Verwenden Sie die Suche oder die Geolokalisierung',
'openMeteo': 'Daten von Open-Meteo (CC-BY 4.0)', 'done': 'Fertig',
'hourlyVariables': 'Stündliche Wettervariablen', 'groups': 'Unsere gruppen',
'dailyVariables': 'Tägliche Wettervariablen', 'openMeteo': 'Daten von Open-Meteo (CC-BY 4.0)',
}; 'hourlyVariables': 'Stündliche Wettervariablen',
'dailyVariables': 'Tägliche Wettervariablen',
'largeElement': 'Große Wetteranzeige',
'map': 'Karte',
'clearCacheStore': 'Cache leeren',
'deletedCacheStore': 'Cache wird geleert',
'deletedCacheStoreQuery':
'Sind Sie sicher, dass Sie den Cache leeren möchten?',
'addWidget': 'Widget hinzufügen',
'hideMap': 'Karte ausblenden',
};
} }

269
lib/translation/en_us.dart Normal file → Executable file
View file

@ -1,133 +1,142 @@
class EnUs { class EnUs {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Get Started', 'start': 'Get Started',
'description': 'description':
'Weather application with an up-to-date forecast for each hour, day, and week for any location.', 'Weather application with an up-to-date forecast for each hour, day, and week for any location.',
'name': 'Weather', 'name': 'Weather',
'name2': 'Convenient Design', 'name2': 'Convenient Design',
'name3': 'Contact Us', 'name3': 'Contact Us',
'description2': 'description2':
'All navigation is designed to interact with the application as conveniently and quickly as possible.', 'All navigation is designed to interact with the application as conveniently and quickly as possible.',
'description3': 'description3':
'If you encounter any issues, please contact us via email or in the application reviews.', 'If you encounter any issues, please contact us via email or in the application reviews.',
'next': 'Next', 'next': 'Next',
'search': 'Search...', 'search': 'Search...',
'loading': 'Loading...', 'loading': 'Loading...',
'searchCity': 'Find your city', 'searchCity': 'Find your city',
'humidity': 'Humidity', 'humidity': 'Humidity',
'wind': 'Wind', 'wind': 'Wind',
'visibility': 'Visibility', 'visibility': 'Visibility',
'feels': 'Feels', 'feels': 'Feels',
'evaporation': 'Evapotranspiration', 'evaporation': 'Evapotranspiration',
'precipitation': 'Precipitation', 'precipitation': 'Precipitation',
'direction': 'Direction', 'direction': 'Direction',
'pressure': 'Pressure', 'pressure': 'Pressure',
'rain': 'Rain', 'rain': 'Rain',
'clear_sky': 'Clear sky', 'clear_sky': 'Clear sky',
'cloudy': 'Cloudy', 'cloudy': 'Cloudy',
'overcast': 'Overcast', 'overcast': 'Overcast',
'fog': 'Fog', 'fog': 'Fog',
'drizzle': 'Drizzle', 'drizzle': 'Drizzle',
'drizzling_rain': 'Freezing Drizzle', 'drizzling_rain': 'Freezing Drizzle',
'freezing_rain': 'Freezing Rain', 'freezing_rain': 'Freezing Rain',
'heavy_rains': 'Rain showers', 'heavy_rains': 'Rain showers',
'snow': 'Snow', 'snow': 'Snow',
'thunderstorm': 'Thunderstorm', 'thunderstorm': 'Thunderstorm',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'inch', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'inch',
'settings': 'Set.', 'mm': 'mm',
'no_inter': 'No Internet', 'hPa': 'hPa',
'on_inter': 'Turn on the Internet to get meteorological data.', 'settings': 'Set.',
'location': 'Location', 'no_inter': 'No Internet',
'no_location': 'on_inter': 'Turn on the Internet to get meteorological data.',
'Enable the location service to get weather data for the current location.', 'location': 'Location',
'theme': 'Theme', 'no_location':
'low': 'Low', 'Enable the location service to get weather data for the current location.',
'high': 'High', 'theme': 'Theme',
'normal': 'Normal', 'low': 'Low',
'lat': 'Latitude', 'high': 'High',
'lon': 'Longitude', 'normal': 'Normal',
'create': 'Create', 'lat': 'Latitude',
'city': 'City', 'lon': 'Longitude',
'district': 'District', 'create': 'Create',
'noWeatherCard': 'Add a city', 'city': 'City',
'deletedCardWeather': 'Deleting a city', 'district': 'District',
'deletedCardWeatherQuery': 'Are you sure you want to delete the city?', 'noWeatherCard': 'Add a city',
'delete': 'Delete', 'deletedCardWeather': 'Deleting a city',
'cancel': 'Cancel', 'deletedCardWeatherQuery': 'Are you sure you want to delete the city?',
'time': 'Time in the city', 'delete': 'Delete',
'validateName': 'Please enter the name', 'cancel': 'Cancel',
'measurements': 'System of measures', 'time': 'Time in the city',
'degrees': 'Degrees', 'validateName': 'Please enter the name',
'celsius': 'Celsius', 'measurements': 'System of measures',
'fahrenheit': 'Fahrenheit', 'degrees': 'Degrees',
'imperial': 'Imperial', 'celsius': 'Celsius',
'metric': 'Metric', 'fahrenheit': 'Fahrenheit',
'validateValue': 'Please enter a value', 'imperial': 'Imperial',
'validateNumber': 'Please enter a valid number', 'metric': 'Metric',
'validate90': 'Value must be between -90 and 90', 'validateValue': 'Please enter a value',
'validate180': 'Value must be between -180 and 180', 'validateNumber': 'Please enter a valid number',
'notifications': 'Notifications', 'validate90': 'Value must be between -90 and 90',
'sunrise': 'Sunrise', 'validate180': 'Value must be between -180 and 180',
'sunset': 'Sunset', 'notifications': 'Notifications',
'timeformat': 'Time format', 'sunrise': 'Sunrise',
'12': '12-hour', 'sunset': 'Sunset',
'24': '24-hour', 'timeformat': 'Time format',
'cloudcover': 'Cloudcover', '12': '12-hour',
'uvIndex': 'UV-index', '24': '24-hour',
'materialColor': 'Dynamic colors', 'cloudcover': 'Cloudcover',
'uvLow': 'Low', 'uvIndex': 'UV-index',
'uvAverage': 'Moderate', 'materialColor': 'Dynamic colors',
'uvHigh': 'High', 'uvLow': 'Low',
'uvVeryHigh': 'Very high', 'uvAverage': 'Moderate',
'uvExtreme': 'Extreme', 'uvHigh': 'High',
'weatherMore': '12-day weather forecast', 'uvVeryHigh': 'Very high',
'windgusts': 'Gust', 'uvExtreme': 'Extreme',
'north': 'North', 'weatherMore': '12-day weather forecast',
'northeast': 'Northeast', 'windgusts': 'Gust',
'east': 'East', 'north': 'North',
'southeast': 'Southeast', 'northeast': 'Northeast',
'south': 'South', 'east': 'East',
'southwest': 'Southwest', 'southeast': 'Southeast',
'west': 'West', 'south': 'South',
'northwest': 'Northwest', 'southwest': 'Southwest',
'project': 'Project on', 'west': 'West',
'version': 'Application version', 'northwest': 'Northwest',
'precipitationProbability': 'Precipitation probability', 'project': 'Project on',
'apparentTemperatureMin': 'Minimum apparent temperature', 'version': 'Application version',
'apparentTemperatureMax': 'Maximum apparent temperature', 'precipitationProbability': 'Precipitation probability',
'amoledTheme': 'AMOLED-theme', 'apparentTemperatureMin': 'Minimum apparent temperature',
'appearance': 'Appearance', 'apparentTemperatureMax': 'Maximum apparent temperature',
'functions': 'Functions', 'amoledTheme': 'AMOLED-theme',
'data': 'Data', 'appearance': 'Appearance',
'language': 'Language', 'functions': 'Functions',
'timeRange': 'Frequency (in hours)', 'data': 'Data',
'timeStart': 'Start time', 'language': 'Language',
'timeEnd': 'End time', 'timeRange': 'Frequency (in hours)',
'support': 'Donate', 'timeStart': 'Start time',
'system': 'System', 'timeEnd': 'End time',
'dark': 'Dark', 'support': 'Donate',
'light': 'Light', 'system': 'System',
'license': 'Licenses', 'dark': 'Dark',
'widget': 'Widget', 'light': 'Light',
'widgetBackground': 'Widget background', 'license': 'Licenses',
'widgetText': 'Widget text', 'widget': 'Widget',
'dewpoint': 'Dewpoint', 'widgetBackground': 'Widget background',
'shortwaveRadiation': 'Shortwave radiation', 'widgetText': 'Widget text',
'W/m2': 'W/m2', 'dewpoint': 'Dewpoint',
'roundDegree': 'Round degrees', 'shortwaveRadiation': 'Shortwave radiation',
'settings_full': 'Settings', 'W/m2': 'W/m2',
'cities': 'Cities', 'roundDegree': 'Round degrees',
'searchMethod': 'Use search or geolocation', 'settings_full': 'Settings',
'done': 'Done', 'cities': 'Cities',
'groups': 'Our groups', 'searchMethod': 'Use search or geolocation',
'openMeteo': 'Data by Open-Meteo (CC-BY 4.0)', 'done': 'Done',
'hourlyVariables': 'Hourly weather variables', 'groups': 'Our groups',
'dailyVariables': 'Daily weather variables', 'openMeteo': 'Data by Open-Meteo (CC-BY 4.0)',
}; 'hourlyVariables': 'Hourly weather variables',
'dailyVariables': 'Daily weather variables',
'largeElement': 'Large weather display',
'map': 'Map',
'clearCacheStore': 'Clear cache',
'deletedCacheStore': 'Clearing the cache',
'deletedCacheStoreQuery': 'Are you sure you want to clear the cache?',
'addWidget': 'Add widget',
'hideMap': 'Hide map',
};
} }

270
lib/translation/es_es.dart Normal file → Executable file
View file

@ -1,134 +1,142 @@
class EsEs { class EsEs {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Empezar', 'start': 'Empezar',
'description': 'description':
'Aplicación meteorológica con un pronóstico actualizado para cada hora, día y semana para cualquier lugar.', 'Aplicación meteorológica con un pronóstico actualizado para cada hora, día y semana para cualquier lugar.',
'name': 'Tiempo', 'name': 'Tiempo',
'name2': 'Diseño Conveniente', 'name2': 'Diseño Conveniente',
'name3': 'Contáctenos', 'name3': 'Contáctenos',
'description2': 'description2':
'Toda la navegación está diseñada para interactuar con la aplicación de la manera más cómoda y rápida posible.', 'Toda la navegación está diseñada para interactuar con la aplicación de la manera más cómoda y rápida posible.',
'description3': 'description3':
'Si encuentra algún problema, contáctenos por correo electrónico o en las reseñas de la aplicación.', 'Si encuentra algún problema, contáctenos por correo electrónico o en las reseñas de la aplicación.',
'next': 'Siguiente', 'next': 'Siguiente',
'search': 'Buscar...', 'search': 'Buscar...',
'loading': 'Cargando...', 'loading': 'Cargando...',
'searchCity': 'Busca tu ciudad', 'searchCity': 'Busca tu ciudad',
'humidity': 'Humedad', 'humidity': 'Humedad',
'wind': 'Viento', 'wind': 'Viento',
'visibility': 'Visibilidad', 'visibility': 'Visibilidad',
'feels': 'Sensación térmica', 'feels': 'Sensación térmica',
'evaporation': 'Evaporación', 'evaporation': 'Evaporación',
'precipitation': 'Precipitación', 'precipitation': 'Precipitación',
'direction': 'Dirección', 'direction': 'Dirección',
'pressure': 'Presión', 'pressure': 'Presión',
'rain': 'Lluvia', 'rain': 'Lluvia',
'clear_sky': 'Cielo despejado', 'clear_sky': 'Cielo despejado',
'cloudy': 'Nuboso', 'cloudy': 'Nuboso',
'overcast': 'Cubierto de nubes', 'overcast': 'Cubierto de nubes',
'fog': 'Niebla', 'fog': 'Niebla',
'drizzle': 'Llovizna', 'drizzle': 'Llovizna',
'drizzling_rain': 'Llovizna helada', 'drizzling_rain': 'Llovizna helada',
'freezing_rain': 'Lluvia helada', 'freezing_rain': 'Lluvia helada',
'heavy_rains': 'Chubasco intenso', 'heavy_rains': 'Chubasco intenso',
'snow': 'Nieve', 'snow': 'Nieve',
'thunderstorm': 'Tormenta', 'thunderstorm': 'Tormenta',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'inch', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'inch',
'settings': 'Ajustes', 'mm': 'mm',
'no_inter': 'Sin conexión a Internet', 'hPa': 'hPa',
'on_inter': 'settings': 'Ajustes',
'Conéctate a Internet para obtener información meteorológica.', 'no_inter': 'Sin conexión a Internet',
'location': 'Ubicación', 'on_inter': 'Conéctate a Internet para obtener información meteorológica.',
'no_location': 'location': 'Ubicación',
'Activa la localización para obtener información meteorológica para tu ubicación actual.', 'no_location':
'theme': 'Tema', 'Activa la localización para obtener información meteorológica para tu ubicación actual.',
'low': 'Bajo', 'theme': 'Tema',
'high': 'Alto', 'low': 'Bajo',
'normal': 'Normal', 'high': 'Alto',
'lat': 'Latitud', 'normal': 'Normal',
'lon': 'Longitud', 'lat': 'Latitud',
'create': 'Crear', 'lon': 'Longitud',
'city': 'Ciudad', 'create': 'Crear',
'district': 'Distrito', 'city': 'Ciudad',
'noWeatherCard': 'Añadir una ciudad', 'district': 'Distrito',
'deletedCardWeather': 'Eliminar una ciudad', 'noWeatherCard': 'Añadir una ciudad',
'deletedCardWeatherQuery': 'deletedCardWeather': 'Eliminar una ciudad',
'¿Estás seguro de que quieres eliminar la ciudad?', 'deletedCardWeatherQuery':
'delete': 'Eliminar', '¿Estás seguro de que quieres eliminar la ciudad?',
'cancel': 'Cancelar', 'delete': 'Eliminar',
'time': 'Hora en la ciudad', 'cancel': 'Cancelar',
'validateName': 'Por favor, introduce un nombre', 'time': 'Hora en la ciudad',
'measurements': 'Sistema de medidas', 'validateName': 'Por favor, introduce un nombre',
'degrees': 'Grados', 'measurements': 'Sistema de medidas',
'celsius': 'Celsius', 'degrees': 'Grados',
'fahrenheit': 'Fahrenheit', 'celsius': 'Celsius',
'imperial': 'Imperial', 'fahrenheit': 'Fahrenheit',
'metric': 'Métrico', 'imperial': 'Imperial',
'validateValue': 'Por favor, introduce un valor', 'metric': 'Métrico',
'validateNumber': 'Por favor, introduce un número válido', 'validateValue': 'Por favor, introduce un valor',
'validate90': 'El valor tiene que estar entre -90 y 90', 'validateNumber': 'Por favor, introduce un número válido',
'validate180': 'El valor tiene que estar entre -180 y 180', 'validate90': 'El valor tiene que estar entre -90 y 90',
'notifications': 'Notificaciones', 'validate180': 'El valor tiene que estar entre -180 y 180',
'sunrise': 'Amanecer', 'notifications': 'Notificaciones',
'sunset': 'Atardecer', 'sunrise': 'Amanecer',
'timeformat': 'Formato de hora', 'sunset': 'Atardecer',
'12': '12 horas', 'timeformat': 'Formato de hora',
'24': '24 horas', '12': '12 horas',
'cloudcover': 'Cobertura de nubes', '24': '24 horas',
'uvIndex': 'UV-índice', 'cloudcover': 'Cobertura de nubes',
'materialColor': 'Colores Dinámicos', 'uvIndex': 'UV-índice',
'uvLow': 'Bajo', 'materialColor': 'Colores Dinámicos',
'uvAverage': 'Moderado', 'uvLow': 'Bajo',
'uvHigh': 'Alto', 'uvAverage': 'Moderado',
'uvVeryHigh': 'Muy alto', 'uvHigh': 'Alto',
'uvExtreme': 'Extremo', 'uvVeryHigh': 'Muy alto',
'weatherMore': 'Pronóstico del tiempo para 12 días', 'uvExtreme': 'Extremo',
'windgusts': 'Ráfagas', 'weatherMore': 'Pronóstico del tiempo para 12 días',
'north': 'Norte', 'windgusts': 'Ráfagas',
'northeast': 'Noreste', 'north': 'Norte',
'east': 'Este', 'northeast': 'Noreste',
'southeast': 'Sureste', 'east': 'Este',
'south': 'Sur', 'southeast': 'Sureste',
'southwest': 'Suroeste', 'south': 'Sur',
'west': 'Oeste', 'southwest': 'Suroeste',
'northwest': 'Noroeste', 'west': 'Oeste',
'project': 'Proyecto en', 'northwest': 'Noroeste',
'version': 'Versión de la aplicación', 'project': 'Proyecto en',
'precipitationProbability': 'Probabilidad de precipitación', 'version': 'Versión de la aplicación',
'apparentTemperatureMin': 'Temperatura aparente mínima', 'precipitationProbability': 'Probabilidad de precipitación',
'apparentTemperatureMax': 'Temperatura aparente máxima', 'apparentTemperatureMin': 'Temperatura aparente mínima',
'amoledTheme': 'AMOLED-tema', 'apparentTemperatureMax': 'Temperatura aparente máxima',
'appearance': 'Apariencia', 'amoledTheme': 'AMOLED-tema',
'functions': 'Funciones', 'appearance': 'Apariencia',
'data': 'Datos', 'functions': 'Funciones',
'language': 'Idioma', 'data': 'Datos',
'timeRange': 'Frecuencia (en horas)', 'language': 'Idioma',
'timeStart': 'Hora de inicio', 'timeRange': 'Frecuencia (en horas)',
'timeEnd': 'Hora de finalización', 'timeStart': 'Hora de inicio',
'support': 'Soporte', 'timeEnd': 'Hora de finalización',
'system': 'Sistema', 'support': 'Soporte',
'dark': 'Oscuro', 'system': 'Sistema',
'light': 'Claro', 'dark': 'Oscuro',
'license': 'Licencias', 'light': 'Claro',
'widget': 'Widget', 'license': 'Licencias',
'widgetBackground': 'Fondo del widget', 'widget': 'Widget',
'widgetText': 'Texto del widget', 'widgetBackground': 'Fondo del widget',
'dewpoint': 'Punto de rocío', 'widgetText': 'Texto del widget',
'shortwaveRadiation': 'Radiación de onda corta', 'dewpoint': 'Punto de rocío',
'roundDegree': 'Redondear grados', 'shortwaveRadiation': 'Radiación de onda corta',
'settings_full': 'Configuración', 'roundDegree': 'Redondear grados',
'cities': 'Ciudades', 'settings_full': 'Configuración',
'searchMethod': 'Usa la búsqueda o la geolocalización', 'cities': 'Ciudades',
'done': 'Hecho', 'searchMethod': 'Usa la búsqueda o la geolocalización',
'groups': 'Nuestros grupos', 'done': 'Hecho',
'openMeteo': 'Datos de Open-Meteo (CC-BY 4.0)', 'groups': 'Nuestros grupos',
'hourlyVariables': 'Variables meteorológicas horarias', 'openMeteo': 'Datos de Open-Meteo (CC-BY 4.0)',
'dailyVariables': 'Variables meteorológicas diarias', 'hourlyVariables': 'Variables meteorológicas horarias',
}; 'dailyVariables': 'Variables meteorológicas diarias',
'largeElement': 'Visualización grande del clima',
'map': 'Mapa',
'clearCacheStore': 'Borrar caché',
'deletedCacheStore': 'Borrando caché',
'deletedCacheStoreQuery': '¿Estás seguro de que quieres borrar el caché?',
'addWidget': 'Agregar widget',
'hideMap': 'Ocultar mapa',
};
} }

270
lib/translation/fa_ir.dart Normal file → Executable file
View file

@ -1,133 +1,143 @@
class FaIr { class FaIr {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'شروع کنید', 'start': 'شروع کنید',
'description': 'description':
'یک برنامه هواشناسی با پیش‌بینی به روز برای هر ساعت، روز و هفته و هر مکان', 'یک برنامه هواشناسی با پیش‌بینی به روز برای هر ساعت، روز و هفته و هر مکان',
'name': 'آب و هوا', 'name': 'آب و هوا',
'name2': 'طراحی راحت', 'name2': 'طراحی راحت',
'name3': 'ارتباط باما', 'name3': 'ارتباط باما',
'description2': 'description2':
'برنامه به گونه ای طراحی شده است تا به راحتی بتوانید با آن ارتباط بگیرید.', 'برنامه به گونه ای طراحی شده است تا به راحتی بتوانید با آن ارتباط بگیرید.',
'description3': 'description3':
'اگر با مشکلی روبرو شدید، لطفاً با ما از طریق ایمیل و یا نظرات برنامه ارتباط بگیرید.', 'اگر با مشکلی روبرو شدید، لطفاً با ما از طریق ایمیل و یا نظرات برنامه ارتباط بگیرید.',
'next': 'بعدی', 'next': 'بعدی',
'search': 'جستجو....', 'search': 'جستجو....',
'loading': 'درحال بارگذاری...', 'loading': 'درحال بارگذاری...',
'searchCity': 'شهر خود را پیدا کنید', 'searchCity': 'شهر خود را پیدا کنید',
'humidity': 'رطوبت', 'humidity': 'رطوبت',
'wind': 'باد', 'wind': 'باد',
'visibility': 'میزان دید', 'visibility': 'میزان دید',
'feels': 'دما', 'feels': 'دما',
'evaporation': 'تبخیر و تعرق', 'evaporation': 'تبخیر و تعرق',
'precipitation': 'ته‌نشینی', 'precipitation': 'ته‌نشینی',
'direction': 'جهت', 'direction': 'جهت',
'pressure': 'فشار', 'pressure': 'فشار',
'rain': 'باران', 'rain': 'باران',
'clear_sky': 'آسمان صاف', 'clear_sky': 'آسمان صاف',
'cloudy': 'ابری', 'cloudy': 'ابری',
'overcast': 'ابری', 'overcast': 'ابری',
'fog': 'مه', 'fog': 'مه',
'drizzle': 'ریز باران', 'drizzle': 'ریز باران',
'drizzling_rain': 'تگرگ', 'drizzling_rain': 'تگرگ',
'freezing_rain': 'باران یخ‌زن', 'freezing_rain': 'باران یخ‌زن',
'heavy_rains': 'باران شدید', 'heavy_rains': 'باران شدید',
'snow': 'برف', 'snow': 'برف',
'thunderstorm': 'طوفان', 'thunderstorm': 'طوفان',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'mi': 'mi',
'km': 'km', 'km': 'km',
'inch': 'inch', 'm/s': 'm/s',
'mm': 'mm', 'mmHg': 'mmHg',
'hPa': 'hPa', 'inch': 'inch',
'settings': 'تنظیمات', 'mm': 'mm',
'no_inter': 'عدم اتصال به اینترنت', 'hPa': 'hPa',
'on_inter': 'برای دریافت تغییرات جوی اینترنت خود را روشن کنید.', 'settings': 'تنظیمات',
'location': 'مکان', 'no_inter': 'عدم اتصال به اینترنت',
'no_location': 'on_inter': 'برای دریافت تغییرات جوی اینترنت خود را روشن کنید.',
'برای دریافت اطلاعات آب و هوا برای مکان فعلی، سرویس مکان را فعال کنید.', 'location': 'مکان',
'theme': 'پوسته', 'no_location':
'low': 'کم', 'برای دریافت اطلاعات آب و هوا برای مکان فعلی، سرویس مکان را فعال کنید.',
'high': 'زیاد', 'theme': 'پوسته',
'normal': 'عادی', 'low': 'کم',
'lat': 'عرض جغرافیایی', 'high': 'زیاد',
'lon': 'طول جغرافیایی', 'normal': 'عادی',
'create': 'ایجاد', 'lat': 'عرض جغرافیایی',
'city': 'شهر', 'lon': 'طول جغرافیایی',
'district': 'ناحیه', 'create': 'ایجاد',
'noWeatherCard': 'یک شهر اضافه کنید', 'city': 'شهر',
'deletedCardWeather': 'حذف یک شهر', 'district': 'ناحیه',
'deletedCardWeatherQuery': 'آیا از حذف این شهر اطمینان دارید؟', 'noWeatherCard': 'یک شهر اضافه کنید',
'delete': 'حذف', 'deletedCardWeather': 'حذف یک شهر',
'cancel': 'صرف نظر', 'deletedCardWeatherQuery': 'آیا از حذف این شهر اطمینان دارید؟',
'time': 'زمان در این شهر', 'delete': 'حذف',
'validateName': 'لطفاً نام را وارد کنید.', 'cancel': 'صرف نظر',
'measurements': 'سیستم اندازه گیری', 'time': 'زمان در این شهر',
'degrees': 'درجه', 'validateName': 'لطفاً نام را وارد کنید.',
'celsius': 'سلسیوس', 'measurements': 'سیستم اندازه گیری',
'fahrenheit': 'فارنهایت', 'degrees': 'درجه',
'imperial': 'بریتانیایی', 'celsius': 'سلسیوس',
'metric': 'متریک', 'fahrenheit': 'فارنهایت',
'validateValue': 'لطفاً یک مقدار را وارد کنید.', 'imperial': 'بریتانیایی',
'validateNumber': 'لطفاً یک مقدار معتبر وارد کنید.', 'metric': 'متریک',
'validate90': 'مقدار شما باید بین -۹۰ و ۹۰ باشد.', 'validateValue': 'لطفاً یک مقدار را وارد کنید.',
'validate180': 'مقدار شما باید بین -۱۸۰ و ۱۸۰ باشد.', 'validateNumber': 'لطفاً یک مقدار معتبر وارد کنید.',
'notifications': 'اعلانات', 'validate90': 'مقدار شما باید بین -۹۰ و ۹۰ باشد.',
'sunrise': 'طلوع آفتاب', 'validate180': 'مقدار شما باید بین -۱۸۰ و ۱۸۰ باشد.',
'sunset': 'غروب آفتاب', 'notifications': 'اعلانات',
'timeformat': 'نوع زمان', 'sunrise': 'طلوع آفتاب',
'12': '۱۲ ساعته', 'sunset': 'غروب آفتاب',
'24': '۲۴ ساعته', 'timeformat': 'نوع زمان',
'cloudcover': 'پوشش ابری', '12': '۱۲ ساعته',
'uvIndex': 'شاخص اشعه ماوراء بنفش', '24': '۲۴ ساعته',
'materialColor': 'رنگ های پویا', 'cloudcover': 'پوشش ابری',
'uvLow': 'کم', 'uvIndex': 'شاخص اشعه ماوراء بنفش',
'uvAverage': 'متوسط', 'materialColor': 'رنگ های پویا',
'uvHigh': 'زیاد', 'uvLow': 'کم',
'uvVeryHigh': 'خیلی زیاد', 'uvAverage': 'متوسط',
'uvExtreme': 'شدید', 'uvHigh': 'زیاد',
'weatherMore': 'پیش بینی آب و هوا 12 روزه', 'uvVeryHigh': 'خیلی زیاد',
'windgusts': 'وزش باد', 'uvExtreme': 'شدید',
'north': 'شمال', 'weatherMore': 'پیش بینی آب و هوا 12 روزه',
'northeast': 'شمال شرقی', 'windgusts': 'وزش باد',
'east': 'شرق', 'north': 'شمال',
'southeast': 'جنوب شرقی', 'northeast': 'شمال شرقی',
'south': 'جنوب', 'east': 'شرق',
'southwest': 'جنوب غربی', 'southeast': 'جنوب شرقی',
'west': 'غرب', 'south': 'جنوب',
'northwest': 'شمال غربی', 'southwest': 'جنوب غربی',
'project': 'Project on', 'west': 'غرب',
'version': 'نگارش برنامه', 'northwest': 'شمال غربی',
'precipitationProbability': 'احتمال بارش', 'project': 'Project on',
'apparentTemperatureMin': 'حداقل دمای ظاهری', 'version': 'نگارش برنامه',
'apparentTemperatureMax': 'حداکثر دمای ظاهری', 'precipitationProbability': 'احتمال بارش',
'amoledTheme': 'پوسته امولد', 'apparentTemperatureMin': 'حداقل دمای ظاهری',
'appearance': 'ظاهر', 'apparentTemperatureMax': 'حداکثر دمای ظاهری',
'functions': 'کارکرد', 'amoledTheme': 'پوسته امولد',
'data': 'داده ها', 'appearance': 'ظاهر',
'language': 'زبان', 'functions': 'کارکرد',
'timeRange': 'فرکانس (بر حسب ساعت)', 'data': 'داده ها',
'timeStart': 'زمان شروع', 'language': 'زبان',
'timeEnd': 'زمان پایان', 'timeRange': 'فرکانس (بر حسب ساعت)',
'support': 'پشتیبانی', 'timeStart': 'زمان شروع',
'system': 'سیستم', 'timeEnd': 'زمان پایان',
'dark': 'تیره', 'support': 'پشتیبانی',
'light': 'روشن', 'system': 'سیستم',
'license': 'مجوز', 'dark': 'تیره',
'widget': 'ویجت', 'light': 'روشن',
'widgetBackground': 'پس زمینه ویجت', 'license': 'مجوز',
'widgetText': 'متن ویجت', 'widget': 'ویجت',
'dewpoint': 'نقطه شبنم', 'widgetBackground': 'پس زمینه ویجت',
'shortwaveRadiation': 'تابش موج کوتاه', 'widgetText': 'متن ویجت',
'W/m2': 'W/m2', 'dewpoint': 'نقطه شبنم',
'roundDegree': 'درجه گرد', 'shortwaveRadiation': 'تابش موج کوتاه',
'settings_full': 'تنظیمات', 'W/m2': 'W/m2',
'cities': 'شهر ها', 'roundDegree': 'درجه گرد',
'searchMethod': 'از جستجو یا موقعیت جغرافیایی استفاده کنید', 'settings_full': 'تنظیمات',
'done': 'پایان', 'cities': 'شهر ها',
'groups': 'گروه‌های ما', 'searchMethod': 'از جستجو یا موقعیت جغرافیایی استفاده کنید',
'openMeteo': 'داده‌ها از Open-Meteo (CC-BY 4.0)', 'done': 'پایان',
'hourlyVariables': 'متغیرهای ساعتی هواشناسی', 'groups': 'گروه‌های ما',
'dailyVariables': 'متغیرهای روزانه هواشناسی', 'openMeteo': 'داده‌ها از Open-Meteo (CC-BY 4.0)',
}; 'hourlyVariables': 'متغیرهای ساعتی هواشناسی',
'dailyVariables': 'متغیرهای روزانه هواشناسی',
'largeElement': 'نمایش هواشناسی بزرگ',
'map': 'نقشه',
'clearCacheStore': 'پاک کردن حافظه نهان',
'deletedCacheStore': 'در حال پاک کردن حافظه نهان',
'deletedCacheStoreQuery':
'آیا مطمئن هستید که می‌خواهید حافظه نهان را پاک کنید؟',
'addWidget': 'افزودن ویجت',
'hideMap': 'پنهان کردن نقشه',
};
} }

270
lib/translation/fr_fr.dart Normal file → Executable file
View file

@ -1,134 +1,142 @@
class FrFr { class FrFr {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Démarrer', 'start': 'Démarrer',
'description': 'description':
'Application météo avec un pronostic à jour pour chaque heure, jour et semaine pour n\'importe quel endroit.', 'Application météo avec un pronostic à jour pour chaque heure, jour et semaine pour n\'importe quel endroit.',
'name': 'Météo', 'name': 'Météo',
'name2': 'Design pratique', 'name2': 'Design pratique',
'name3': 'Nous contacter', 'name3': 'Nous contacter',
'description2': 'description2':
'Toute la navigation est conçue pour interagir avec l\'application de la manière la plus pratique et la plus rapide possible.', 'Toute la navigation est conçue pour interagir avec l\'application de la manière la plus pratique et la plus rapide possible.',
'description3': 'description3':
'Si vous rencontrez des problèmes, veuillez nous contacter par e-mail ou dans les avis de l\'application.', 'Si vous rencontrez des problèmes, veuillez nous contacter par e-mail ou dans les avis de l\'application.',
'next': 'Suivant', 'next': 'Suivant',
'search': 'Rechercher...', 'search': 'Rechercher...',
'loading': 'Chargement...', 'loading': 'Chargement...',
'searchCity': 'Trouver votre ville', 'searchCity': 'Trouver votre ville',
'humidity': 'Humidité', 'humidity': 'Humidité',
'wind': 'Vent', 'wind': 'Vent',
'visibility': 'Visibilité', 'visibility': 'Visibilité',
'feels': 'Ressenti', 'feels': 'Ressenti',
'evaporation': 'Evaporation', 'evaporation': 'Evaporation',
'precipitation': 'Précipitation', 'precipitation': 'Précipitation',
'direction': 'Direction', 'direction': 'Direction',
'pressure': 'Pression', 'pressure': 'Pression',
'rain': 'Pluie', 'rain': 'Pluie',
'clear_sky': 'Ciel dégagé', 'clear_sky': 'Ciel dégagé',
'cloudy': 'Nuageux', 'cloudy': 'Nuageux',
'overcast': 'Couvert', 'overcast': 'Couvert',
'fog': 'Brouillard', 'fog': 'Brouillard',
'drizzle': 'Bruine', 'drizzle': 'Bruine',
'drizzling_rain': 'Brouillard givrant', 'drizzling_rain': 'Brouillard givrant',
'freezing_rain': 'Pluie verglaçante', 'freezing_rain': 'Pluie verglaçante',
'heavy_rains': 'Averses de pluie', 'heavy_rains': 'Averses de pluie',
'snow': 'Neige', 'snow': 'Neige',
'thunderstorm': 'Orage', 'thunderstorm': 'Orage',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'inch', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'inch',
'settings': 'Par.', 'mm': 'mm',
'no_inter': 'Pas de réseau', 'hPa': 'hPa',
'on_inter': 'settings': 'Par.',
'Connectez-vous à internet pour obtenir des données météorologiques.', 'no_inter': 'Pas de réseau',
'location': 'Localisation', 'on_inter':
'no_location': 'Connectez-vous à internet pour obtenir des données météorologiques.',
'Activez le service de localisation pour obtenir les données météorologiques de l\'endroit actuel.', 'location': 'Localisation',
'theme': 'Thème', 'no_location':
'low': 'Bas', 'Activez le service de localisation pour obtenir les données météorologiques de l\'endroit actuel.',
'high': 'Haut', 'theme': 'Thème',
'normal': 'Normal', 'low': 'Bas',
'lat': 'Latitude', 'high': 'Haut',
'lon': 'Longitude', 'normal': 'Normal',
'create': 'Créer', 'lat': 'Latitude',
'city': 'Ville', 'lon': 'Longitude',
'district': 'District', 'create': 'Créer',
'noWeatherCard': 'Ajouter une ville', 'city': 'Ville',
'deletedCardWeather': 'Supprimer une ville', 'district': 'District',
'deletedCardWeatherQuery': 'noWeatherCard': 'Ajouter une ville',
'Êtes-vous sûr de vouloir supprimer la ville ?', 'deletedCardWeather': 'Supprimer une ville',
'delete': 'Supprimer', 'deletedCardWeatherQuery': 'Êtes-vous sûr de vouloir supprimer la ville ?',
'cancel': 'Annuler', 'delete': 'Supprimer',
'time': 'Heure locale', 'cancel': 'Annuler',
'validateName': 'Veuillez saisir le nom', 'time': 'Heure locale',
'measurements': 'Système de mesures', 'validateName': 'Veuillez saisir le nom',
'degrees': 'Degrés', 'measurements': 'Système de mesures',
'celsius': 'Celsius', 'degrees': 'Degrés',
'fahrenheit': 'Fahrenheit', 'celsius': 'Celsius',
'imperial': 'Imperial', 'fahrenheit': 'Fahrenheit',
'metric': 'Métrique', 'imperial': 'Imperial',
'validateValue': 'Veuillez saisir une valeur', 'metric': 'Métrique',
'validateNumber': 'Veuillez saisir un numéro valide', 'validateValue': 'Veuillez saisir une valeur',
'validate90': 'La valeur doit être comprise entre -90 et 90', 'validateNumber': 'Veuillez saisir un numéro valide',
'validate180': 'La valeur doit être comprise entre -180 et 180', 'validate90': 'La valeur doit être comprise entre -90 et 90',
'notifications': 'Notifications', 'validate180': 'La valeur doit être comprise entre -180 et 180',
'sunrise': 'Lever du soleil', 'notifications': 'Notifications',
'sunset': 'Coucher du soleil', 'sunrise': 'Lever du soleil',
'timeformat': 'Format horaire', 'sunset': 'Coucher du soleil',
'12': '12 heures', 'timeformat': 'Format horaire',
'24': '24 heures', '12': '12 heures',
'cloudcover': 'Сouverture nuageuse', '24': '24 heures',
'uvIndex': 'UV-indice', 'cloudcover': 'Сouverture nuageuse',
'materialColor': 'Couleurs Dynamiques', 'uvIndex': 'UV-indice',
'uvLow': 'Faible', 'materialColor': 'Couleurs Dynamiques',
'uvAverage': 'Modéré', 'uvLow': 'Faible',
'uvHigh': 'Élevé', 'uvAverage': 'Modéré',
'uvVeryHigh': 'Très élevé', 'uvHigh': 'Élevé',
'uvExtreme': 'Extrême', 'uvVeryHigh': 'Très élevé',
'weatherMore': 'Prévisions météo pour 12 jours', 'uvExtreme': 'Extrême',
'windgusts': 'Rafale', 'weatherMore': 'Prévisions météo pour 12 jours',
'north': 'Nord', 'windgusts': 'Rafale',
'northeast': 'Nord-Est', 'north': 'Nord',
'east': 'Est', 'northeast': 'Nord-Est',
'southeast': 'Sud-Est', 'east': 'Est',
'south': 'Sud', 'southeast': 'Sud-Est',
'southwest': 'Sud-Ouest', 'south': 'Sud',
'west': 'Ouest', 'southwest': 'Sud-Ouest',
'northwest': 'Nord-Ouest', 'west': 'Ouest',
'project': 'Project on', 'northwest': 'Nord-Ouest',
'version': 'Application version', 'project': 'Project on',
'precipitationProbability': 'Probabilité de précipitation', 'version': 'Application version',
'apparentTemperatureMin': 'Température apparente minimale', 'precipitationProbability': 'Probabilité de précipitation',
'apparentTemperatureMax': 'Température apparente maximale', 'apparentTemperatureMin': 'Température apparente minimale',
'amoledTheme': 'AMOLED-thème', 'apparentTemperatureMax': 'Température apparente maximale',
'appearance': 'Apparence', 'amoledTheme': 'AMOLED-thème',
'functions': 'Fonctions', 'appearance': 'Apparence',
'data': 'Données', 'functions': 'Fonctions',
'language': 'Langue', 'data': 'Données',
'timeRange': 'Fréquence (en heures)', 'language': 'Langue',
'timeStart': 'Heure de début', 'timeRange': 'Fréquence (en heures)',
'timeEnd': 'Heure de fin', 'timeStart': 'Heure de début',
'support': 'Support', 'timeEnd': 'Heure de fin',
'system': 'Système', 'support': 'Support',
'dark': 'Sombre', 'system': 'Système',
'light': 'Clair', 'dark': 'Sombre',
'license': 'Licences', 'light': 'Clair',
'widget': 'Widget', 'license': 'Licences',
'widgetBackground': 'Fond du widget', 'widget': 'Widget',
'widgetText': 'Texte du widget', 'widgetBackground': 'Fond du widget',
'dewpoint': 'Point de rosée', 'widgetText': 'Texte du widget',
'shortwaveRadiation': 'Rayonnement à ondes courtes', 'dewpoint': 'Point de rosée',
'roundDegree': 'Arrondir les degrés', 'shortwaveRadiation': 'Rayonnement à ondes courtes',
'settings_full': 'Paramètres', 'roundDegree': 'Arrondir les degrés',
'cities': 'Villes', 'settings_full': 'Paramètres',
'searchMethod': 'Utilisez la recherche ou la géolocalisation', 'cities': 'Villes',
'done': 'Terminé', 'searchMethod': 'Utilisez la recherche ou la géolocalisation',
'groups': 'Nos groupes', 'done': 'Terminé',
'openMeteo': 'Données de Open-Meteo (CC-BY 4.0)', 'groups': 'Nos groupes',
'hourlyVariables': 'Variables météorologiques horaires', 'openMeteo': 'Données de Open-Meteo (CC-BY 4.0)',
'dailyVariables': 'Variables météorologiques quotidiennes', 'hourlyVariables': 'Variables météorologiques horaires',
}; 'dailyVariables': 'Variables météorologiques quotidiennes',
'largeElement': 'Affichage météo grand format',
'map': 'Carte',
'clearCacheStore': 'Effacer le cache',
'deletedCacheStore': 'Effacement du cache',
'deletedCacheStoreQuery': 'Êtes-vous sûr de vouloir effacer le cache?',
'addWidget': 'Ajouter un widget',
'hideMap': 'Cacher la carte',
};
} }

272
lib/translation/ga_ie.dart Normal file → Executable file
View file

@ -1,134 +1,144 @@
class GaIe { class GaIe {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Tosaigh', 'start': 'Tosaigh',
'description': 'description':
'Aip aimsire le réamhaisnéis láithreach do gach uair, lá, agus seachtain do gach áit.', 'Aip aimsire le réamhaisnéis láithreach do gach uair, lá, agus seachtain do gach áit.',
'name': 'Aimsir', 'name': 'Aimsir',
'name2': 'Dearadh Éasca', 'name2': 'Dearadh Éasca',
'name3': 'Déan teagmháil linn', 'name3': 'Déan teagmháil linn',
'description2': 'description2':
'Tá gach treoir déanta chun éascaíocht agus gniomhachtú a dhéanamh leis an aip chomh héasca agus chomh tapa agus is féidir.', 'Tá gach treoir déanta chun éascaíocht agus gniomhachtú a dhéanamh leis an aip chomh héasca agus chomh tapa agus is féidir.',
'description3': 'description3':
'Má tá fadhb ar bith agat, déan teagmháil linn trí Ríomhphost nó trí phlé an aip.', 'Má tá fadhb ar bith agat, déan teagmháil linn trí Ríomhphost nó trí phlé an aip.',
'next': 'Ar Aghaidh', 'next': 'Ar Aghaidh',
'search': 'Cuardaigh...', 'search': 'Cuardaigh...',
'loading': 'Ag Lódáil...', 'loading': 'Ag Lódáil...',
'searchCity': 'Aimsigh do chathair', 'searchCity': 'Aimsigh do chathair',
'humidity': 'Measarthaíocht Géimneachta', 'humidity': 'Measarthaíocht Géimneachta',
'wind': 'Gaoth', 'wind': 'Gaoth',
'visibility': 'Radharc', 'visibility': 'Radharc',
'feels': 'Brath', 'feels': 'Brath',
'evaporation': 'Buirtheasaiteacht', 'evaporation': 'Buirtheasaiteacht',
'precipitation': 'Tuirlingt', 'precipitation': 'Tuirlingt',
'direction': 'Treorach', 'direction': 'Treorach',
'pressure': 'Brú', 'pressure': 'Brú',
'rain': 'Fearthainn', 'rain': 'Fearthainn',
'clear_sky': 'Spéir Ghlán', 'clear_sky': 'Spéir Ghlán',
'cloudy': 'Scamallach', 'cloudy': 'Scamallach',
'overcast': 'Tromscamallach', 'overcast': 'Tromscamallach',
'fog': 'Ceo', 'fog': 'Ceo',
'drizzle': 'Táilliú', 'drizzle': 'Táilliú',
'drizzling_rain': 'Táilliú Ag Fuarthainn', 'drizzling_rain': 'Táilliú Ag Fuarthainn',
'freezing_rain': 'Tuirlingt Fuara', 'freezing_rain': 'Tuirlingt Fuara',
'heavy_rains': 'Scáil fearthainne', 'heavy_rains': 'Scáil fearthainne',
'snow': 'Sneachta', 'snow': 'Sneachta',
'thunderstorm': 'Tornaí', 'thunderstorm': 'Tornaí',
'kph': 'km/u', 'kph': 'km/u',
'mph': 'mi/u', 'mph': 'mi/u',
'mi': 'míle', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'úinse', 'mi': 'míle',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'úinse',
'settings': 'Socrú', 'mm': 'mm',
'no_inter': 'Gan Idirlíon', 'hPa': 'hPa',
'on_inter': 'Cuir ar Idirlíon chun sonraí aeráide a fháil.', 'settings': 'Socrú',
'location': 'Áit', 'no_inter': 'Gan Idirlíon',
'no_location': 'on_inter': 'Cuir ar Idirlíon chun sonraí aeráide a fháil.',
'Cumasaigh seirbhís na háite chun sonraí aimsire a fháil don áit reatha.', 'location': 'Áit',
'theme': 'Téama', 'no_location':
'low': 'Íseal', 'Cumasaigh seirbhís na háite chun sonraí aimsire a fháil don áit reatha.',
'high': 'Ard', 'theme': 'Téama',
'normal': 'Gnáth', 'low': 'Íseal',
'lat': 'Éilt', 'high': 'Ard',
'lon': 'Long', 'normal': 'Gnáth',
'create': 'Cruthaigh', 'lat': 'Éilt',
'city': 'Cathair', 'lon': 'Long',
'district': 'Ceantar', 'create': 'Cruthaigh',
'noWeatherCard': 'Cuir cathair leis', 'city': 'Cathair',
'deletedCardWeather': 'Áireamh cathair á scriosadh', 'district': 'Ceantar',
'deletedCardWeatherQuery': 'noWeatherCard': 'Cuir cathair leis',
'An bhfuil tú cinnte go bhfuil tú ag iarraidh an chathair a scriosadh?', 'deletedCardWeather': 'Áireamh cathair á scriosadh',
'delete': 'Scrios', 'deletedCardWeatherQuery':
'cancel': 'Cealaigh', 'An bhfuil tú cinnte go bhfuil tú ag iarraidh an chathair a scriosadh?',
'time': 'Am sa chathair', 'delete': 'Scrios',
'validateName': 'Cuir ainm isteach, le do thoil', 'cancel': 'Cealaigh',
'measurements': 'Córas Mheáchain', 'time': 'Am sa chathair',
'degrees': 'Céim', 'validateName': 'Cuir ainm isteach, le do thoil',
'celsius': 'Céim Celsius', 'measurements': 'Córas Mheáchain',
'fahrenheit': 'Céim Fahrenheit', 'degrees': 'Céim',
'imperial': 'Impireach', 'celsius': 'Céim Celsius',
'metric': 'Mheitric', 'fahrenheit': 'Céim Fahrenheit',
'validateValue': 'Cuir luach isteach, le do thoil', 'imperial': 'Impireach',
'validateNumber': 'Cuir uimhir bailí isteach, le do thoil', 'metric': 'Mheitric',
'validate90': 'Caithfidh luach a bheith idir -90 agus 90', 'validateValue': 'Cuir luach isteach, le do thoil',
'validate180': 'Caithfidh luach a bheith idir -180 agus 180', 'validateNumber': 'Cuir uimhir bailí isteach, le do thoil',
'notifications': 'Fógraí', 'validate90': 'Caithfidh luach a bheith idir -90 agus 90',
'sunrise': 'Éirí na Gréine', 'validate180': 'Caithfidh luach a bheith idir -180 agus 180',
'sunset': 'Dul faoi na Gréine', 'notifications': 'Fógraí',
'timeformat': 'Formáid Am', 'sunrise': 'Éirí na Gréine',
'12': '12-uair', 'sunset': 'Dul faoi na Gréine',
'24': '24-uair', 'timeformat': 'Formáid Am',
'cloudcover': 'Clúdach Scamall', '12': '12-uair',
'uvIndex': 'Indéacs UV', '24': '24-uair',
'materialColor': 'Dathanna Dinimiciúla', 'cloudcover': 'Clúdach Scamall',
'uvLow': 'Íseal', 'uvIndex': 'Indéacs UV',
'uvAverage': 'Meánach', 'materialColor': 'Dathanna Dinimiciúla',
'uvHigh': 'Ard', 'uvLow': 'Íseal',
'uvVeryHigh': 'An-Árd', 'uvAverage': 'Meánach',
'uvExtreme': 'Éachtach', 'uvHigh': 'Ard',
'weatherMore': 'Réamhaisnéis Aimsire 12 lá', 'uvVeryHigh': 'An-Árd',
'windgusts': 'Tonna Gaoithe', 'uvExtreme': 'Éachtach',
'north': 'Tuaisceart', 'weatherMore': 'Réamhaisnéis Aimsire 12 lá',
'northeast': 'Tuaisceart-Thoir', 'windgusts': 'Tonna Gaoithe',
'east': 'Thoir', 'north': 'Tuaisceart',
'southeast': 'Deisceart-Thoir', 'northeast': 'Tuaisceart-Thoir',
'south': 'Deisceart', 'east': 'Thoir',
'southwest': 'Deisceart-Iarthar', 'southeast': 'Deisceart-Thoir',
'west': 'Iarthar', 'south': 'Deisceart',
'northwest': 'Tuaisceart-Iarthar', 'southwest': 'Deisceart-Iarthar',
'project': 'Tionscadal ar siúl', 'west': 'Iarthar',
'version': 'Leagan Feidhmchláir', 'northwest': 'Tuaisceart-Iarthar',
'precipitationProbability': 'Ionsaíocht Tuirlingt', 'project': 'Tionscadal ar siúl',
'apparentTemperatureMin': 'Teocht Shamhlaithe Ísle', 'version': 'Leagan Feidhmchláir',
'apparentTemperatureMax': 'Teocht Shamhlaithe Uachtarach', 'precipitationProbability': 'Ionsaíocht Tuirlingt',
'amoledTheme': 'Téama AMOLED', 'apparentTemperatureMin': 'Teocht Shamhlaithe Ísle',
'appearance': 'Amharc', 'apparentTemperatureMax': 'Teocht Shamhlaithe Uachtarach',
'functions': 'Feidhmeanna', 'amoledTheme': 'Téama AMOLED',
'data': 'Sonraí', 'appearance': 'Amharc',
'language': 'Teanga', 'functions': 'Feidhmeanna',
'timeRange': 'Raon Am (i n-uaireanta)', 'data': 'Sonraí',
'timeStart': 'Tús Am', 'language': 'Teanga',
'timeEnd': 'Críoch Am', 'timeRange': 'Raon Am (i n-uaireanta)',
'support': 'Tacaíocht', 'timeStart': 'Tús Am',
'system': 'Córas', 'timeEnd': 'Críoch Am',
'dark': 'Téama Dorcha', 'support': 'Tacaíocht',
'light': 'Téama Soiléir', 'system': 'Córas',
'license': 'Ceadúnas', 'dark': 'Téama Dorcha',
'widget': 'Rón', 'light': 'Téama Soiléir',
'widgetBackground': 'Cúlra an Rón', 'license': 'Ceadúnas',
'widgetText': 'Téacs an Rón', 'widget': 'Rón',
'dewpoint': 'Poinnte Dé', 'widgetBackground': 'Cúlra an Rón',
'shortwaveRadiation': 'Fuinneamh Ghearrfhad', 'widgetText': 'Téacs an Rón',
'W/m2': 'W/m2', 'dewpoint': 'Poinnte Dé',
'roundDegree': 'Timpeall na Gráid', 'shortwaveRadiation': 'Fuinneamh Ghearrfhad',
'settings_full': 'Socruithe', 'W/m2': 'W/m2',
'cities': 'Cathracha', 'roundDegree': 'Timpeall na Gráid',
'searchMethod': 'Úsáid ceangal nó geolocáid', 'settings_full': 'Socruithe',
'done': 'Críochnaithe', 'cities': 'Cathracha',
'groups': 'Ár ngrúpaí', 'searchMethod': 'Úsáid ceangal nó geolocáid',
'openMeteo': 'Sonraí ó Open-Meteo (CC-BY 4.0)', 'done': 'Críochnaithe',
'hourlyVariables': 'Athrógacha aimsire uaireanta', 'groups': 'Ár ngrúpaí',
'dailyVariables': 'Athrógacha aimsire laethúla', 'openMeteo': 'Sonraí ó Open-Meteo (CC-BY 4.0)',
}; 'hourlyVariables': 'Athrógacha aimsire uaireanta',
'dailyVariables': 'Athrógacha aimsire laethúla',
'largeElement': 'Taispeáint mór na haimsire',
'map': 'Léarscáil',
'clearCacheStore': 'Glan taisce',
'deletedCacheStore': 'Ag glanadh an taisce',
'deletedCacheStoreQuery':
'An bhfuil tú cinnte gur mian leat an taisce a ghlanadh?',
'addWidget': 'Cuir giuirléid leis',
'hideMap': 'Folaigh léarscáil',
};
} }

265
lib/translation/hi_in.dart Normal file → Executable file
View file

@ -1,131 +1,140 @@
class HiIn { class HiIn {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'शुरू करें', 'start': 'शुरू करें',
'description': 'description':
'प्रति घंटे, दिन और सप्ताह के लिए किसी भी स्थान के लिए आधुनिक पूर्वानुमान के साथ मौसम एप्लिकेशन।', 'प्रति घंटे, दिन और सप्ताह के लिए किसी भी स्थान के लिए आधुनिक पूर्वानुमान के साथ मौसम एप्लिकेशन।',
'name': 'मौसम', 'name': 'मौसम',
'name2': 'आसान डिजाइन', 'name2': 'आसान डिजाइन',
'name3': 'हमे संपर्क करें', 'name3': 'हमे संपर्क करें',
'description2': 'description2':
'सभी नेविगेशन को इस प्रकार तैयार किया गया है ताकि आप एप्लिकेशन के साथ सर्वोत्तम रूप से और तेजी से संवाद कर सकें।', 'सभी नेविगेशन को इस प्रकार तैयार किया गया है ताकि आप एप्लिकेशन के साथ सर्वोत्तम रूप से और तेजी से संवाद कर सकें।',
'description3': 'description3':
'यदि आपको कोई समस्या आती है, तो कृपया हमसे ईमेल या एप्लिकेशन समीक्षा के माध्यम से संपर्क करें।', 'यदि आपको कोई समस्या आती है, तो कृपया हमसे ईमेल या एप्लिकेशन समीक्षा के माध्यम से संपर्क करें।',
'next': 'आगे', 'next': 'आगे',
'search': 'खोजें...', 'search': 'खोजें...',
'loading': 'लोड हो रहा है...', 'loading': 'लोड हो रहा है...',
'searchCity': 'अपना शहर खोजें', 'searchCity': 'अपना शहर खोजें',
'humidity': 'नमी', 'humidity': 'नमी',
'wind': 'हवा', 'wind': 'हवा',
'visibility': 'दृश्यता', 'visibility': 'दृश्यता',
'feels': 'अनुभव', 'feels': 'अनुभव',
'evaporation': 'वाष्पीकरण', 'evaporation': 'वाष्पीकरण',
'precipitation': 'वर्षा', 'precipitation': 'वर्षा',
'direction': 'दिशा', 'direction': 'दिशा',
'pressure': 'दबाव', 'pressure': 'दबाव',
'rain': 'बारिश', 'rain': 'बारिश',
'clear_sky': 'साफ आकाश', 'clear_sky': 'साफ आकाश',
'cloudy': 'मेघपाली', 'cloudy': 'मेघपाली',
'overcast': 'बादलबस्ती', 'overcast': 'बादलबस्ती',
'fog': 'कोहरा', 'fog': 'कोहरा',
'drizzle': 'बूंदाबांदी', 'drizzle': 'बूंदाबांदी',
'drizzling_rain': 'हिमवृष्टि', 'drizzling_rain': 'हिमवृष्टि',
'freezing_rain': 'हिमस्खलन', 'freezing_rain': 'हिमस्खलन',
'heavy_rains': 'बारिश की बौछारें', 'heavy_rains': 'बारिश की बौछारें',
'snow': 'बर्फबारी', 'snow': 'बर्फबारी',
'thunderstorm': 'बिजली चमक', 'thunderstorm': 'बिजली चमक',
'kph': 'किमी/घंटा', 'kph': 'किमी/घंटा',
'mph': 'मील/घंटा', 'mph': 'मील/घंटा',
'mi': 'मील', 'm/s': 'मी/से',
'km': 'किमी', 'mmHg': 'मिमी एचजी',
'inch': 'इंच', 'mi': 'मील',
'mm': 'मिलीमीटर', 'km': 'किमी',
'hPa': 'हेक्टोपास्कल', 'inch': 'इंच',
'settings': 'सेटिंग्स', 'mm': 'मिलीमीटर',
'no_inter': 'कोई इंटरनेट नहीं है', 'hPa': 'हेक्टोपास्कल',
'on_inter': 'मौसमी आंकड़े प्राप्त करने के लिए इंटरनेट को चालू करें।', 'settings': 'सेटिंग्स',
'location': 'स्थान', 'no_inter': 'कोई इंटरनेट नहीं है',
'no_location': 'वर्तमान स्थान के लिए मौसम डेटा प्राप्त करने के', 'on_inter': 'मौसमी आंकड़े प्राप्त करने के लिए इंटरनेट को चालू करें।',
'theme': 'थीम', 'location': 'स्थान',
'low': 'निम्न', 'no_location': 'वर्तमान स्थान के लिए मौसम डेटा प्राप्त करने के',
'high': 'उच्च', 'theme': 'थीम',
'normal': 'सामान्य', 'low': 'निम्न',
'lat': 'अक्षांश', 'high': 'उच्च',
'lon': 'देशांतर', 'normal': 'सामान्य',
'create': 'बनाएँ', 'lat': 'अक्षांश',
'city': 'शहर', 'lon': 'देशांतर',
'district': 'जिला', 'create': 'बनाएँ',
'noWeatherCard': 'शहर जोड़ें', 'city': 'शहर',
'deletedCardWeather': 'शहर हटाना', 'district': 'जिला',
'deletedCardWeatherQuery': 'क्या आप वाकई शहर को हटाना चाहते हैं?', 'noWeatherCard': 'शहर जोड़ें',
'delete': 'हटाएँ', 'deletedCardWeather': 'शहर हटाना',
'cancel': 'रद्द करें', 'deletedCardWeatherQuery': 'क्या आप वाकई शहर को हटाना चाहते हैं?',
'time': 'शहर में समय', 'delete': 'हटाएँ',
'validateName': 'कृपया नाम दर्ज करें', 'cancel': 'रद्द करें',
'measurements': 'मापन प्रणाली', 'time': 'शहर में समय',
'degrees': 'डिग्री', 'validateName': 'कृपया नाम दर्ज करें',
'celsius': 'सेल्सियस', 'measurements': 'मापन प्रणाली',
'fahrenheit': 'फ़ारेनहाइट', 'degrees': 'डिग्री',
'imperial': 'इम्पीरियल', 'celsius': 'सेल्सियस',
'metric': 'मीट्रिक', 'fahrenheit': 'फ़ारेनहाइट',
'validateValue': 'कृपया मान दर्ज करें', 'imperial': 'इम्पीरियल',
'validateNumber': 'कृपया एक मान्य संख्या दर्ज करें', 'metric': 'मीट्रिक',
'validate90': 'मान -९० और ९० के बीच होना चाहिए', 'validateValue': 'कृपया मान दर्ज करें',
'validate180': 'मान -१८० और १८० के बीच होना चाहिए', 'validateNumber': 'कृपया एक मान्य संख्या दर्ज करें',
'notifications': 'सूचनाएं', 'validate90': 'मान -९० और ९० के बीच होना चाहिए',
'sunrise': 'सूर्योदय', 'validate180': 'मान -१८० और १८० के बीच होना चाहिए',
'sunset': 'सूर्यास्त', 'notifications': 'सूचनाएं',
'timeformat': 'समय प्रारूप', 'sunrise': 'सूर्योदय',
'12': '१२ घंटा', 'sunset': 'सूर्यास्त',
'24': '२४ घंटा', 'timeformat': 'समय प्रारूप',
'cloudcover': 'बादलों का कवर', '12': '१२ घंटा',
'uvIndex': 'यूवी-सूचकांक', '24': '२४ घंटा',
'materialColor': 'गतिशील रंग', 'cloudcover': 'बादलों का कवर',
'uvLow': 'कम', 'uvIndex': 'यूवी-सूचकांक',
'uvAverage': 'माध्यम', 'materialColor': 'गतिशील रंग',
'uvHigh': 'उच्च', 'uvLow': 'कम',
'uvVeryHigh': 'बहुत उच्च', 'uvAverage': 'माध्यम',
'uvExtreme': 'अत्यधिक', 'uvHigh': 'उच्च',
'weatherMore': '१२ - दिवसीय मौसम पूर', 'uvVeryHigh': 'बहुत उच्च',
'windgusts': 'गुस्त', 'uvExtreme': 'अत्यधिक',
'north': 'उत्तर', 'weatherMore': '१२ - दिवसीय मौसम पूर',
'northeast': 'उत्तर-पूर्व', 'windgusts': 'गुस्त',
'east': 'पूर्व', 'north': 'उत्तर',
'southeast': 'दक्षिण-पूर्व', 'northeast': 'उत्तर-पूर्व',
'south': 'दक्षिण', 'east': 'पूर्व',
'southwest': 'दक्षिण-पश्चिम', 'southeast': 'दक्षिण-पूर्व',
'west': 'पश्चिम', 'south': 'दक्षिण',
'northwest': 'उत्तर-पश्चिम', 'southwest': 'दक्षिण-पश्चिम',
'project': 'परियोजना पर', 'west': 'पश्चिम',
'version': 'एप्लिकेशन संस्करण', 'northwest': 'उत्तर-पश्चिम',
'precipitationProbability': 'वर्षा संभावना', 'project': 'परियोजना पर',
'apparentTemperatureMin': 'न्यूनतम प्रतीत तापमान', 'version': 'एप्लिकेशन संस्करण',
'apparentTemperatureMax': 'अधिकतम प्रतीत तापमान', 'precipitationProbability': 'वर्षा संभावना',
'amoledTheme': 'AMOLED थीम', 'apparentTemperatureMin': 'न्यूनतम प्रतीत तापमान',
'appearance': 'दिखावट', 'apparentTemperatureMax': 'अधिकतम प्रतीत तापमान',
'functions': 'कार्य', 'amoledTheme': 'AMOLED थीम',
'data': 'डेटा', 'appearance': 'दिखावट',
'language': 'भाषा', 'functions': 'कार्य',
'timeRange': 'अवधि (घंटों में)', 'data': 'डेटा',
'timeStart': 'प्रारंभ समय', 'language': 'भाषा',
'timeEnd': 'समाप्ति समय', 'timeRange': 'अवधि (घंटों में)',
'support': 'समर्थन', 'timeStart': 'प्रारंभ समय',
'system': 'सिस्टम', 'timeEnd': 'समाप्ति समय',
'dark': 'डार्क', 'support': 'समर्थन',
'light': 'लाइट', 'system': 'सिस्टम',
'license': 'लाइसेंस', 'dark': 'डार्क',
'widget': 'विजेट', 'light': 'लाइट',
'widgetBackground': 'विजेट कि पृष्ठभूमि', 'license': 'लाइसेंस',
'widgetText': 'विजेट पाठ', 'widget': 'विजेट',
'dewpoint': 'बर्फ़ के बिंदु', 'widgetBackground': 'विजेट कि पृष्ठभूमि',
'shortwaveRadiation': 'शॉर्टवेव विकिरण', 'widgetText': 'विजेट पाठ',
'roundDegree': 'डिग्री गोली मारें', 'dewpoint': 'बर्फ़ के बिंदु',
'settings_full': 'सेटिंग्स', 'shortwaveRadiation': 'शॉर्टवेव विकिरण',
'cities': 'शहर', 'roundDegree': 'डिग्री गोली मारें',
'searchMethod': 'खोज या स्थानगति का उपयोग करें', 'settings_full': 'सेटिंग्स',
'done': 'किया', 'cities': 'शहर',
'groups': 'हमारे समूह', 'searchMethod': 'खोज या स्थानगति का उपयोग करें',
'openMeteo': 'Open-Meteo से डेटा (CC-BY 4.0)', 'done': 'किया',
'hourlyVariables': 'घंटेवार मौसम चर', 'groups': 'हमारे समूह',
'dailyVariables': 'दैनिक मौसम चर', 'openMeteo': 'Open-Meteo से डेटा (CC-BY 4.0)',
}; 'hourlyVariables': 'घंटेवार मौसम चर',
'dailyVariables': 'दैनिक मौसम चर',
'largeElement': 'बड़े मौसम का प्रदर्शन',
'map': 'मानचित्र',
'clearCacheStore': 'कैश साफ़ करें',
'deletedCacheStore': 'कैश साफ़ हो रहा है',
'deletedCacheStoreQuery': 'क्या आप वाकई कैश साफ़ करना चाहते हैं?',
'addWidget': 'विजेट जोड़ें',
'hideMap': 'मानचित्र छिपाएँ',
};
} }

270
lib/translation/hu_hu.dart Normal file → Executable file
View file

@ -1,134 +1,142 @@
class HuHu { class HuHu {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Kezdés', 'start': 'Kezdés',
'description': 'description':
'Időjárás alkalmazás a friss óránkénti, napi és heti előrejelzéssel bármely helyszínre.', 'Időjárás alkalmazás a friss óránkénti, napi és heti előrejelzéssel bármely helyszínre.',
'name': 'Időjárás', 'name': 'Időjárás',
'name2': 'Kényelmes tervezés', 'name2': 'Kényelmes tervezés',
'name3': 'Kapcsolatfelvétel velünk', 'name3': 'Kapcsolatfelvétel velünk',
'description2': 'description2':
'Az összes navigáció úgy van kialakítva, hogy maximálisan kényelmes és gyors legyen az alkalmazással való interakció.', 'Az összes navigáció úgy van kialakítva, hogy maximálisan kényelmes és gyors legyen az alkalmazással való interakció.',
'description3': 'description3':
'Ha bármilyen problémája adódik, kérjük, lépjen kapcsolatba velünk e-mailben vagy az alkalmazás értékeléseiben.', 'Ha bármilyen problémája adódik, kérjük, lépjen kapcsolatba velünk e-mailben vagy az alkalmazás értékeléseiben.',
'next': 'Tovább', 'next': 'Tovább',
'search': 'Keresés...', 'search': 'Keresés...',
'loading': 'Betöltés...', 'loading': 'Betöltés...',
'searchCity': 'Keresse meg a városát', 'searchCity': 'Keresse meg a városát',
'humidity': 'Páratartalom', 'humidity': 'Páratartalom',
'wind': 'Szél', 'wind': 'Szél',
'visibility': 'Láthatóság', 'visibility': 'Láthatóság',
'feels': 'Hőérzet', 'feels': 'Hőérzet',
'evaporation': 'Párolgás', 'evaporation': 'Párolgás',
'precipitation': 'Csapadék', 'precipitation': 'Csapadék',
'direction': 'Irány', 'direction': 'Irány',
'pressure': 'Nyomás', 'pressure': 'Nyomás',
'rain': 'Eső', 'rain': 'Eső',
'clear_sky': 'Tiszta ég', 'clear_sky': 'Tiszta ég',
'cloudy': 'Felhős', 'cloudy': 'Felhős',
'overcast': 'Borult', 'overcast': 'Borult',
'fog': 'Köd', 'fog': 'Köd',
'drizzle': 'Szitálás', 'drizzle': 'Szitálás',
'drizzling_rain': 'Fagyos szitálás', 'drizzling_rain': 'Fagyos szitálás',
'freezing_rain': 'Fagyos eső', 'freezing_rain': 'Fagyos eső',
'heavy_rains': 'Zivataros záporok', 'heavy_rains': 'Zivataros záporok',
'snow': '', 'snow': '',
'thunderstorm': 'Zivatar', 'thunderstorm': 'Zivatar',
'kph': 'km/óra', 'kph': 'km/óra',
'mph': 'mph', 'mph': 'mph',
'mi': 'mérföld', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'hüvelyk', 'mi': 'mérföld',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'hüvelyk',
'settings': 'Beállítások', 'mm': 'mm',
'no_inter': 'Nincs internet', 'hPa': 'hPa',
'on_inter': 'settings': 'Beállítások',
'Kapcsolja be az internetet az időjárási adatok lekéréséhez.', 'no_inter': 'Nincs internet',
'location': 'Hely', 'on_inter': 'Kapcsolja be az internetet az időjárási adatok lekéréséhez.',
'no_location': 'location': 'Hely',
'Engedélyezze a helyszolgáltatást az aktuális hely időjárásadatainak megszerzéséhez.', 'no_location':
'theme': 'Téma', 'Engedélyezze a helyszolgáltatást az aktuális hely időjárásadatainak megszerzéséhez.',
'low': 'Alacsony', 'theme': 'Téma',
'high': 'Magas', 'low': 'Alacsony',
'normal': 'Normál', 'high': 'Magas',
'lat': 'Szélesség', 'normal': 'Normál',
'lon': 'Hosszúság', 'lat': 'Szélesség',
'create': 'Létrehozás', 'lon': 'Hosszúság',
'city': 'Város', 'create': 'Létrehozás',
'district': 'Kerület', 'city': 'Város',
'noWeatherCard': 'Adjon hozzá egy várost', 'district': 'Kerület',
'deletedCardWeather': 'Város törlése', 'noWeatherCard': 'Adjon hozzá egy várost',
'deletedCardWeatherQuery': 'Biztosan törölni szeretné a várost?', 'deletedCardWeather': 'Város törlése',
'delete': 'Törlés', 'deletedCardWeatherQuery': 'Biztosan törölni szeretné a várost?',
'cancel': 'Mégse', 'delete': 'Törlés',
'time': 'Idő a városban', 'cancel': 'Mégse',
'validateName': 'Kérjük, adja meg a nevet', 'time': 'Idő a városban',
'measurements': 'Mérési rendszer', 'validateName': 'Kérjük, adja meg a nevet',
'degrees': 'Fok', 'measurements': 'Mérési rendszer',
'celsius': 'Celsius', 'degrees': 'Fok',
'fahrenheit': 'Fahrenheit', 'celsius': 'Celsius',
'imperial': 'Angol mértékegység', 'fahrenheit': 'Fahrenheit',
'metric': 'Metrikus mértékegység', 'imperial': 'Angol mértékegység',
'validateValue': 'Kérjük, adjon meg egy értéket', 'metric': 'Metrikus mértékegység',
'validateNumber': 'Kérjük, adjon meg érvényes számot', 'validateValue': 'Kérjük, adjon meg egy értéket',
'validate90': 'Az érték -90 és 90 közötti kell legyen', 'validateNumber': 'Kérjük, adjon meg érvényes számot',
'validate180': 'Az érték -180 és 180 közötti kell legyen', 'validate90': 'Az érték -90 és 90 közötti kell legyen',
'notifications': 'Értesítések', 'validate180': 'Az érték -180 és 180 közötti kell legyen',
'sunrise': 'Napkelte', 'notifications': 'Értesítések',
'sunset': 'Napnyugta', 'sunrise': 'Napkelte',
'timeformat': 'Időformátum', 'sunset': 'Napnyugta',
'12': '12 órás', 'timeformat': 'Időformátum',
'24': '24 órás', '12': '12 órás',
'cloudcover': 'Felhőzet', '24': '24 órás',
'uvIndex': 'UV-index', 'cloudcover': 'Felhőzet',
'materialColor': 'Dinamikus színek', 'uvIndex': 'UV-index',
'uvLow': 'Alacsony', 'materialColor': 'Dinamikus színek',
'uvAverage': 'Mérsékelt', 'uvLow': 'Alacsony',
'uvHigh': 'Magas', 'uvAverage': 'Mérsékelt',
'uvVeryHigh': 'Nagyon magas', 'uvHigh': 'Magas',
'uvExtreme': 'Extrém', 'uvVeryHigh': 'Nagyon magas',
'weatherMore': '12 napos időjárás előrejelzés', 'uvExtreme': 'Extrém',
'windgusts': 'Szélrohamok', 'weatherMore': '12 napos időjárás előrejelzés',
'north': 'Észak', 'windgusts': 'Szélrohamok',
'northeast': 'Északkelet', 'north': 'Észak',
'east': 'Kelet', 'northeast': 'Északkelet',
'southeast': 'Délkelet', 'east': 'Kelet',
'south': 'Dél', 'southeast': 'Délkelet',
'southwest': 'Délkelet', 'south': 'Dél',
'west': 'Nyugat', 'southwest': 'Délkelet',
'northwest': 'Északnyugat', 'west': 'Nyugat',
'project': 'Projekt', 'northwest': 'Északnyugat',
'version': 'Alkalmazás verzió', 'project': 'Projekt',
'precipitationProbability': 'Csapadék valószínűsége', 'version': 'Alkalmazás verzió',
'apparentTemperatureMin': 'Minimális látszólagos hőmérséklet', 'precipitationProbability': 'Csapadék valószínűsége',
'apparentTemperatureMax': 'Maximális látszólagos hőmérséklet', 'apparentTemperatureMin': 'Minimális látszólagos hőmérséklet',
'amoledTheme': 'AMOLED téma', 'apparentTemperatureMax': 'Maximális látszólagos hőmérséklet',
'appearance': 'Megjelenés', 'amoledTheme': 'AMOLED téma',
'functions': 'Funkciók', 'appearance': 'Megjelenés',
'data': 'Adatok', 'functions': 'Funkciók',
'language': 'Nyelv', 'data': 'Adatok',
'timeRange': 'Gyakoriság (órákban)', 'language': 'Nyelv',
'timeStart': 'Kezdési idő', 'timeRange': 'Gyakoriság (órákban)',
'timeEnd': 'Befejezési idő', 'timeStart': 'Kezdési idő',
'support': 'Támogatás', 'timeEnd': 'Befejezési idő',
'system': 'Rendszer', 'support': 'Támogatás',
'dark': 'Sötét', 'system': 'Rendszer',
'light': 'Világos', 'dark': 'Sötét',
'license': 'Licenc', 'light': 'Világos',
'widget': 'Widget', 'license': 'Licenc',
'widgetBackground': 'Widget háttér', 'widget': 'Widget',
'widgetText': 'Widget szöveg', 'widgetBackground': 'Widget háttér',
'dewpoint': 'Harmatpont', 'widgetText': 'Widget szöveg',
'shortwaveRadiation': 'Rövidhullámú sugárzás', 'dewpoint': 'Harmatpont',
'W/m2': 'W/m2', 'shortwaveRadiation': 'Rövidhullámú sugárzás',
'roundDegree': 'Fokok Kerekítése', 'W/m2': 'W/m2',
'settings_full': 'Beállítások', 'roundDegree': 'Fokok Kerekítése',
'cities': 'Városok', 'settings_full': 'Beállítások',
'searchMethod': 'Használja a keresést vagy a földrajzi helyet', 'cities': 'Városok',
'done': 'Kész', 'searchMethod': 'Használja a keresést vagy a földrajzi helyet',
'groups': 'Csoportjaink', 'done': 'Kész',
'openMeteo': 'Adatok az Open-Meteo-tól (CC-BY 4.0)', 'groups': 'Csoportjaink',
'hourlyVariables': 'Óránkénti időjárási változók', 'openMeteo': 'Adatok az Open-Meteo-tól (CC-BY 4.0)',
'dailyVariables': 'Napi időjárási változók', 'hourlyVariables': 'Óránkénti időjárási változók',
}; 'dailyVariables': 'Napi időjárási változók',
'largeElement': 'Nagy méretű időjárás megjelenítése',
'map': 'Térkép',
'clearCacheStore': 'Gyorsítótár törlése',
'deletedCacheStore': 'Gyorsítótár törlése folyamatban',
'deletedCacheStoreQuery': 'Biztosan törölni szeretné a gyorsítótárat?',
'addWidget': 'Widget hozzáadása',
'hideMap': 'Térkép elrejtése',
};
} }

269
lib/translation/it_it.dart Normal file → Executable file
View file

@ -1,134 +1,141 @@
class ItIt { class ItIt {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Clicca per iniziare', 'start': 'Clicca per iniziare',
'description': 'description':
'Applicazione meteo con una previsione aggiornata per ogni ora, giorno e settimana per qualsiasi luogo.', 'Applicazione meteo con una previsione aggiornata per ogni ora, giorno e settimana per qualsiasi luogo.',
'name': 'Meteo', 'name': 'Meteo',
'name2': 'Design comodo', 'name2': 'Design comodo',
'name3': 'Contattaci', 'name3': 'Contattaci',
'description2': 'description2':
'Tutta la navigazione è progettata per interagire con l\'applicazione nel modo più comodo e veloce possibile.', 'Tutta la navigazione è progettata per interagire con l\'applicazione nel modo più comodo e veloce possibile.',
'description3': 'description3':
'Se incontri problemi, contattaci via email o nelle recensioni dell\'applicazione.', 'Se incontri problemi, contattaci via email o nelle recensioni dell\'applicazione.',
'next': 'Avanti', 'next': 'Avanti',
'search': 'Cerca...', 'search': 'Cerca...',
'loading': 'Caricamento...', 'loading': 'Caricamento...',
'searchCity': 'Trova la tua città', 'searchCity': 'Trova la tua città',
'humidity': 'Umidità', 'humidity': 'Umidità',
'wind': 'Vento', 'wind': 'Vento',
'visibility': 'Visibilità', 'visibility': 'Visibilità',
'feels': 'Percepiti', 'feels': 'Percepiti',
'evaporation': 'Evaporazione', 'evaporation': 'Evaporazione',
'precipitation': 'Precipitazione', 'precipitation': 'Precipitazione',
'direction': 'Direzione', 'direction': 'Direzione',
'pressure': 'Pressione', 'pressure': 'Pressione',
'rain': 'Pioggia', 'rain': 'Pioggia',
'clear_sky': 'Sereno', 'clear_sky': 'Sereno',
'cloudy': 'Nuvoloso', 'cloudy': 'Nuvoloso',
'overcast': 'Coperto', 'overcast': 'Coperto',
'fog': 'Nebbia', 'fog': 'Nebbia',
'drizzle': 'Pioggerella', 'drizzle': 'Pioggerella',
'drizzling_rain': 'Pioggerella Gelata', 'drizzling_rain': 'Pioggerella Gelata',
'freezing_rain': 'Pioggia Gelata', 'freezing_rain': 'Pioggia Gelata',
'heavy_rains': 'Acquazzone', 'heavy_rains': 'Acquazzone',
'snow': 'Neve', 'snow': 'Neve',
'thunderstorm': 'Temporale', 'thunderstorm': 'Temporale',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'inch', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'inch',
'settings': 'Imposta.', 'mm': 'mm',
'no_inter': 'Non c\'è connessione Internet', 'hPa': 'hPa',
'on_inter': 'settings': 'Imposta.',
'Attiva la connessione Internet per avere dati meteorologici.', 'no_inter': 'Non c\'è connessione Internet',
'location': 'Posizione', 'on_inter': 'Attiva la connessione Internet per avere dati meteorologici.',
'no_location': 'location': 'Posizione',
'Abilita il servizio di localizzazione per ottenere i dati meteo per la posizione corrente.', 'no_location':
'theme': 'Tema', 'Abilita il servizio di localizzazione per ottenere i dati meteo per la posizione corrente.',
'low': 'Basso', 'theme': 'Tema',
'high': 'Alto', 'low': 'Basso',
'normal': 'Normale', 'high': 'Alto',
'lat': 'Latitudine', 'normal': 'Normale',
'lon': 'Longitudine', 'lat': 'Latitudine',
'create': 'Creare', 'lon': 'Longitudine',
'city': 'Città', 'create': 'Creare',
'district': 'Regione', 'city': 'Città',
'noWeatherCard': 'Aggiungi una città', 'district': 'Regione',
'deletedCardWeather': 'Rimozione della città', 'noWeatherCard': 'Aggiungi una città',
'deletedCardWeatherQuery': 'deletedCardWeather': 'Rimozione della città',
'Sei sicuro di voler rimuovere questa città?', 'deletedCardWeatherQuery': 'Sei sicuro di voler rimuovere questa città?',
'delete': 'Elimina', 'delete': 'Elimina',
'cancel': 'Annulla', 'cancel': 'Annulla',
'time': 'Orario locale', 'time': 'Orario locale',
'validateName': 'Si prega di inserire il nome', 'validateName': 'Si prega di inserire il nome',
'measurements': 'Sistema di misure', 'measurements': 'Sistema di misure',
'degrees': 'Gradi', 'degrees': 'Gradi',
'celsius': 'Celsius', 'celsius': 'Celsius',
'fahrenheit': 'Fahrenheit', 'fahrenheit': 'Fahrenheit',
'imperial': 'Imperiale', 'imperial': 'Imperiale',
'metric': 'Metrico', 'metric': 'Metrico',
'validateValue': 'Si prega di inserire il valore', 'validateValue': 'Si prega di inserire il valore',
'validateNumber': 'Si prega di inserire il numero', 'validateNumber': 'Si prega di inserire il numero',
'validate90': 'Il valore deve essere compreso tra -90 e 90', 'validate90': 'Il valore deve essere compreso tra -90 e 90',
'validate180': 'Il valore deve essere compreso tra -180 e 180', 'validate180': 'Il valore deve essere compreso tra -180 e 180',
'notifications': 'Notifiche', 'notifications': 'Notifiche',
'sunrise': 'Alba', 'sunrise': 'Alba',
'sunset': 'Tramonto', 'sunset': 'Tramonto',
'timeformat': 'Formato ora', 'timeformat': 'Formato ora',
'12': '12 ore', '12': '12 ore',
'24': '24 ore', '24': '24 ore',
'cloudcover': 'Copertura nuvolosa', 'cloudcover': 'Copertura nuvolosa',
'uvIndex': 'Indice UV', 'uvIndex': 'Indice UV',
'materialColor': 'Colori Dinamici', 'materialColor': 'Colori Dinamici',
'uvLow': 'Basso', 'uvLow': 'Basso',
'uvAverage': 'Moderato', 'uvAverage': 'Moderato',
'uvHigh': 'Alto', 'uvHigh': 'Alto',
'uvVeryHigh': 'Molto alto', 'uvVeryHigh': 'Molto alto',
'uvExtreme': 'Estremo', 'uvExtreme': 'Estremo',
'weatherMore': 'Previsioni del tempo per 12 giorni', 'weatherMore': 'Previsioni del tempo per 12 giorni',
'windgusts': 'Raffica', 'windgusts': 'Raffica',
'north': 'Nord', 'north': 'Nord',
'northeast': 'Nord-est', 'northeast': 'Nord-est',
'east': 'Est', 'east': 'Est',
'southeast': 'Sud-est', 'southeast': 'Sud-est',
'south': 'Sud', 'south': 'Sud',
'southwest': 'Sud-ovest', 'southwest': 'Sud-ovest',
'west': 'Ovest', 'west': 'Ovest',
'northwest': 'Nord-ovest', 'northwest': 'Nord-ovest',
'project': 'Progetto su', 'project': 'Progetto su',
'version': 'Versione dell\'applicazione', 'version': 'Versione dell\'applicazione',
'precipitationProbability': 'Probabilità di precipitazione', 'precipitationProbability': 'Probabilità di precipitazione',
'apparentTemperatureMin': 'Temperatura minima percepita', 'apparentTemperatureMin': 'Temperatura minima percepita',
'apparentTemperatureMax': 'Temperatura massima percepita', 'apparentTemperatureMax': 'Temperatura massima percepita',
'amoledTheme': 'AMOLED-tema', 'amoledTheme': 'AMOLED-tema',
'appearance': 'Aspetto', 'appearance': 'Aspetto',
'functions': 'Funzioni', 'functions': 'Funzioni',
'data': 'Dati', 'data': 'Dati',
'language': 'Lingua', 'language': 'Lingua',
'timeRange': 'Frequenza (in ore)', 'timeRange': 'Frequenza (in ore)',
'timeStart': 'Ora di inizio', 'timeStart': 'Ora di inizio',
'timeEnd': 'Ora di fine', 'timeEnd': 'Ora di fine',
'support': 'Supporto', 'support': 'Supporto',
'system': 'Sistema', 'system': 'Sistema',
'dark': 'Scuro', 'dark': 'Scuro',
'light': 'Chiaro', 'light': 'Chiaro',
'license': 'Licenze', 'license': 'Licenze',
'widget': 'Widget', 'widget': 'Widget',
'widgetBackground': 'Sfondo del widget', 'widgetBackground': 'Sfondo del widget',
'widgetText': 'Testo del widget', 'widgetText': 'Testo del widget',
'dewpoint': 'Punto di rugiada', 'dewpoint': 'Punto di rugiada',
'shortwaveRadiation': 'Radiazione a onde corte', 'shortwaveRadiation': 'Radiazione a onde corte',
'roundDegree': 'Arrotonda i gradi', 'roundDegree': 'Arrotonda i gradi',
'settings_full': 'Impostazioni', 'settings_full': 'Impostazioni',
'cities': 'Città', 'cities': 'Città',
'searchMethod': 'Utilizza la ricerca o la geolocalizzazione', 'searchMethod': 'Utilizza la ricerca o la geolocalizzazione',
'done': 'Fatto', 'done': 'Fatto',
'groups': 'I nostri gruppi', 'groups': 'I nostri gruppi',
'openMeteo': 'Dati da Open-Meteo (CC-BY 4.0)', 'openMeteo': 'Dati da Open-Meteo (CC-BY 4.0)',
'hourlyVariables': 'Variabili meteorologiche orarie', 'hourlyVariables': 'Variabili meteorologiche orarie',
'dailyVariables': 'Variabili meteorologiche giornaliere', 'dailyVariables': 'Variabili meteorologiche giornaliere',
}; 'largeElement': 'Visualizzazione grande elemento meteo',
'map': 'Mappa',
'clearCacheStore': 'Cancella cache',
'deletedCacheStore': 'Cancellazione della cache',
'deletedCacheStoreQuery': 'Sei sicuro di voler cancellare la cache?',
'addWidget': 'Aggiungi widget',
'hideMap': 'Nascondi mappa',
};
} }

268
lib/translation/ka_ge.dart Normal file → Executable file
View file

@ -1,133 +1,141 @@
class KaGe { class KaGe {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'დაიწყე', 'start': 'დაიწყე',
'description': 'description':
'აპლიკაცია ამჟამად პროგნოზით ყოველ საათზე, დღეზე და კვირაზე ნებისმიერ ადგილისთვის.', 'აპლიკაცია ამჟამად პროგნოზით ყოველ საათზე, დღეზე და კვირაზე ნებისმიერ ადგილისთვის.',
'name': 'ამინდი', 'name': 'ამინდი',
'name2': 'მართვის კომფორტი', 'name2': 'მართვის კომფორტი',
'name3': 'შეგვეხმიანე', 'name3': 'შეგვეხმიანე',
'description2': 'description2':
'ყველა ნავიგაცია შექმნილია ისე, რომ შეგიძლიათ მაქსიმალურად კომფორტულად და სწრაფად იქონოთ აპლიკაციით.', 'ყველა ნავიგაცია შექმნილია ისე, რომ შეგიძლიათ მაქსიმალურად კომფორტულად და სწრაფად იქონოთ აპლიკაციით.',
'description3': 'description3':
'თუ გექნებათ ნებისმიერი პრობლემა, გთხოვთ, დაგვეკონტაქტოთ ელ-ფოსტით ან აპლიკაციის მიმოხილვის გვერდზე.', 'თუ გექნებათ ნებისმიერი პრობლემა, გთხოვთ, დაგვეკონტაქტოთ ელ-ფოსტით ან აპლიკაციის მიმოხილვის გვერდზე.',
'next': 'შემდეგ', 'next': 'შემდეგ',
'search': 'ძიება...', 'search': 'ძიება...',
'loading': 'დატვირთვა...', 'loading': 'დატვირთვა...',
'searchCity': 'იპოვეთ თქვენი ქალაქი', 'searchCity': 'იპოვეთ თქვენი ქალაქი',
'humidity': 'ტენიანობა', 'humidity': 'ტენიანობა',
'wind': 'ქარი', 'wind': 'ქარი',
'visibility': 'ხილვადობა', 'visibility': 'ხილვადობა',
'feels': 'გრძნობს', 'feels': 'გრძნობს',
'evaporation': 'აორთქლება', 'evaporation': 'აორთქლება',
'precipitation': 'ნალექი', 'precipitation': 'ნალექი',
'direction': 'მიმართულება', 'direction': 'მიმართულება',
'pressure': 'წნევა', 'pressure': 'წნევა',
'rain': 'წვიმა', 'rain': 'წვიმა',
'clear_sky': 'წმინდა ცა', 'clear_sky': 'წმინდა ცა',
'cloudy': 'მოღრუბლული', 'cloudy': 'მოღრუბლული',
'overcast': 'მოსაწყენი', 'overcast': 'მოსაწყენი',
'fog': 'ნისლი', 'fog': 'ნისლი',
'drizzle': 'წვიმა', 'drizzle': 'წვიმა',
'drizzling_rain': 'დრიზლინგი წვიმა', 'drizzling_rain': 'დრიზლინგი წვიმა',
'freezing_rain': 'გაყინვის წვიმა', 'freezing_rain': 'გაყინვის წვიმა',
'heavy_rains': 'ძლიერი წვიმები', 'heavy_rains': 'ძლიერი წვიმები',
'snow': 'თოვლი', 'snow': 'თოვლი',
'thunderstorm': 'ჭექა-ქუხილი', 'thunderstorm': 'ჭექა-ქუხილი',
'kph': 'კმ/სთ', 'kph': 'კმ/სთ',
'mph': 'მილი/სთ', 'mph': 'მილი/სთ',
'mi': 'მილი', 'm/s': 'მ/წმ',
'km': 'კმ', 'mmHg': 'მმHg',
'inch': 'ინჩი', 'mi': 'მილი',
'mm': 'მმ', 'km': 'კმ',
'hPa': 'ჰპა', 'inch': 'ინჩი',
'settings': 'პარამ.', 'mm': 'მმ',
'no_inter': 'ინტერნეტი არ არის', 'hPa': 'ჰპა',
'on_inter': 'ჩართეთ ინტერნეტი მეტეოროლოგიური მონაცემების მისაღებად.', 'settings': 'პარამ.',
'location': 'ადგილმდებარეობა', 'no_inter': 'ინტერნეტი არ არის',
'no_location': 'on_inter': 'ჩართეთ ინტერნეტი მეტეოროლოგიური მონაცემების მისაღებად.',
'ჩართეთ მდებარეობის სერვისი, რომ მიიღოთ ამინდის მონაცემები მიმდინარე ადგილმდებარეობისთვის.', 'location': 'ადგილმდებარეობა',
'theme': 'თემა', 'no_location':
'low': 'დაბალი', 'ჩართეთ მდებარეობის სერვისი, რომ მიიღოთ ამინდის მონაცემები მიმდინარე ადგილმდებარეობისთვის.',
'high': 'მაღალი', 'theme': 'თემა',
'normal': 'ნორმალური', 'low': 'დაბალი',
'lat': 'სიგანე', 'high': 'მაღალი',
'lon': 'გრძედი', 'normal': 'ნორმალური',
'create': 'შექმნა', 'lat': 'სიგანე',
'city': 'ქალაქი', 'lon': 'გრძედი',
'district': 'რაიონი', 'create': 'შექმნა',
'noWeatherCard': 'დაამატეთ ქალაქი', 'city': 'ქალაქი',
'deletedCardWeather': 'ქალაქის წაშლა', 'district': 'რაიონი',
'deletedCardWeatherQuery': 'noWeatherCard': 'დაამატეთ ქალაქი',
'დარწმუნებული ხართ, რომ გსურთ ქალაქის წაშლა?', 'deletedCardWeather': 'ქალაქის წაშლა',
'delete': 'ამოღება', 'deletedCardWeatherQuery': 'დარწმუნებული ხართ, რომ გსურთ ქალაქის წაშლა?',
'cancel': 'გაუქმება', 'delete': 'ამოღება',
'time': 'დრო ქალაქში', 'cancel': 'გაუქმება',
'validateName': 'გთხოვთ შეიყვანოთ სახელი', 'time': 'დრო ქალაქში',
'measurements': 'საზომი სისტემა', 'validateName': 'გთხოვთ შეიყვანოთ სახელი',
'degrees': 'გრადუსი', 'measurements': 'საზომი სისტემა',
'celsius': 'ცელსიუსი', 'degrees': 'გრადუსი',
'fahrenheit': 'ფარენჰაიტი', 'celsius': 'ცელსიუსი',
'imperial': 'იმპერიული', 'fahrenheit': 'ფარენჰაიტი',
'metric': 'მეტრული', 'imperial': 'იმპერიული',
'validateValue': 'გთხოვთ შეიყვანოთ მნიშვნელობა', 'metric': 'მეტრული',
'validateNumber': 'გთხოვთ შეიყვანოთ ნომერი', 'validateValue': 'გთხოვთ შეიყვანოთ მნიშვნელობა',
'validate90': 'მნიშვნელობა უნდა იყოს -90-დან 90-მდე', 'validateNumber': 'გთხოვთ შეიყვანოთ ნომერი',
'validate180': 'მნიშვნელობა უნდა იყოს -180-დან 180-მდე', 'validate90': 'მნიშვნელობა უნდა იყოს -90-დან 90-მდე',
'notifications': 'შეტყობინებები', 'validate180': 'მნიშვნელობა უნდა იყოს -180-დან 180-მდე',
'sunrise': 'მზის ამოსვლა', 'notifications': 'შეტყობინებები',
'sunset': 'მზის ჩასვლა', 'sunrise': 'მზის ამოსვლა',
'timeformat': 'დროის ფორმატი', 'sunset': 'მზის ჩასვლა',
'12': '12-საათი', 'timeformat': 'დროის ფორმატი',
'24': '24-საათი', '12': '12-საათი',
'cloudcover': 'ღრუბლის საფარი', '24': '24-საათი',
'uvIndex': 'UV-ინდექსი', 'cloudcover': 'ღრუბლის საფარი',
'materialColor': 'დინამიური ფერები', 'uvIndex': 'UV-ინდექსი',
'uvLow': 'დაბალი', 'materialColor': 'დინამიური ფერები',
'uvAverage': 'ზომიერი', 'uvLow': 'დაბალი',
'uvHigh': 'მაღალი', 'uvAverage': 'ზომიერი',
'uvVeryHigh': 'ძალიან მაღალი', 'uvHigh': 'მაღალი',
'uvExtreme': 'ძლევა ზედა', 'uvVeryHigh': 'ძალიან მაღალი',
'weatherMore': '12-დღიანი ამინდის პროგნოზი', 'uvExtreme': 'ძლევა ზედა',
'windgusts': 'ნაკადი', 'weatherMore': '12-დღიანი ამინდის პროგნოზი',
'north': 'ჩრდილოეთი', 'windgusts': 'ნაკადი',
'northeast': 'ჩრდილო-აღმოსავლეთი', 'north': 'ჩრდილოეთი',
'east': 'აღმოსავლეთი', 'northeast': 'ჩრდილო-აღმოსავლეთი',
'southeast': 'სამხრეთ-აღმოსავლეთი', 'east': 'აღმოსავლეთი',
'south': 'სამხრეთი', 'southeast': 'სამხრეთ-აღმოსავლეთი',
'southwest': 'სამხრეთ-დასავლეთი', 'south': 'სამხრეთი',
'west': 'დასავლეთი', 'southwest': 'სამხრეთ-დასავლეთი',
'northwest': 'ჩრდილო-დასავლეთი', 'west': 'დასავლეთი',
'project': 'პროექტი ჩართულია', 'northwest': 'ჩრდილო-დასავლეთი',
'version': 'განაცხადის ვერსია', 'project': 'პროექტი ჩართულია',
'precipitationProbability': 'ნალექების ალბათობა', 'version': 'განაცხადის ვერსია',
'apparentTemperatureMin': 'მინიმალური აშკარა ტემპერატურა', 'precipitationProbability': 'ნალექების ალბათობა',
'apparentTemperatureMax': 'მაქსიმალური აშკარა ტემპერატურა', 'apparentTemperatureMin': 'მინიმალური აშკარა ტემპერატურა',
'amoledTheme': 'AMOLED-თემა', 'apparentTemperatureMax': 'მაქსიმალური აშკარა ტემპერატურა',
'appearance': 'გარეგნობა', 'amoledTheme': 'AMOLED-თემა',
'functions': 'ფუნქციები', 'appearance': 'გარეგნობა',
'data': 'მონაცემები', 'functions': 'ფუნქციები',
'language': 'ენა', 'data': 'მონაცემები',
'timeRange': 'სიხშირე (საათებში)', 'language': 'ენა',
'timeStart': 'დაწყების დრო', 'timeRange': 'სიხშირე (საათებში)',
'timeEnd': 'დასრულების დრო', 'timeStart': 'დაწყების დრო',
'support': 'მხარდაჭერა', 'timeEnd': 'დასრულების დრო',
'system': 'სისტემა', 'support': 'მხარდაჭერა',
'dark': 'ბნელი', 'system': 'სისტემა',
'light': 'სინათლე', 'dark': 'ბნელი',
'license': 'ლიცენზიები', 'light': 'სინათლე',
'widget': 'ვიჯეტი', 'license': 'ლიცენზიები',
'widgetBackground': 'ვიჯეტის ფონი', 'widget': 'ვიჯეტი',
'widgetText': 'ვიჯეტის ტექსტი', 'widgetBackground': 'ვიჯეტის ფონი',
'dewpoint': 'დევპოინტი', 'widgetText': 'ვიჯეტის ტექსტი',
'shortwaveRadiation': 'მოკლე ტალღის გამოსხივება', 'dewpoint': 'დევპოინტი',
'roundDegree': 'ხარისხი მიჯნურობა', 'shortwaveRadiation': 'მოკლე ტალღის გამოსხივება',
'settings_full': 'პარამეტრები', 'roundDegree': 'ხარისხი მიჯნურობა',
'cities': 'ქალაქები', 'settings_full': 'პარამეტრები',
'searchMethod': 'გამოიყენეთ ძებნა ან გეოლოკაცია', 'cities': 'ქალაქები',
'done': 'დასრულებულია', 'searchMethod': 'გამოიყენეთ ძებნა ან გეოლოკაცია',
'groups': 'ჩვენი ჯგუფები', 'done': 'დასრულებულია',
'openMeteo': 'მონაცემები Open-Meteo-დან (CC-BY 4.0)', 'groups': 'ჩვენი ჯგუფები',
'hourlyVariables': 'საათობრივი ამინდის ცვლადები', 'openMeteo': 'მონაცემები Open-Meteo-დან (CC-BY 4.0)',
'dailyVariables': 'ყოველდღიური ამინდის ცვლადები', 'hourlyVariables': 'საათობრივი ამინდის ცვლადები',
}; 'dailyVariables': 'ყოველდღიური ამინდის ცვლადები',
'largeElement': 'გადიდი ამინდის გამოჩენა',
'map': 'რუკა',
'clearCacheStore': 'ქეშის გასუფთავება',
'deletedCacheStore': 'ქეშის გასუფთავება მიმდინარეობს',
'deletedCacheStoreQuery': 'დარწმუნებული ხართ, რომ გსურთ ქეშის გასუფთავება?',
'addWidget': 'ვიდჯეტის დამატება',
'hideMap': 'რუკის დამალვა',
};
} }

261
lib/translation/ko_kr.dart Normal file → Executable file
View file

@ -1,129 +1,138 @@
class KoKr { class KoKr {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': '시작하기', 'start': '시작하기',
'description': '어떤 곳이든, 어느 순간이든, 날씨를 확인하세요.', 'description': '어떤 곳이든, 어느 순간이든, 날씨를 확인하세요.',
'name': '날씨', 'name': '날씨',
'name2': '편리한 디자인', 'name2': '편리한 디자인',
'name3': '문의하기', 'name3': '문의하기',
'description2': '모든 내비게이션은 가능한 한 편리하고 빠르게 애플리케이션과 상호 작용하도록 설계되었습니다.', 'description2': '모든 내비게이션은 가능한 한 편리하고 빠르게 애플리케이션과 상호 작용하도록 설계되었습니다.',
'description3': '어떤 오류가 발생했다면, 이메일 또는 앱 리뷰로 문의해주세요.', 'description3': '어떤 오류가 발생했다면, 이메일 또는 앱 리뷰로 문의해주세요.',
'next': '다음', 'next': '다음',
'search': '검색...', 'search': '검색...',
'loading': '로딩 중...', 'loading': '로딩 중...',
'searchCity': '도시를 찾아보세요', 'searchCity': '도시를 찾아보세요',
'humidity': '습도', 'humidity': '습도',
'wind': '풍속', 'wind': '풍속',
'visibility': '가시거리', 'visibility': '가시거리',
'feels': '체감 온도', 'feels': '체감 온도',
'evaporation': '증발량', 'evaporation': '증발량',
'precipitation': '강수량', 'precipitation': '강수량',
'direction': '풍향', 'direction': '풍향',
'pressure': '기압', 'pressure': '기압',
'rain': '', 'rain': '',
'clear_sky': '맑음', 'clear_sky': '맑음',
'cloudy': '구름 조금', 'cloudy': '구름 조금',
'overcast': '구름 많음', 'overcast': '구름 많음',
'fog': '안개', 'fog': '안개',
'drizzle': '이슬비', 'drizzle': '이슬비',
'drizzling_rain': '얼어붙은 이슬비', 'drizzling_rain': '얼어붙은 이슬비',
'freezing_rain': '얼어붙는 비', 'freezing_rain': '얼어붙는 비',
'heavy_rains': '폭우', 'heavy_rains': '폭우',
'snow': '', 'snow': '',
'thunderstorm': '천둥번개', 'thunderstorm': '천둥번개',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': '미터/초',
'km': 'km', 'mmHg': '밀리미터 수은주',
'inch': '인치', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': '인치',
'settings': '설정', 'mm': 'mm',
'no_inter': '인터넷 없음', 'hPa': 'hPa',
'on_inter': '현재 위치에 대한 정보를 얻기 위해서는 인터넷이 필요합니다.', 'settings': '설정',
'location': '위치', 'no_inter': '인터넷 없음',
'no_location': '현재 위치에 대한 정보를 얻기 위해서는 위치 서비스를 활성화해야 합니다.', 'on_inter': '현재 위치에 대한 정보를 얻기 위해서는 인터넷이 필요합니다.',
'theme': '테마', 'location': '위치',
'low': '낮음', 'no_location': '현재 위치에 대한 정보를 얻기 위해서는 위치 서비스를 활성화해야 합니다.',
'high': '높음', 'theme': '테마',
'normal': '보통', 'low': '낮음',
'lat': '위도', 'high': '높음',
'lon': '경도', 'normal': '보통',
'create': '만들기', 'lat': '위도',
'city': '도시', 'lon': '경도',
'district': '지역', 'create': '만들기',
'noWeatherCard': '도시를 추가하세요', 'city': '도시',
'deletedCardWeather': '도시 삭제하기', 'district': '지역',
'deletedCardWeatherQuery': '정말로 이 도시를 삭제하시겠나요?', 'noWeatherCard': '도시를 추가하세요',
'delete': '삭제', 'deletedCardWeather': '도시 삭제하기',
'cancel': '취소', 'deletedCardWeatherQuery': '정말로 이 도시를 삭제하시겠나요?',
'time': '도시 시간', 'delete': '삭제',
'validateName': '이름을 입력해주세요', 'cancel': '취소',
'measurements': '표시 방식', 'time': '도시 시간',
'degrees': '', 'validateName': '이름을 입력해주세요',
'celsius': '섭씨', 'measurements': '표시 방식',
'fahrenheit': '화씨', 'degrees': '',
'imperial': '인치', 'celsius': '섭씨',
'metric': '미터', 'fahrenheit': '화씨',
'validateValue': '값을 입력해주세요', 'imperial': '인치',
'validateNumber': '올바른 숫자를 입력해주세요', 'metric': '미터',
'validate90': '-90과 90 사이의 값만 가능합니다', 'validateValue': '값을 입력해주세요',
'validate180': '-180과 180 사이의 값만 가능합니다', 'validateNumber': '올바른 숫자를 입력해주세요',
'notifications': '알림', 'validate90': '-90과 90 사이의 값만 가능합니다',
'sunrise': '일출', 'validate180': '-180과 180 사이의 값만 가능합니다',
'sunset': '일몰', 'notifications': '알림',
'timeformat': '시간 형식', 'sunrise': '일출',
'12': '12시간', 'sunset': '일몰',
'24': '24시간', 'timeformat': '시간 형식',
'cloudcover': '구름', '12': '12시간',
'uvIndex': 'UV 정도', '24': '24시간',
'materialColor': '동적 색상', 'cloudcover': '구름',
'uvLow': '낮음', 'uvIndex': 'UV 정도',
'uvAverage': '보통', 'materialColor': '동적 색상',
'uvHigh': '높은', 'uvLow': '낮음',
'uvVeryHigh': '매우 높음', 'uvAverage': '보통',
'uvExtreme': '엄청남!', 'uvHigh': '높은',
'weatherMore': '12일 일기 예보', 'uvVeryHigh': '매우 높음',
'windgusts': '돌풍', 'uvExtreme': '엄청남!',
'north': '', 'weatherMore': '12일 일기 예보',
'northeast': '북동', 'windgusts': '돌풍',
'east': '', 'north': '',
'southeast': '남동', 'northeast': '북동',
'south': '', 'east': '',
'southwest': '남서', 'southeast': '남동',
'west': '', 'south': '',
'northwest': '북서', 'southwest': '남서',
'project': '프로젝트 위치:', 'west': '',
'version': '버전', 'northwest': '북서',
'precipitationProbability': '깅수 확률', 'project': '프로젝트 위치:',
'apparentTemperatureMin': '최저 기온', 'version': '버전',
'apparentTemperatureMax': '최고 기온', 'precipitationProbability': '깅수 확률',
'amoledTheme': 'AMOLED-테마', 'apparentTemperatureMin': '최저 기온',
'appearance': '디자인', 'apparentTemperatureMax': '최고 기온',
'functions': '기능', 'amoledTheme': 'AMOLED-테마',
'data': '데이터', 'appearance': '디자인',
'language': '언어', 'functions': '기능',
'timeRange': '빈도 (시간 단위)', 'data': '데이터',
'timeStart': '시작 시간', 'language': '언어',
'timeEnd': '종료 시간', 'timeRange': '빈도 (시간 단위)',
'support': '후원하기', 'timeStart': '시작 시간',
'system': '시스템', 'timeEnd': '종료 시간',
'dark': '어두운', 'support': '후원하기',
'light': '밝은', 'system': '시스템',
'license': '라이선스', 'dark': '어두운',
'widget': '위젯', 'light': '밝은',
'widgetBackground': '위젯 배경', 'license': '라이선스',
'widgetText': '위젯 텍스트', 'widget': '위젯',
'dewpoint': '이슬점', 'widgetBackground': '위젯 배경',
'shortwaveRadiation': '단파 복사', 'widgetText': '위젯 텍스트',
'W/m2': 'W/m2', 'dewpoint': '이슬점',
'roundDegree': '온도 반올림', 'shortwaveRadiation': '단파 복사',
'settings_full': '설정', 'W/m2': 'W/m2',
'cities': '도시', 'roundDegree': '온도 반올림',
'searchMethod': '검색 또는 지리적 위치를 사용하세요', 'settings_full': '설정',
'done': '완료', 'cities': '도시',
'groups': '우리 그룹', 'searchMethod': '검색 또는 지리적 위치를 사용하세요',
'openMeteo': 'Open-Meteo의 데이터 (CC-BY 4.0)', 'done': '완료',
'hourlyVariables': '시간별 날씨 변수', 'groups': '우리 그룹',
'dailyVariables': '일별 날씨 변수', 'openMeteo': 'Open-Meteo의 데이터 (CC-BY 4.0)',
}; 'hourlyVariables': '시간별 날씨 변수',
'dailyVariables': '일별 날씨 변수',
'largeElement': '큰 날씨 표시',
'map': '지도',
'clearCacheStore': '캐시 지우기',
'deletedCacheStore': '캐시 삭제 중',
'deletedCacheStoreQuery': '캐시를 정말로 지우시겠습니까?',
'addWidget': '위젯 추가',
'hideMap': '지도를 숨기기',
};
} }

269
lib/translation/nl_nl.dart Normal file → Executable file
View file

@ -1,134 +1,141 @@
class NlNl { class NlNl {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Beginnen', 'start': 'Beginnen',
'description': 'description':
'Weer-applicatie met een actuele prognose voor elk uur, dag en week voor elke locatie.', 'Weer-applicatie met een actuele prognose voor elk uur, dag en week voor elke locatie.',
'name': 'Weer', 'name': 'Weer',
'name2': 'Handig Ontwerp', 'name2': 'Handig Ontwerp',
'name3': 'Neem contact met ons op', 'name3': 'Neem contact met ons op',
'description2': 'description2':
'Alle navigatie is ontworpen om zo gemakkelijk en snel mogelijk met de applicatie te kunnen communiceren.', 'Alle navigatie is ontworpen om zo gemakkelijk en snel mogelijk met de applicatie te kunnen communiceren.',
'description3': 'description3':
'Als u problemen ondervindt, neem dan contact met ons op via e-mail of in de recensies van de applicatie.', 'Als u problemen ondervindt, neem dan contact met ons op via e-mail of in de recensies van de applicatie.',
'next': 'Volgende', 'next': 'Volgende',
'search': 'Zoeken...', 'search': 'Zoeken...',
'loading': 'Laden...', 'loading': 'Laden...',
'searchCity': 'Vind jouw stad', 'searchCity': 'Vind jouw stad',
'humidity': 'Luchtvochtigheid', 'humidity': 'Luchtvochtigheid',
'wind': 'Wind', 'wind': 'Wind',
'visibility': 'Zichtbaarheid', 'visibility': 'Zichtbaarheid',
'feels': 'Voelt', 'feels': 'Voelt',
'evaporation': 'Verdamping', 'evaporation': 'Verdamping',
'precipitation': 'Neerslag', 'precipitation': 'Neerslag',
'direction': 'Richting', 'direction': 'Richting',
'pressure': 'Druk', 'pressure': 'Druk',
'rain': 'Regen', 'rain': 'Regen',
'clear_sky': 'Heldere lucht', 'clear_sky': 'Heldere lucht',
'cloudy': 'Bewolkt', 'cloudy': 'Bewolkt',
'overcast': 'Betrokken', 'overcast': 'Betrokken',
'fog': 'Mist', 'fog': 'Mist',
'drizzle': 'Motregen', 'drizzle': 'Motregen',
'drizzling_rain': 'Ijskoude motregen', 'drizzling_rain': 'Ijskoude motregen',
'freezing_rain': 'Ijskoude regen', 'freezing_rain': 'Ijskoude regen',
'heavy_rains': 'Regendouche', 'heavy_rains': 'Regendouche',
'snow': 'Sneeuw', 'snow': 'Sneeuw',
'thunderstorm': 'Onweersbui', 'thunderstorm': 'Onweersbui',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'inch', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'inch',
'settings': 'Instellingen.', 'mm': 'mm',
'no_inter': 'Geen Internet', 'hPa': 'hPa',
'on_inter': 'settings': 'Instellingen.',
'Schakel Internet in om meteorologische gegevens te ontvangen.', 'no_inter': 'Geen Internet',
'location': 'Locatie', 'on_inter': 'Schakel Internet in om meteorologische gegevens te ontvangen.',
'no_location': 'location': 'Locatie',
'Schakel de locatiedienst in om weer gegevens voor de huidige locatie te ontvangen.', 'no_location':
'theme': 'Thema', 'Schakel de locatiedienst in om weer gegevens voor de huidige locatie te ontvangen.',
'low': 'Laag', 'theme': 'Thema',
'high': 'Hoog', 'low': 'Laag',
'normal': 'Normaal', 'high': 'Hoog',
'lat': 'Breedtegraad', 'normal': 'Normaal',
'lon': 'Lengtegraad', 'lat': 'Breedtegraad',
'create': 'Creëer', 'lon': 'Lengtegraad',
'city': 'Stad', 'create': 'Creëer',
'district': 'District', 'city': 'Stad',
'noWeatherCard': 'Voeg een stad toe', 'district': 'District',
'deletedCardWeather': 'Verwijder een city', 'noWeatherCard': 'Voeg een stad toe',
'deletedCardWeatherQuery': 'deletedCardWeather': 'Verwijder een city',
'Weet je zeker dat je de stad wilt verwijderen?', 'deletedCardWeatherQuery': 'Weet je zeker dat je de stad wilt verwijderen?',
'delete': 'Verwijder', 'delete': 'Verwijder',
'cancel': 'Annuleer', 'cancel': 'Annuleer',
'time': 'Tijd in de stad', 'time': 'Tijd in de stad',
'validateName': 'Vul de naam in', 'validateName': 'Vul de naam in',
'measurements': 'Meetsysteem', 'measurements': 'Meetsysteem',
'degrees': 'Graden', 'degrees': 'Graden',
'celsius': 'Celsius', 'celsius': 'Celsius',
'fahrenheit': 'Fahrenheit', 'fahrenheit': 'Fahrenheit',
'imperial': 'Imperiaal', 'imperial': 'Imperiaal',
'metric': 'Metrisch', 'metric': 'Metrisch',
'validateValue': 'Vul een waarde in', 'validateValue': 'Vul een waarde in',
'validateNumber': 'Vul een geldig nummer in', 'validateNumber': 'Vul een geldig nummer in',
'validate90': 'Waarde moet tussen -90 and 90 zijn', 'validate90': 'Waarde moet tussen -90 and 90 zijn',
'validate180': 'Waarde moet tussen -180 and 180 zijn', 'validate180': 'Waarde moet tussen -180 and 180 zijn',
'notifications': 'Notificaties', 'notifications': 'Notificaties',
'sunrise': 'Zonsopkomst', 'sunrise': 'Zonsopkomst',
'sunset': 'Zonsondergang', 'sunset': 'Zonsondergang',
'timeformat': 'Tijdnotatie', 'timeformat': 'Tijdnotatie',
'12': '12-uur', '12': '12-uur',
'24': '24-uur', '24': '24-uur',
'cloudcover': 'Bewolking', 'cloudcover': 'Bewolking',
'uvIndex': 'UV-index', 'uvIndex': 'UV-index',
'materialColor': 'Dynamische Kleuren', 'materialColor': 'Dynamische Kleuren',
'uvLow': 'Laag', 'uvLow': 'Laag',
'uvAverage': 'Matig', 'uvAverage': 'Matig',
'uvHigh': 'Hoog', 'uvHigh': 'Hoog',
'uvVeryHigh': 'Erg hoog', 'uvVeryHigh': 'Erg hoog',
'uvExtreme': 'Extreem', 'uvExtreme': 'Extreem',
'weatherMore': '12-daagse weersverwachting', 'weatherMore': '12-daagse weersverwachting',
'windgusts': 'Windstoten', 'windgusts': 'Windstoten',
'north': 'Noord', 'north': 'Noord',
'northeast': 'Noordoost', 'northeast': 'Noordoost',
'east': 'Oost', 'east': 'Oost',
'southeast': 'Zuidoost', 'southeast': 'Zuidoost',
'south': 'Zuid', 'south': 'Zuid',
'southwest': 'Zuidwest', 'southwest': 'Zuidwest',
'west': 'West', 'west': 'West',
'northwest': 'Noordwest', 'northwest': 'Noordwest',
'project': 'Project op', 'project': 'Project op',
'version': 'Applicatieversie', 'version': 'Applicatieversie',
'precipitationProbability': 'Kans op neerslag', 'precipitationProbability': 'Kans op neerslag',
'apparentTemperatureMin': 'Minimum schijnbare temperatuur', 'apparentTemperatureMin': 'Minimum schijnbare temperatuur',
'apparentTemperatureMax': 'Maximale schijnbare temperatuur', 'apparentTemperatureMax': 'Maximale schijnbare temperatuur',
'amoledTheme': 'AMOLED-thema', 'amoledTheme': 'AMOLED-thema',
'appearance': 'Uiterlijk', 'appearance': 'Uiterlijk',
'functions': 'Functies', 'functions': 'Functies',
'data': 'Gegevens', 'data': 'Gegevens',
'language': 'Taal', 'language': 'Taal',
'timeRange': 'Frequentie (in uren)', 'timeRange': 'Frequentie (in uren)',
'timeStart': 'Begintijd', 'timeStart': 'Begintijd',
'timeEnd': 'Eindtijd', 'timeEnd': 'Eindtijd',
'support': 'Ondersteuning', 'support': 'Ondersteuning',
'system': 'Systeem', 'system': 'Systeem',
'dark': 'Donker', 'dark': 'Donker',
'light': 'Licht', 'light': 'Licht',
'license': 'Licenties', 'license': 'Licenties',
'widget': 'Widget', 'widget': 'Widget',
'widgetBackground': 'Widget-achtergrond', 'widgetBackground': 'Widget-achtergrond',
'widgetText': 'Tekst van widget', 'widgetText': 'Tekst van widget',
'dewpoint': 'Dauwpunt', 'dewpoint': 'Dauwpunt',
'shortwaveRadiation': 'Korte golfstraling', 'shortwaveRadiation': 'Korte golfstraling',
'roundDegree': 'Rond graden af', 'roundDegree': 'Rond graden af',
'settings_full': 'Instellingen', 'settings_full': 'Instellingen',
'cities': 'Steden', 'cities': 'Steden',
'searchMethod': 'Gebruik zoeken of geolocatie', 'searchMethod': 'Gebruik zoeken of geolocatie',
'done': 'Klaar', 'done': 'Klaar',
'groups': 'Onze groepen', 'groups': 'Onze groepen',
'openMeteo': 'Gegevens van Open-Meteo (CC-BY 4.0)', 'openMeteo': 'Gegevens van Open-Meteo (CC-BY 4.0)',
'hourlyVariables': 'Uurlijkse weervariabelen', 'hourlyVariables': 'Uurlijkse weervariabelen',
'dailyVariables': 'Dagelijkse weervariabelen', 'dailyVariables': 'Dagelijkse weervariabelen',
}; 'largeElement': 'Groot weerbericht weergeven',
'map': 'Kaart',
'clearCacheStore': 'Cache wissen',
'deletedCacheStore': 'Cache wissen',
'deletedCacheStoreQuery': 'Weet je zeker dat je de cache wilt wissen?',
'addWidget': 'Widget toevoegen',
'hideMap': 'Kaart verbergen',
};
} }

267
lib/translation/pl_pl.dart Normal file → Executable file
View file

@ -1,132 +1,141 @@
class PlPl { class PlPl {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Rozpocznij', 'start': 'Rozpocznij',
'description': 'description':
'Aplikacja pogodowa z aktualną prognozą na każdą godzinę, dzień i tydzień dla dowolnego miejsca.', 'Aplikacja pogodowa z aktualną prognozą na każdą godzinę, dzień i tydzień dla dowolnego miejsca.',
'name': 'Pogoda', 'name': 'Pogoda',
'name2': 'Wygodny design', 'name2': 'Wygodny design',
'name3': 'Skontaktuj się z nami', 'name3': 'Skontaktuj się z nami',
'description2': 'description2':
'Cała nawigacja jest zaprojektowana tak, aby można było jak najwygodniej i najszybciej współdziałać z aplikacją.', 'Cała nawigacja jest zaprojektowana tak, aby można było jak najwygodniej i najszybciej współdziałać z aplikacją.',
'description3': 'description3':
'Jeśli napotkasz jakiekolwiek problemy, skontaktuj się z nami drogą e-mailową lub w recenzjach aplikacji.', 'Jeśli napotkasz jakiekolwiek problemy, skontaktuj się z nami drogą e-mailową lub w recenzjach aplikacji.',
'next': 'Dalej', 'next': 'Dalej',
'search': 'Szukaj...', 'search': 'Szukaj...',
'loading': 'Ładowanie...', 'loading': 'Ładowanie...',
'searchCity': 'Znajdź swoje miasto', 'searchCity': 'Znajdź swoje miasto',
'humidity': 'Wilgoć', 'humidity': 'Wilgoć',
'wind': 'Wiatr', 'wind': 'Wiatr',
'visibility': 'Widoczność', 'visibility': 'Widoczność',
'feels': 'Odczuwalna', 'feels': 'Odczuwalna',
'evaporation': 'Parowanie', 'evaporation': 'Parowanie',
'precipitation': 'Opad atmosferyczny', 'precipitation': 'Opad atmosferyczny',
'direction': 'Kierunek', 'direction': 'Kierunek',
'pressure': 'Ciśnienie', 'pressure': 'Ciśnienie',
'rain': 'Deszcz', 'rain': 'Deszcz',
'clear_sky': 'Czyste niebo', 'clear_sky': 'Czyste niebo',
'cloudy': 'Pochmurno', 'cloudy': 'Pochmurno',
'overcast': 'Pochmurnie', 'overcast': 'Pochmurnie',
'fog': 'Mgła', 'fog': 'Mgła',
'drizzle': 'Mżawka', 'drizzle': 'Mżawka',
'drizzling_rain': 'Mroźna Mżawka', 'drizzling_rain': 'Mroźna Mżawka',
'freezing_rain': 'Mroźny deszcz', 'freezing_rain': 'Mroźny deszcz',
'heavy_rains': 'Przelotne opady deszczu', 'heavy_rains': 'Przelotne opady deszczu',
'snow': 'Śnieg', 'snow': 'Śnieg',
'thunderstorm': 'Burza z piorunami', 'thunderstorm': 'Burza z piorunami',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'inch', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'inch',
'settings': 'Ustaw.', 'mm': 'mm',
'no_inter': 'Brak internetu', 'hPa': 'hPa',
'on_inter': 'Włącz Internet, aby uzyskać dane meteorologiczne.', 'settings': 'Ustaw.',
'location': 'Lokalizacja', 'no_inter': 'Brak internetu',
'no_location': 'on_inter': 'Włącz Internet, aby uzyskać dane meteorologiczne.',
'Włącz usługę lokalizacyjną, aby uzyskać dane pogodowe dla bieżącej lokalizacji.', 'location': 'Lokalizacja',
'theme': 'Motyw', 'no_location':
'low': 'Niski', 'Włącz usługę lokalizacyjną, aby uzyskać dane pogodowe dla bieżącej lokalizacji.',
'high': 'Wysoki', 'theme': 'Motyw',
'normal': 'Normalny', 'low': 'Niski',
'lat': 'Latitude', 'high': 'Wysoki',
'lon': 'Longitude', 'normal': 'Normalny',
'create': 'Stwórz', 'lat': 'Latitude',
'city': 'Miasto', 'lon': 'Longitude',
'district': 'Dzielnica', 'create': 'Stwórz',
'noWeatherCard': 'Dodaj miasto', 'city': 'Miasto',
'deletedCardWeather': 'Usuwanie miasta', 'district': 'Dzielnica',
'deletedCardWeatherQuery': 'Czy na pewno chcesz usunąć miasto?', 'noWeatherCard': 'Dodaj miasto',
'delete': 'Usuń', 'deletedCardWeather': 'Usuwanie miasta',
'cancel': 'Anuluj', 'deletedCardWeatherQuery': 'Czy na pewno chcesz usunąć miasto?',
'time': 'Czas w mieście', 'delete': 'Usuń',
'validateName': 'Wprowadź nazwę', 'cancel': 'Anuluj',
'measurements': 'System środków', 'time': 'Czas w mieście',
'degrees': 'Stopni', 'validateName': 'Wprowadź nazwę',
'celsius': 'Celsjusz', 'measurements': 'System środków',
'fahrenheit': 'Fahrenheita', 'degrees': 'Stopni',
'imperial': 'Imperial', 'celsius': 'Celsjusz',
'metric': 'Metric', 'fahrenheit': 'Fahrenheita',
'validateValue': 'Proszę wprowadzić wartość', 'imperial': 'Imperial',
'validateNumber': 'Proszę wprowadzić poprawny numer', 'metric': 'Metric',
'validate90': 'Wartość musi mieścić się w zakresie od -90 do 90', 'validateValue': 'Proszę wprowadzić wartość',
'validate180': 'Wartość musi mieścić się w przedziale od -180 do 180', 'validateNumber': 'Proszę wprowadzić poprawny numer',
'notifications': 'Powiadomienia', 'validate90': 'Wartość musi mieścić się w zakresie od -90 do 90',
'sunrise': 'Wschód słońca', 'validate180': 'Wartość musi mieścić się w przedziale od -180 do 180',
'sunset': 'Zachód słońca', 'notifications': 'Powiadomienia',
'timeformat': 'Format czasu', 'sunrise': 'Wschód słońca',
'12': '12-hour', 'sunset': 'Zachód słońca',
'24': '24-hour', 'timeformat': 'Format czasu',
'cloudcover': 'Zachmurzenie', '12': '12-hour',
'uvIndex': 'Indeks UV', '24': '24-hour',
'materialColor': 'Dynamiczne kolory', 'cloudcover': 'Zachmurzenie',
'uvLow': 'Niski', 'uvIndex': 'Indeks UV',
'uvAverage': 'Umiarkowany', 'materialColor': 'Dynamiczne kolory',
'uvHigh': 'Wysoki', 'uvLow': 'Niski',
'uvVeryHigh': 'Bardzo wysoki', 'uvAverage': 'Umiarkowany',
'uvExtreme': 'Extremalny', 'uvHigh': 'Wysoki',
'weatherMore': 'Prognoza pogody na 12 dni', 'uvVeryHigh': 'Bardzo wysoki',
'windgusts': 'Porywy wiatru', 'uvExtreme': 'Extremalny',
'north': 'Północ', 'weatherMore': 'Prognoza pogody na 12 dni',
'northeast': 'Północny wschód', 'windgusts': 'Porywy wiatru',
'east': 'Wschód', 'north': 'Północ',
'southeast': 'południowy wschód', 'northeast': 'Północny wschód',
'south': 'Południe', 'east': 'Wschód',
'southwest': 'Południowy zachód', 'southeast': 'południowy wschód',
'west': 'Zachód', 'south': 'Południe',
'northwest': 'Północny zachód', 'southwest': 'Południowy zachód',
'project': 'Project on', 'west': 'Zachód',
'version': 'Wersja aplikacji', 'northwest': 'Północny zachód',
'precipitationProbability': 'Prawdopodobieństwo opadów', 'project': 'Project on',
'apparentTemperatureMin': 'Minimalna temperatura pozorna', 'version': 'Wersja aplikacji',
'apparentTemperatureMax': 'Maksymalna pozorna temperatura', 'precipitationProbability': 'Prawdopodobieństwo opadów',
'amoledTheme': 'AMOLED-theme', 'apparentTemperatureMin': 'Minimalna temperatura pozorna',
'appearance': 'Wygląd', 'apparentTemperatureMax': 'Maksymalna pozorna temperatura',
'functions': 'Funkcje', 'amoledTheme': 'AMOLED-theme',
'data': 'Data', 'appearance': 'Wygląd',
'language': 'Język', 'functions': 'Funkcje',
'timeRange': 'Częstotliwość (w godzinach)', 'data': 'Data',
'timeStart': 'Czas rozpoczęcia', 'language': 'Język',
'timeEnd': 'Czas zakończenia', 'timeRange': 'Częstotliwość (w godzinach)',
'support': 'Wsparcie', 'timeStart': 'Czas rozpoczęcia',
'system': 'System', 'timeEnd': 'Czas zakończenia',
'dark': 'Ciemny', 'support': 'Wsparcie',
'light': 'Jasny', 'system': 'System',
'license': 'Licencje', 'dark': 'Ciemny',
'widget': 'Widget', 'light': 'Jasny',
'widgetBackground': 'Tło widżetu', 'license': 'Licencje',
'widgetText': 'Tekst widżetu', 'widget': 'Widget',
'dewpoint': 'Punkt rosy', 'widgetBackground': 'Tło widżetu',
'shortwaveRadiation': 'Promieniowanie krótkofalowe', 'widgetText': 'Tekst widżetu',
'roundDegree': 'Zaokrąglaj stopnie', 'dewpoint': 'Punkt rosy',
'settings_full': 'Ustawienia', 'shortwaveRadiation': 'Promieniowanie krótkofalowe',
'cities': 'Miasta', 'roundDegree': 'Zaokrąglaj stopnie',
'searchMethod': 'Użyj wyszukiwania lub geolokalizacji', 'settings_full': 'Ustawienia',
'done': 'Gotowe', 'cities': 'Miasta',
'groups': 'Nasze grupy', 'searchMethod': 'Użyj wyszukiwania lub geolokalizacji',
'openMeteo': 'Dane z Open-Meteo (CC-BY 4.0)', 'done': 'Gotowe',
'hourlyVariables': 'Godzinowe zmienne pogodowe', 'groups': 'Nasze grupy',
'dailyVariables': 'Dzienne zmienne pogodowe', 'openMeteo': 'Dane z Open-Meteo (CC-BY 4.0)',
}; 'hourlyVariables': 'Godzinowe zmienne pogodowe',
'dailyVariables': 'Dzienne zmienne pogodowe',
'largeElement': 'Duże wyświetlanie pogody',
'map': 'Mapa',
'clearCacheStore': 'Wyczyść pamięć podręczną',
'deletedCacheStore': 'Czyszczenie pamięci podręcznej',
'deletedCacheStoreQuery': 'Czy na pewno chcesz wyczyścić pamięć podręczną?',
'addWidget': 'Dodaj widget',
'hideMap': 'Ukryj mapę',
};
} }

269
lib/translation/pt_br.dart Normal file → Executable file
View file

@ -1,133 +1,142 @@
class PtBr { class PtBr {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Iniciar', 'start': 'Iniciar',
'description': 'description':
'Aplicativo de previsão do tempo com previsão atualizada para cada hora, dia e semana para qualquer local.', 'Aplicativo de previsão do tempo com previsão atualizada para cada hora, dia e semana para qualquer local.',
'name': 'Clima', 'name': 'Clima',
'name2': 'Design Conveniente', 'name2': 'Design Conveniente',
'name3': 'Entre em Contato Conosco', 'name3': 'Entre em Contato Conosco',
'description2': 'description2':
'Toda a navegação é projetada para interagir com o aplicativo da maneira mais conveniente e rápida possível.', 'Toda a navegação é projetada para interagir com o aplicativo da maneira mais conveniente e rápida possível.',
'description3': 'description3':
'Se você encontrar algum problema, entre em contato conosco por e-mail ou nas avaliações do aplicativo.', 'Se você encontrar algum problema, entre em contato conosco por e-mail ou nas avaliações do aplicativo.',
'next': 'Próximo', 'next': 'Próximo',
'search': 'Pesquisar...', 'search': 'Pesquisar...',
'loading': 'Carregando...', 'loading': 'Carregando...',
'searchCity': 'Procure sua cidade', 'searchCity': 'Procure sua cidade',
'humidity': 'Umidade', 'humidity': 'Umidade',
'wind': 'Vento', 'wind': 'Vento',
'visibility': 'Visibilidade', 'visibility': 'Visibilidade',
'feels': 'Sensação', 'feels': 'Sensação',
'evaporation': 'Evapotranspirações', 'evaporation': 'Evapotranspirações',
'precipitation': 'Precipitação', 'precipitation': 'Precipitação',
'direction': 'Direção', 'direction': 'Direção',
'pressure': 'Pressão', 'pressure': 'Pressão',
'rain': 'Chuva', 'rain': 'Chuva',
'clear_sky': 'Céu limpo', 'clear_sky': 'Céu limpo',
'cloudy': 'Nublado', 'cloudy': 'Nublado',
'overcast': 'Encoberto', 'overcast': 'Encoberto',
'fog': 'Névoa', 'fog': 'Névoa',
'drizzle': 'Garoa', 'drizzle': 'Garoa',
'drizzling_rain': 'Chuva fraca', 'drizzling_rain': 'Chuva fraca',
'freezing_rain': 'Chuva congelante', 'freezing_rain': 'Chuva congelante',
'heavy_rains': 'Chuva pesada', 'heavy_rains': 'Chuva pesada',
'snow': 'Neve', 'snow': 'Neve',
'thunderstorm': 'Tempestade', 'thunderstorm': 'Tempestade',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'inch', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'inch',
'settings': 'Configurações.', 'mm': 'mm',
'no_inter': 'Sem conexão', 'hPa': 'hPa',
'on_inter': 'Conecte-se a internet para atualizar os dados de clima.', 'settings': 'Configurações.',
'location': 'Localização', 'no_inter': 'Sem conexão',
'no_location': 'on_inter': 'Conecte-se a internet para atualizar os dados de clima.',
'Habilite a localização para obter dados de clima do local atual.', 'location': 'Localização',
'theme': 'Tema', 'no_location':
'low': 'Baixo', 'Habilite a localização para obter dados de clima do local atual.',
'high': 'Alto', 'theme': 'Tema',
'normal': 'Normal', 'low': 'Baixo',
'lat': 'Latitude', 'high': 'Alto',
'lon': 'Longitude', 'normal': 'Normal',
'create': 'Criar', 'lat': 'Latitude',
'city': 'Cidade', 'lon': 'Longitude',
'district': 'Distrito', 'create': 'Criar',
'noWeatherCard': 'Adicione uma cidade', 'city': 'Cidade',
'deletedCardWeather': 'Deletando a cidade', 'district': 'Distrito',
'deletedCardWeatherQuery': 'noWeatherCard': 'Adicione uma cidade',
'Você tem certeza que deseja remover esta cidade?', 'deletedCardWeather': 'Deletando a cidade',
'delete': 'Deletar', 'deletedCardWeatherQuery':
'cancel': 'Cancelar', 'Você tem certeza que deseja remover esta cidade?',
'time': 'Clima na cidade', 'delete': 'Deletar',
'validateName': 'Por favor escreva um nome', 'cancel': 'Cancelar',
'measurements': 'Sistema de medidas', 'time': 'Clima na cidade',
'degrees': 'Graus', 'validateName': 'Por favor escreva um nome',
'celsius': 'Celsius', 'measurements': 'Sistema de medidas',
'fahrenheit': 'Fahrenheit', 'degrees': 'Graus',
'imperial': 'Imperial', 'celsius': 'Celsius',
'metric': 'Métrico', 'fahrenheit': 'Fahrenheit',
'validateValue': 'Por favor escreva um valor', 'imperial': 'Imperial',
'validateNumber': 'Por favor escreva um número válido', 'metric': 'Métrico',
'validate90': 'Valor deve estar entre -90 and 90', 'validateValue': 'Por favor escreva um valor',
'validate180': 'Valor deve estar entre -180 and 180', 'validateNumber': 'Por favor escreva um número válido',
'notifications': 'Notificações', 'validate90': 'Valor deve estar entre -90 and 90',
'sunrise': 'Nascer do sol', 'validate180': 'Valor deve estar entre -180 and 180',
'sunset': 'Pôr do sol', 'notifications': 'Notificações',
'timeformat': 'Formato de hora', 'sunrise': 'Nascer do sol',
'12': '12 horas', 'sunset': 'Pôr do sol',
'24': '24 horas', 'timeformat': 'Formato de hora',
'cloudcover': 'Сobertura de nuvens', '12': '12 horas',
'uvIndex': 'UV-índice', '24': '24 horas',
'materialColor': 'Cores Dinâmicas', 'cloudcover': 'Сobertura de nuvens',
'uvLow': 'Baixo', 'uvIndex': 'UV-índice',
'uvAverage': 'Moderado', 'materialColor': 'Cores Dinâmicas',
'uvHigh': 'Alto', 'uvLow': 'Baixo',
'uvVeryHigh': 'Muito alto', 'uvAverage': 'Moderado',
'uvExtreme': 'Extremo', 'uvHigh': 'Alto',
'weatherMore': 'Previsão do tempo para 12 dias', 'uvVeryHigh': 'Muito alto',
'windgusts': 'Rajadas', 'uvExtreme': 'Extremo',
'north': 'Norte', 'weatherMore': 'Previsão do tempo para 12 dias',
'northeast': 'Nordeste', 'windgusts': 'Rajadas',
'east': 'Leste', 'north': 'Norte',
'southeast': 'Sudeste', 'northeast': 'Nordeste',
'south': 'Sul', 'east': 'Leste',
'southwest': 'Sudoeste', 'southeast': 'Sudeste',
'west': 'Oeste', 'south': 'Sul',
'northwest': 'Noroeste', 'southwest': 'Sudoeste',
'project': 'Projeto em', 'west': 'Oeste',
'version': 'Versão do aplicativo', 'northwest': 'Noroeste',
'precipitationProbability': 'Probabilidade de precipitação', 'project': 'Projeto em',
'apparentTemperatureMin': 'Temperatura aparente mínima', 'version': 'Versão do aplicativo',
'apparentTemperatureMax': 'Temperatura aparente máxima', 'precipitationProbability': 'Probabilidade de precipitação',
'amoledTheme': 'AMOLED-tema', 'apparentTemperatureMin': 'Temperatura aparente mínima',
'appearance': 'Aparência', 'apparentTemperatureMax': 'Temperatura aparente máxima',
'functions': 'Funções', 'amoledTheme': 'AMOLED-tema',
'data': 'Dados', 'appearance': 'Aparência',
'language': 'Idioma', 'functions': 'Funções',
'timeRange': 'Frequência (em horas)', 'data': 'Dados',
'timeStart': 'Hora de início', 'language': 'Idioma',
'timeEnd': 'Hora de término', 'timeRange': 'Frequência (em horas)',
'support': 'Suporte', 'timeStart': 'Hora de início',
'system': 'Sistema', 'timeEnd': 'Hora de término',
'dark': 'Escuro', 'support': 'Suporte',
'light': 'Claro', 'system': 'Sistema',
'license': 'Licenças', 'dark': 'Escuro',
'widget': 'Widget', 'light': 'Claro',
'widgetBackground': 'Fundo do widget', 'license': 'Licenças',
'widgetText': 'Texto do widget', 'widget': 'Widget',
'dewpoint': 'Ponto de orvalho', 'widgetBackground': 'Fundo do widget',
'shortwaveRadiation': 'Radiação de ondas curtas', 'widgetText': 'Texto do widget',
'roundDegree': 'Arredondar graus', 'dewpoint': 'Ponto de orvalho',
'settings_full': 'Configurações', 'shortwaveRadiation': 'Radiação de ondas curtas',
'cities': 'Cidades', 'roundDegree': 'Arredondar graus',
'searchMethod': 'Use a pesquisa ou a geolocalização', 'settings_full': 'Configurações',
'done': 'Concluído', 'cities': 'Cidades',
'groups': 'Nossos grupos', 'searchMethod': 'Use a pesquisa ou a geolocalização',
'openMeteo': 'Dados do Open-Meteo (CC-BY 4.0)', 'done': 'Concluído',
'hourlyVariables': 'Variáveis meteorológicas horárias', 'groups': 'Nossos grupos',
'dailyVariables': 'Variáveis meteorológicas diárias', 'openMeteo': 'Dados do Open-Meteo (CC-BY 4.0)',
}; 'hourlyVariables': 'Variáveis meteorológicas horárias',
'dailyVariables': 'Variáveis meteorológicas diárias',
'largeElement': 'Exibição grande do clima',
'map': 'Mapa',
'clearCacheStore': 'Limpar cache',
'deletedCacheStore': 'Limpando cache',
'deletedCacheStoreQuery': 'Tem certeza de que deseja limpar o cache?',
'addWidget': 'Adicionar widget',
'hideMap': 'Ocultar mapa',
};
} }

267
lib/translation/ro_ro.dart Normal file → Executable file
View file

@ -1,132 +1,141 @@
class RoRo { class RoRo {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Începe', 'start': 'Începe',
'description': 'description':
'Aplicație meteo cu o prognoză actualizată pentru fiecare oră, zi și săptămână pentru orice loc.', 'Aplicație meteo cu o prognoză actualizată pentru fiecare oră, zi și săptămână pentru orice loc.',
'name': 'Vremea', 'name': 'Vremea',
'name2': 'Design Convenabil', 'name2': 'Design Convenabil',
'name3': 'Contactați-ne', 'name3': 'Contactați-ne',
'description2': 'description2':
'Toată navigarea este concepută pentru a interacționa cu aplicația în cel mai comod și rapid mod posibil.', 'Toată navigarea este concepută pentru a interacționa cu aplicația în cel mai comod și rapid mod posibil.',
'description3': 'description3':
'Dacă întâmpinați orice probleme, vă rugăm să ne contactați prin e-mail sau în recenziile aplicației.', 'Dacă întâmpinați orice probleme, vă rugăm să ne contactați prin e-mail sau în recenziile aplicației.',
'next': 'Următorul', 'next': 'Următorul',
'search': 'Caută...', 'search': 'Caută...',
'loading': 'Încărcare...', 'loading': 'Încărcare...',
'searchCity': 'Caută oraș', 'searchCity': 'Caută oraș',
'humidity': 'Umiditate', 'humidity': 'Umiditate',
'wind': 'Vânt', 'wind': 'Vânt',
'visibility': 'Vizibilitate', 'visibility': 'Vizibilitate',
'feels': 'Se simt', 'feels': 'Se simt',
'evaporation': 'Evapotranspirație', 'evaporation': 'Evapotranspirație',
'precipitation': 'Precipitații', 'precipitation': 'Precipitații',
'direction': 'Direcție', 'direction': 'Direcție',
'pressure': 'Presiune', 'pressure': 'Presiune',
'rain': 'Ploaie', 'rain': 'Ploaie',
'clear_sky': 'Senin', 'clear_sky': 'Senin',
'cloudy': 'Înnorat', 'cloudy': 'Înnorat',
'overcast': 'Cer acoperit de nori', 'overcast': 'Cer acoperit de nori',
'fog': 'Ceață', 'fog': 'Ceață',
'drizzle': 'Burniță', 'drizzle': 'Burniță',
'drizzling_rain': 'Burniță înghețată', 'drizzling_rain': 'Burniță înghețată',
'freezing_rain': 'Ploaie înghețată', 'freezing_rain': 'Ploaie înghețată',
'heavy_rains': 'Ploaie torențială', 'heavy_rains': 'Ploaie torențială',
'snow': 'Ninsoare', 'snow': 'Ninsoare',
'thunderstorm': 'Furtună', 'thunderstorm': 'Furtună',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'inch', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'inch',
'settings': 'Set.', 'mm': 'mm',
'no_inter': 'Fără Internet', 'hPa': 'hPa',
'on_inter': 'Pornește Internetul pentru a obține date meteorologice.', 'settings': 'Set.',
'location': 'Locație', 'no_inter': 'Fără Internet',
'no_location': 'on_inter': 'Pornește Internetul pentru a obține date meteorologice.',
'Activează serviciul de localizare pentru a obține date meteorologice pentru locația curentă.', 'location': 'Locație',
'theme': 'Temă', 'no_location':
'low': 'Scăzut', 'Activează serviciul de localizare pentru a obține date meteorologice pentru locația curentă.',
'high': 'Ridicat', 'theme': 'Temă',
'normal': 'Normal', 'low': 'Scăzut',
'lat': 'Latitudine', 'high': 'Ridicat',
'lon': 'Longitudine', 'normal': 'Normal',
'create': 'Crează', 'lat': 'Latitudine',
'city': 'Oraș', 'lon': 'Longitudine',
'district': 'District', 'create': 'Crează',
'noWeatherCard': 'Adaugă un oraș', 'city': 'Oraș',
'deletedCardWeather': 'Ștergerea orașului', 'district': 'District',
'deletedCardWeatherQuery': 'Ești sigur că vrei să ștergi orașul?', 'noWeatherCard': 'Adaugă un oraș',
'delete': 'Șterge', 'deletedCardWeather': 'Ștergerea orașului',
'cancel': 'Anulează', 'deletedCardWeatherQuery': 'Ești sigur că vrei să ștergi orașul?',
'time': 'Ora în oraș', 'delete': 'Șterge',
'validateName': 'Introdu numele', 'cancel': 'Anulează',
'measurements': 'Sistemul de măsuri', 'time': 'Ora în oraș',
'degrees': 'Grade', 'validateName': 'Introdu numele',
'celsius': 'Celsius', 'measurements': 'Sistemul de măsuri',
'fahrenheit': 'Fahrenheit', 'degrees': 'Grade',
'imperial': 'Imperial', 'celsius': 'Celsius',
'metric': 'Metric', 'fahrenheit': 'Fahrenheit',
'validateValue': 'Introdu o valoare', 'imperial': 'Imperial',
'validateNumber': 'Introdu un număr valid', 'metric': 'Metric',
'validate90': 'Valoarea trebuie să fie între -90 și 90', 'validateValue': 'Introdu o valoare',
'validate180': 'Valoarea trebuie să fie între -180 și 180', 'validateNumber': 'Introdu un număr valid',
'notifications': 'Notificări', 'validate90': 'Valoarea trebuie să fie între -90 și 90',
'sunrise': 'Răsărit', 'validate180': 'Valoarea trebuie să fie între -180 și 180',
'sunset': 'Apus', 'notifications': 'Notificări',
'timeformat': 'Format orar', 'sunrise': 'Răsărit',
'12': '12 ore', 'sunset': 'Apus',
'24': '24 ore', 'timeformat': 'Format orar',
'cloudcover': 'Acoperirea norilor', '12': '12 ore',
'uvIndex': 'Index UV', '24': '24 ore',
'materialColor': 'Culori dinamice (Android 12+)', 'cloudcover': 'Acoperirea norilor',
'uvLow': 'Scăzut', 'uvIndex': 'Index UV',
'uvAverage': 'Moderat', 'materialColor': 'Culori dinamice (Android 12+)',
'uvHigh': 'Ridicat', 'uvLow': 'Scăzut',
'uvVeryHigh': 'Foarte ridicat', 'uvAverage': 'Moderat',
'uvExtreme': 'Extrem', 'uvHigh': 'Ridicat',
'weatherMore': 'Prognoza pe 12 zile', 'uvVeryHigh': 'Foarte ridicat',
'windgusts': 'Rafale de vânt', 'uvExtreme': 'Extrem',
'north': 'Nord', 'weatherMore': 'Prognoza pe 12 zile',
'northeast': 'Nord-est', 'windgusts': 'Rafale de vânt',
'east': 'Est', 'north': 'Nord',
'southeast': 'Sud-est', 'northeast': 'Nord-est',
'south': 'Sud', 'east': 'Est',
'southwest': 'Sud-vest', 'southeast': 'Sud-est',
'west': 'Vest', 'south': 'Sud',
'northwest': 'Nord-vest', 'southwest': 'Sud-vest',
'project': 'Proiectul pe', 'west': 'Vest',
'version': 'Versiunea aplicației', 'northwest': 'Nord-vest',
'precipitationProbability': 'Probabilitatea precipitațiilor', 'project': 'Proiectul pe',
'apparentTemperatureMin': 'Temperatura minimă aparentă', 'version': 'Versiunea aplicației',
'apparentTemperatureMax': 'Temperatura maximă aparentă', 'precipitationProbability': 'Probabilitatea precipitațiilor',
'amoledTheme': 'Temă AMOLED', 'apparentTemperatureMin': 'Temperatura minimă aparentă',
'appearance': 'Aspect', 'apparentTemperatureMax': 'Temperatura maximă aparentă',
'functions': 'Funcții', 'amoledTheme': 'Temă AMOLED',
'data': 'Data', 'appearance': 'Aspect',
'language': 'Limba', 'functions': 'Funcții',
'timeRange': 'Frecvența (în ore)', 'data': 'Data',
'timeStart': 'Ora de început', 'language': 'Limba',
'timeEnd': 'Ora de sfârșit', 'timeRange': 'Frecvența (în ore)',
'support': 'Suport', 'timeStart': 'Ora de început',
'system': 'Sistem', 'timeEnd': 'Ora de sfârșit',
'dark': 'Întunecat', 'support': 'Suport',
'light': 'Luminos', 'system': 'Sistem',
'license': 'Licențe', 'dark': 'Întunecat',
'widget': 'Widget', 'light': 'Luminos',
'widgetBackground': 'Fundal widget', 'license': 'Licențe',
'widgetText': 'Text widget', 'widget': 'Widget',
'dewpoint': 'Punct de rouă', 'widgetBackground': 'Fundal widget',
'shortwaveRadiation': 'Radiație cu unde scurte', 'widgetText': 'Text widget',
'roundDegree': 'Rotunjire grade', 'dewpoint': 'Punct de rouă',
'settings_full': 'Setări', 'shortwaveRadiation': 'Radiație cu unde scurte',
'cities': 'Orașe', 'roundDegree': 'Rotunjire grade',
'searchMethod': 'Folosiți căutarea sau geolocația', 'settings_full': 'Setări',
'done': 'Gata', 'cities': 'Orașe',
'groups': 'Grupurile noastre', 'searchMethod': 'Folosiți căutarea sau geolocația',
'openMeteo': 'Date de la Open-Meteo (CC-BY 4.0)', 'done': 'Gata',
'hourlyVariables': 'Variabile meteorologice orare', 'groups': 'Grupurile noastre',
'dailyVariables': 'Variabile meteorologice zilnice', 'openMeteo': 'Date de la Open-Meteo (CC-BY 4.0)',
}; 'hourlyVariables': 'Variabile meteorologice orare',
'dailyVariables': 'Variabile meteorologice zilnice',
'largeElement': 'Afișare mare a vremii',
'map': 'Hartă',
'clearCacheStore': 'Șterge cache-ul',
'deletedCacheStore': 'Ștergerea cache-ului',
'deletedCacheStoreQuery': 'Ești sigur că vrei să ștergi cache-ul?',
'addWidget': 'Adaugă widget',
'hideMap': 'Ascunde harta',
};
} }

269
lib/translation/ru_ru.dart Normal file → Executable file
View file

@ -1,133 +1,142 @@
class RuRu { class RuRu {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Начать', 'start': 'Начать',
'description': 'description':
'Приложение погоды с актуальным прогнозом на каждый час, день и неделю для любого места.', 'Приложение погоды с актуальным прогнозом на каждый час, день и неделю для любого места.',
'name': 'Погода', 'name': 'Погода',
'name2': 'Удобный дизайн', 'name2': 'Удобный дизайн',
'name3': 'Связаться с нами', 'name3': 'Связаться с нами',
'description2': 'description2':
'Вся навигация сделана таким образом, чтобы можно было взаимодействовать с приложением максимально удобно и быстро.', 'Вся навигация сделана таким образом, чтобы можно было взаимодействовать с приложением максимально удобно и быстро.',
'description3': 'description3':
'Если у вас возникнут какие-либо проблемы, пожалуйста, свяжитесь с нами по электронной почте или в отзывах приложения.', 'Если у вас возникнут какие-либо проблемы, пожалуйста, свяжитесь с нами по электронной почте или в отзывах приложения.',
'next': 'Далее', 'next': 'Далее',
'search': 'Поиск...', 'search': 'Поиск...',
'loading': 'Загрузка...', 'loading': 'Загрузка...',
'searchCity': 'Найдите свой город', 'searchCity': 'Найдите свой город',
'humidity': 'Влажность', 'humidity': 'Влажность',
'wind': 'Ветер', 'wind': 'Ветер',
'visibility': 'Видимость', 'visibility': 'Видимость',
'feels': 'Ощущается', 'feels': 'Ощущается',
'evaporation': 'Испарения', 'evaporation': 'Испарения',
'precipitation': 'Осадки', 'precipitation': 'Осадки',
'direction': 'Направление', 'direction': 'Направление',
'pressure': 'Давление', 'pressure': 'Давление',
'rain': 'Дождь', 'rain': 'Дождь',
'clear_sky': 'Чистое небо', 'clear_sky': 'Чистое небо',
'cloudy': 'Облачно', 'cloudy': 'Облачно',
'overcast': 'Пасмурно', 'overcast': 'Пасмурно',
'fog': 'Туман', 'fog': 'Туман',
'drizzle': 'Морось', 'drizzle': 'Морось',
'drizzling_rain': 'Моросящий дождь', 'drizzling_rain': 'Моросящий дождь',
'freezing_rain': 'Ледяной дождь', 'freezing_rain': 'Ледяной дождь',
'heavy_rains': 'Ливневые дожди', 'heavy_rains': 'Ливневые дожди',
'snow': 'Снег', 'snow': 'Снег',
'thunderstorm': 'Гроза', 'thunderstorm': 'Гроза',
'kph': 'км/ч', 'kph': 'км/ч',
'mph': 'миль/ч', 'm/s': 'м/с',
'mi': 'миль', 'mmHg': 'мм рт. ст.',
'km': 'км', 'mph': 'миль/ч',
'inch': 'дюйм', 'mi': 'миль',
'mm': 'мм', 'km': 'км',
'hPa': 'гПа', 'inch': 'дюйм',
'settings': 'Настр.', 'mm': 'мм',
'no_inter': 'Нет интернета', 'hPa': 'гПа',
'on_inter': 'Включите интернет для получения метеорологических данных.', 'settings': 'Настр.',
'location': 'Местоположение', 'no_inter': 'Нет интернета',
'no_location': 'on_inter': 'Включите интернет для получения метеорологических данных.',
'Включите службу определения местоположения для получения метеорологических данных для текущего местоположения.', 'location': 'Местоположение',
'theme': 'Тема', 'no_location':
'low': 'Низкое', 'Включите службу определения местоположения для получения метеорологических данных для текущего местоположения.',
'high': 'Высокое', 'theme': 'Тема',
'normal': 'Нормальное', 'low': 'Низкое',
'lat': 'Широта', 'high': 'Высокое',
'lon': 'Долгота', 'normal': 'Нормальное',
'create': 'Создание', 'lat': 'Широта',
'city': 'Город', 'lon': 'Долгота',
'district': 'Район', 'create': 'Создание',
'noWeatherCard': 'Добавьте город', 'city': 'Город',
'deletedCardWeather': 'Удаление города', 'district': 'Район',
'deletedCardWeatherQuery': 'Вы уверены, что хотите удалить город?', 'noWeatherCard': 'Добавьте город',
'delete': 'Удалить', 'deletedCardWeather': 'Удаление города',
'cancel': 'Отмена', 'deletedCardWeatherQuery': 'Вы уверены, что хотите удалить город?',
'time': 'Время в городе', 'delete': 'Удалить',
'validateName': 'Пожалуйста, введите название', 'cancel': 'Отмена',
'measurements': 'Система мер', 'time': 'Время в городе',
'degrees': 'Градусы', 'validateName': 'Пожалуйста, введите название',
'celsius': 'Цельсия', 'measurements': 'Система мер',
'fahrenheit': 'Фаренгейта', 'degrees': 'Градусы',
'imperial': 'Имперская', 'celsius': 'Цельсия',
'metric': 'Метрическая', 'fahrenheit': 'Фаренгейта',
'validateValue': 'Пожалуйста, введите значение', 'imperial': 'Имперская',
'validateNumber': 'Пожалуйста, введите число', 'metric': 'Метрическая',
'validate90': 'Значение должно быть в диапазоне от -90 до 90', 'validateValue': 'Пожалуйста, введите значение',
'validate180': 'Значение должно быть в диапазоне от -180 до 180', 'validateNumber': 'Пожалуйста, введите число',
'notifications': 'Уведомления', 'validate90': 'Значение должно быть в диапазоне от -90 до 90',
'sunrise': 'Рассвет', 'validate180': 'Значение должно быть в диапазоне от -180 до 180',
'sunset': 'Закат', 'notifications': 'Уведомления',
'timeformat': 'Формат времени', 'sunrise': 'Рассвет',
'12': '12-часовой', 'sunset': 'Закат',
'24': '24-часовой', 'timeformat': 'Формат времени',
'cloudcover': 'Облачный покров', '12': '12-часовой',
'uvIndex': 'УФ-индекс', '24': '24-часовой',
'materialColor': 'Динамические цвета', 'cloudcover': 'Облачный покров',
'uvLow': 'Низкий', 'uvIndex': 'УФ-индекс',
'uvAverage': 'Умеренный', 'materialColor': 'Динамические цвета',
'uvHigh': 'Высокий', 'uvLow': 'Низкий',
'uvVeryHigh': 'Очень высокий', 'uvAverage': 'Умеренный',
'uvExtreme': 'Экстремальный', 'uvHigh': 'Высокий',
'weatherMore': 'Прогноз погоды на 12 дней', 'uvVeryHigh': 'Очень высокий',
'windgusts': 'Шквал', 'uvExtreme': 'Экстремальный',
'north': 'Север', 'weatherMore': 'Прогноз погоды на 12 дней',
'northeast': 'Северо-восток', 'windgusts': 'Шквал',
'east': 'Восток', 'north': 'Север',
'southeast': 'Юго-восток', 'northeast': 'Северо-восток',
'south': 'Юг', 'east': 'Восток',
'southwest': 'Юго-запад', 'southeast': 'Юго-восток',
'west': 'Запад', 'south': 'Юг',
'northwest': 'Северо-запад', 'southwest': 'Юго-запад',
'project': 'Проект на', 'west': 'Запад',
'version': 'Версия приложения', 'northwest': 'Северо-запад',
'precipitationProbability': 'Вероятность выпадения осадков', 'project': 'Проект на',
'apparentTemperatureMin': 'Минимальная ощущаемая температура', 'version': 'Версия приложения',
'apparentTemperatureMax': 'Максимальная ощущаемая температура', 'precipitationProbability': 'Вероятность выпадения осадков',
'amoledTheme': 'AMOLED-тема', 'apparentTemperatureMin': 'Минимальная ощущаемая температура',
'appearance': 'Внешний вид', 'apparentTemperatureMax': 'Максимальная ощущаемая температура',
'functions': 'Функции', 'amoledTheme': 'AMOLED-тема',
'data': 'Данные', 'appearance': 'Внешний вид',
'language': 'Язык', 'functions': 'Функции',
'timeRange': 'Периодичность (в часах)', 'data': 'Данные',
'timeStart': 'Время начала', 'language': 'Язык',
'timeEnd': 'Время окончания', 'timeRange': 'Периодичность (в часах)',
'support': 'Поддержка', 'timeStart': 'Время начала',
'system': 'Системная', 'timeEnd': 'Время окончания',
'dark': 'Тёмная', 'support': 'Поддержка',
'light': 'Светлая', 'system': 'Системная',
'license': 'Лицензии', 'dark': 'Тёмная',
'widget': 'Виджет', 'light': 'Светлая',
'widgetBackground': 'Фон виджета', 'license': 'Лицензии',
'widgetText': 'Текст виджета', 'widget': 'Виджет',
'dewpoint': 'Точка росы', 'widgetBackground': 'Фон виджета',
'shortwaveRadiation': 'Коротковолновое излучение', 'widgetText': 'Текст виджета',
'W/m2': 'Вт/м2', 'dewpoint': 'Точка росы',
'roundDegree': 'Округлить градусы', 'shortwaveRadiation': 'Коротковолновое излучение',
'settings_full': 'Настройки', 'W/m2': 'Вт/м2',
'cities': 'Города', 'roundDegree': 'Округлить градусы',
'searchMethod': 'Воспользуйтесь поиском или геолокацией', 'settings_full': 'Настройки',
'done': 'Готово', 'cities': 'Города',
'groups': 'Наши группы', 'searchMethod': 'Воспользуйтесь поиском или геолокацией',
'openMeteo': 'Данные от Open-Meteo (CC-BY 4.0)', 'done': 'Готово',
'hourlyVariables': 'Почасовые погодные условия', 'groups': 'Наши группы',
'dailyVariables': 'Ежедневные погодные условия', 'openMeteo': 'Данные от Open-Meteo (CC-BY 4.0)',
}; 'hourlyVariables': 'Почасовые погодные условия',
'dailyVariables': 'Ежедневные погодные условия',
'largeElement': 'Отображение погоды большим элементом',
'map': 'Карта',
'clearCacheStore': 'Очистить кэш',
'deletedCacheStore': 'Очистка кэша',
'deletedCacheStoreQuery': 'Вы уверены, что хотите очистить кэш?',
'addWidget': 'Добавить виджет',
'hideMap': 'Скрыть карту',
};
} }

268
lib/translation/sk_sk.dart Normal file → Executable file
View file

@ -1,132 +1,142 @@
class SkSk { class SkSk {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Začať', 'start': 'Začať',
'description': 'description':
'Aplikácia počasia s aktuálnym predpoveďou pre každú hodinu, deň a týždeň pre akékoľvek miesto.', 'Aplikácia počasia s aktuálnym predpoveďou pre každú hodinu, deň a týždeň pre akékoľvek miesto.',
'name': 'Počasie', 'name': 'Počasie',
'name2': 'Pohodlný dizajn', 'name2': 'Pohodlný dizajn',
'name3': 'Kontaktujte nás', 'name3': 'Kontaktujte nás',
'description2': 'description2':
'Celá navigácia je navrhnutá tak, aby sa s aplikáciou dalo interagovať čo najpohodlnejšie a najrýchlejšie.', 'Celá navigácia je navrhnutá tak, aby sa s aplikáciou dalo interagovať čo najpohodlnejšie a najrýchlejšie.',
'description3': 'description3':
'Ak sa vyskytnú nejaké problémy, kontaktujte nás prosím e-mailom alebo v recenziách aplikácie.', 'Ak sa vyskytnú nejaké problémy, kontaktujte nás prosím e-mailom alebo v recenziách aplikácie.',
'next': 'Ďalej', 'next': 'Ďalej',
'search': 'Hľadať...', 'search': 'Hľadať...',
'loading': 'Načítava sa...', 'loading': 'Načítava sa...',
'searchCity': 'Nájdite svoje miesto', 'searchCity': 'Nájdite svoje miesto',
'humidity': 'Vlhkosť', 'humidity': 'Vlhkosť',
'wind': 'Vietor', 'wind': 'Vietor',
'visibility': 'Viditeľnosť', 'visibility': 'Viditeľnosť',
'feels': 'Pocitová teplota', 'feels': 'Pocitová teplota',
'evaporation': 'Evapotranspirácia', 'evaporation': 'Evapotranspirácia',
'precipitation': 'Zrážky', 'precipitation': 'Zrážky',
'direction': 'Smer', 'direction': 'Smer',
'pressure': 'Tlak', 'pressure': 'Tlak',
'rain': 'Dážď', 'rain': 'Dážď',
'clear_sky': 'Jasno', 'clear_sky': 'Jasno',
'cloudy': 'Oblačno', 'cloudy': 'Oblačno',
'overcast': 'Zamračené', 'overcast': 'Zamračené',
'fog': 'Hmla', 'fog': 'Hmla',
'drizzle': 'Mrholenie', 'drizzle': 'Mrholenie',
'drizzling_rain': 'Mrznúce mrholenie', 'drizzling_rain': 'Mrznúce mrholenie',
'freezing_rain': 'Mrazivý dážď', 'freezing_rain': 'Mrazivý dážď',
'heavy_rains': 'Prehánky', 'heavy_rains': 'Prehánky',
'snow': 'Sneh', 'snow': 'Sneh',
'thunderstorm': 'Búrka', 'thunderstorm': 'Búrka',
'kph': 'km/h', 'kph': 'km/h',
'mph': 'mph', 'mph': 'mph',
'mi': 'mi', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'inch', 'mi': 'mi',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'inch',
'settings': 'Nast.', 'mm': 'mm',
'no_inter': 'Žiadny internet', 'hPa': 'hPa',
'on_inter': 'Pripojte sa na internet a získajte meteorologické údaje.', 'settings': 'Nast.',
'location': 'Poloha', 'no_inter': 'Žiadny internet',
'no_location': 'on_inter': 'Pripojte sa na internet a získajte meteorologické údaje.',
'Ak chcete získať údaje o počasí pre aktuálnu polohu, povoľte službu určovania polohy.', 'location': 'Poloha',
'theme': 'Téma', 'no_location':
'low': 'Nízky', 'Ak chcete získať údaje o počasí pre aktuálnu polohu, povoľte službu určovania polohy.',
'high': 'Vysoký', 'theme': 'Téma',
'normal': 'Normálny', 'low': 'Nízky',
'lat': 'Zemepisná šírka', 'high': 'Vysoký',
'lon': 'Zemepisná dĺžka', 'normal': 'Normálny',
'create': 'Vytvoriť', 'lat': 'Zemepisná šírka',
'city': 'Miesto', 'lon': 'Zemepisná dĺžka',
'district': 'Okres', 'create': 'Vytvoriť',
'noWeatherCard': 'Pridať mesto', 'city': 'Miesto',
'deletedCardWeather': 'Vymazať mesto', 'district': 'Okres',
'deletedCardWeatherQuery': 'Naozaj chcete odstrániť mesto?', 'noWeatherCard': 'Pridať mesto',
'delete': 'Odstrániť', 'deletedCardWeather': 'Vymazať mesto',
'cancel': 'Zrušiť', 'deletedCardWeatherQuery': 'Naozaj chcete odstrániť mesto?',
'time': 'Čas v meste', 'delete': 'Odstrániť',
'validateName': 'Prosím zadajte názov', 'cancel': 'Zrušiť',
'measurements': 'Jednotky merania', 'time': 'Čas v meste',
'degrees': 'Stupňe', 'validateName': 'Prosím zadajte názov',
'celsius': 'Celzius', 'measurements': 'Jednotky merania',
'fahrenheit': 'Fahrenheit', 'degrees': 'Stupňe',
'imperial': 'Imperiálne', 'celsius': 'Celzius',
'metric': 'Metrické', 'fahrenheit': 'Fahrenheit',
'validateValue': 'Zadajte hodnotu', 'imperial': 'Imperiálne',
'validateNumber': 'Zadajte platné číslo', 'metric': 'Metrické',
'validate90': 'Hodnota musí byť medzi -90 a 90', 'validateValue': 'Zadajte hodnotu',
'validate180': 'Hodnota musí byť medzi -180 a 180', 'validateNumber': 'Zadajte platné číslo',
'notifications': 'Notifikácie', 'validate90': 'Hodnota musí byť medzi -90 a 90',
'sunrise': 'Východ slnka', 'validate180': 'Hodnota musí byť medzi -180 a 180',
'sunset': 'Západ slnka', 'notifications': 'Notifikácie',
'timeformat': 'Formát času', 'sunrise': 'Východ slnka',
'12': '12-hodinový', 'sunset': 'Západ slnka',
'24': '24-hodinový', 'timeformat': 'Formát času',
'cloudcover': 'Oblačnosť', '12': '12-hodinový',
'uvIndex': 'UV-index', '24': '24-hodinový',
'materialColor': 'Dynamické Farby', 'cloudcover': 'Oblačnosť',
'uvLow': 'Nízky', 'uvIndex': 'UV-index',
'uvAverage': 'Mierny', 'materialColor': 'Dynamické Farby',
'uvHigh': 'Vysoký', 'uvLow': 'Nízky',
'uvVeryHigh': 'Veľmi vysoký', 'uvAverage': 'Mierny',
'uvExtreme': 'Extrémny', 'uvHigh': 'Vysoký',
'weatherMore': 'Predpoveď počasia na 12 dní', 'uvVeryHigh': 'Veľmi vysoký',
'windgusts': 'Nárazy vetra', 'uvExtreme': 'Extrémny',
'north': 'Sever', 'weatherMore': 'Predpoveď počasia na 12 dní',
'northeast': 'Severo-Východ', 'windgusts': 'Nárazy vetra',
'east': 'Východ', 'north': 'Sever',
'southeast': 'Juhovýchod', 'northeast': 'Severo-Východ',
'south': 'Juž', 'east': 'Východ',
'southwest': 'Juhozápad', 'southeast': 'Juhovýchod',
'west': 'Západ', 'south': 'Juž',
'northwest': 'Severo-Západ', 'southwest': 'Juhozápad',
'project': 'Projekt na', 'west': 'Západ',
'version': 'Verzia aplikácie', 'northwest': 'Severo-Západ',
'precipitationProbability': 'Pravdepodobnosť zrážok', 'project': 'Projekt na',
'apparentTemperatureMin': 'Minimálna pocitová teplota', 'version': 'Verzia aplikácie',
'apparentTemperatureMax': 'Maximálna pocitová teplota', 'precipitationProbability': 'Pravdepodobnosť zrážok',
'amoledTheme': 'AMOLED-téma', 'apparentTemperatureMin': 'Minimálna pocitová teplota',
'appearance': 'Vzhľad', 'apparentTemperatureMax': 'Maximálna pocitová teplota',
'functions': 'Funkcie', 'amoledTheme': 'AMOLED-téma',
'data': 'Dáta', 'appearance': 'Vzhľad',
'language': 'Jazyk', 'functions': 'Funkcie',
'timeRange': 'Frekvencia (v hodinách)', 'data': 'Dáta',
'timeStart': 'Čas začiatku', 'language': 'Jazyk',
'timeEnd': 'Čas ukončenia', 'timeRange': 'Frekvencia (v hodinách)',
'support': 'Podpora', 'timeStart': 'Čas začiatku',
'system': 'Systém', 'timeEnd': 'Čas ukončenia',
'dark': 'Tmavá', 'support': 'Podpora',
'light': 'Svetlá', 'system': 'Systém',
'license': 'Licencie', 'dark': 'Tmavá',
'widget': 'Widget', 'light': 'Svetlá',
'widgetBackground': 'Pozadie widgetu', 'license': 'Licencie',
'widgetText': 'Text widgetu', 'widget': 'Widget',
'dewpoint': 'Rosný bod', 'widgetBackground': 'Pozadie widgetu',
'shortwaveRadiation': 'Krátka vlnová radiácia', 'widgetText': 'Text widgetu',
'roundDegree': 'Zaokrúhliť stupne', 'dewpoint': 'Rosný bod',
'settings_full': 'Nastavenia', 'shortwaveRadiation': 'Krátka vlnová radiácia',
'cities': 'Mestá', 'roundDegree': 'Zaokrúhliť stupne',
'searchMethod': 'Použite vyhľadávanie alebo geolokáciu', 'settings_full': 'Nastavenia',
'done': 'Hotovo', 'cities': 'Mestá',
'groups': 'Naše skupiny', 'searchMethod': 'Použite vyhľadávanie alebo geolokáciu',
'openMeteo': 'Údaje od Open-Meteo (CC-BY 4.0)', 'done': 'Hotovo',
'hourlyVariables': 'Hodinové meteorologické premenné', 'groups': 'Naše skupiny',
'dailyVariables': 'Denné meteorologické premenné', 'openMeteo': 'Údaje od Open-Meteo (CC-BY 4.0)',
}; 'hourlyVariables': 'Hodinové meteorologické premenné',
'dailyVariables': 'Denné meteorologické premenné',
'largeElement': 'Veľké zobrazenie počasia',
'map': 'Mapa',
'clearCacheStore': 'Vymazať vyrovnávaciu pamäť',
'deletedCacheStore': 'Vymazávanie vyrovnávacej pamäte',
'deletedCacheStoreQuery':
'Ste si istí, že chcete vymazať vyrovnávaciu pamäť?',
'addWidget': 'Pridať widget',
'hideMap': 'Skryť mapu',
};
} }

268
lib/translation/tr_tr.dart Normal file → Executable file
View file

@ -1,132 +1,142 @@
class TrTr { class TrTr {
Map<String, String> get messages => { Map<String, String> get messages => {
'start': 'Başlat', 'start': 'Başlat',
'description': 'description':
'Herhangi bir yer için her saat, gün ve hafta için güncel hava durumu tahmini sunan hava durumu uygulaması.', 'Herhangi bir yer için her saat, gün ve hafta için güncel hava durumu tahmini sunan hava durumu uygulaması.',
'name': 'Hava Durumu', 'name': 'Hava Durumu',
'name2': 'Pratik Tasarım', 'name2': 'Pratik Tasarım',
'name3': 'Bizimle İletişime Geçin', 'name3': 'Bizimle İletişime Geçin',
'description2': 'description2':
'Tüm gezinme, uygulama ile mümkün olduğunca rahat ve hızlı etkileşim kurmak için tasarlanmıştır.', 'Tüm gezinme, uygulama ile mümkün olduğunca rahat ve hızlı etkileşim kurmak için tasarlanmıştır.',
'description3': 'description3':
'Herhangi bir sorunla karşılaşırsanız, lütfen bize e-posta veya uygulama yorumları aracılığıyla ulaşın.', 'Herhangi bir sorunla karşılaşırsanız, lütfen bize e-posta veya uygulama yorumları aracılığıyla ulaşın.',
'next': 'Devam', 'next': 'Devam',
'search': 'Arayış...', 'search': 'Arayış...',
'loading': 'Yükleniyor...', 'loading': 'Yükleniyor...',
'searchCity': 'Şehrinizi bulun', 'searchCity': 'Şehrinizi bulun',
'humidity': 'Nem', 'humidity': 'Nem',
'wind': 'Rüzgar', 'wind': 'Rüzgar',
'visibility': 'Görüş', 'visibility': 'Görüş',
'feels': 'Hissedilen', 'feels': 'Hissedilen',
'evaporation': 'Buharlaşma', 'evaporation': 'Buharlaşma',
'precipitation': 'Yağış', 'precipitation': 'Yağış',
'direction': 'Yön', 'direction': 'Yön',
'pressure': 'Bası', 'pressure': 'Bası',
'rain': 'Yağmur', 'rain': 'Yağmur',
'clear_sky': 'ık gökyüzü', 'clear_sky': 'ık gökyüzü',
'cloudy': 'Bulutlu', 'cloudy': 'Bulutlu',
'overcast': 'Kapalı', 'overcast': 'Kapalı',
'fog': 'Sis', 'fog': 'Sis',
'drizzle': 'Çiseleme', 'drizzle': 'Çiseleme',
'drizzling_rain': 'Çiseleyen Yağmur', 'drizzling_rain': 'Çiseleyen Yağmur',
'freezing_rain': 'Dondurucu Yağmur', 'freezing_rain': 'Dondurucu Yağmur',
'heavy_rains': 'ırı Yağmurlar', 'heavy_rains': 'ırı Yağmurlar',
'snow': 'Kar', 'snow': 'Kar',
'thunderstorm': 'Gök Gürültülü Fırtına', 'thunderstorm': 'Gök Gürültülü Fırtına',
'kph': 'km/sa', 'kph': 'km/sa',
'mph': 'mil/sa', 'mph': 'mil/sa',
'mi': 'mil', 'm/s': 'm/s',
'km': 'km', 'mmHg': 'mmHg',
'inch': 'inç', 'mi': 'mil',
'mm': 'mm', 'km': 'km',
'hPa': 'hPa', 'inch': 'inç',
'settings': 'Ayarlar', 'mm': 'mm',
'no_inter': 'İnternet yok', 'hPa': 'hPa',
'on_inter': 'Hava durumu verilerini almak için interneti açın.', 'settings': 'Ayarlar',
'location': 'Konum', 'no_inter': 'İnternet yok',
'no_location': 'on_inter': 'Hava durumu verilerini almak için interneti açın.',
'Mevcut konumun hava durumu verilerini almak için konum servisini açın.', 'location': 'Konum',
'theme': 'Tema', 'no_location':
'low': 'Düşük', 'Mevcut konumun hava durumu verilerini almak için konum servisini açın.',
'high': 'Yüksek', 'theme': 'Tema',
'normal': 'Normal', 'low': 'Düşük',
'lat': 'Enlem', 'high': 'Yüksek',
'lon': 'Boylam', 'normal': 'Normal',
'create': 'Oluştur', 'lat': 'Enlem',
'city': 'Şehir', 'lon': 'Boylam',
'district': 'İlçe', 'create': 'Oluştur',
'noWeatherCard': 'Şehri ekle', 'city': 'Şehir',
'deletedCardWeather': 'Şehir silme', 'district': 'İlçe',
'deletedCardWeatherQuery': 'Şehri silmek istediğinizden emin misiniz?', 'noWeatherCard': 'Şehri ekle',
'delete': 'Sil', 'deletedCardWeather': 'Şehir silme',
'cancel': 'İptal', 'deletedCardWeatherQuery': 'Şehri silmek istediğinizden emin misiniz?',
'time': 'Şehirde Saat', 'delete': 'Sil',
'validateName': 'Lütfen bir isim girin', 'cancel': 'İptal',
'measurements': 'Ölçüm sistemi', 'time': 'Şehirde Saat',
'degrees': 'Dereceler', 'validateName': 'Lütfen bir isim girin',
'celsius': 'Celsius', 'measurements': 'Ölçüm sistemi',
'fahrenheit': 'Fahrenheit', 'degrees': 'Dereceler',
'imperial': 'İmparatorluk', 'celsius': 'Celsius',
'metric': 'Metrik', 'fahrenheit': 'Fahrenheit',
'validateValue': 'Lütfen bir değer girin', 'imperial': 'İmparatorluk',
'validateNumber': 'Lütfen bir sayı girin', 'metric': 'Metrik',
'validate90': 'Değer -90 ile 90 arasında olmalıdır', 'validateValue': 'Lütfen bir değer girin',
'validate180': 'Değer -180 ile 180 arasında olmalıdır', 'validateNumber': 'Lütfen bir sayı girin',
'notifications': 'Bildirme', 'validate90': 'Değer -90 ile 90 arasında olmalıdır',
'sunrise': 'Güneş doğuşu', 'validate180': 'Değer -180 ile 180 arasında olmalıdır',
'sunset': 'Güneş batışı', 'notifications': 'Bildirme',
'timeformat': 'Saat biçimi', 'sunrise': 'Güneş doğuşu',
'12': '12 saat', 'sunset': 'Güneş batışı',
'24': '24 saat', 'timeformat': 'Saat biçimi',
'cloudcover': 'Bulut örtüsü', '12': '12 saat',
'uvIndex': 'UV-indeksi', '24': '24 saat',
'materialColor': 'Dinamik Renkler', 'cloudcover': 'Bulut örtüsü',
'uvLow': 'Düşük', 'uvIndex': 'UV-indeksi',
'uvAverage': 'Orta', 'materialColor': 'Dinamik Renkler',
'uvHigh': 'Yüksek', 'uvLow': 'Düşük',
'uvVeryHigh': 'Çok yüksek', 'uvAverage': 'Orta',
'uvExtreme': 'ırı', 'uvHigh': 'Yüksek',
'weatherMore': '12 günlük hava tahmini', 'uvVeryHigh': 'Çok yüksek',
'windgusts': 'Bir telaş', 'uvExtreme': 'ırı',
'north': 'Kuzey', 'weatherMore': '12 günlük hava tahmini',
'northeast': 'Kuzeydoğu', 'windgusts': 'Bir telaş',
'east': 'Doğu', 'north': 'Kuzey',
'southeast': 'Güneydoğu', 'northeast': 'Kuzeydoğu',
'south': 'Güney', 'east': 'Doğu',
'southwest': 'Güneybatı', 'southeast': 'Güneydoğu',
'west': 'Batı', 'south': 'Güney',
'northwest': 'Kuzeybatı', 'southwest': 'Güneybatı',
'project': 'Proje üzerinde', 'west': 'Batı',
'version': 'Uygulama sürümü', 'northwest': 'Kuzeybatı',
'precipitationProbability': 'Yağış olasılığı', 'project': 'Proje üzerinde',
'apparentTemperatureMin': 'Minimum hissedilen sıcaklık', 'version': 'Uygulama sürümü',
'apparentTemperatureMax': 'Maksimum hissedilen sıcaklık', 'precipitationProbability': 'Yağış olasılığı',
'amoledTheme': 'AMOLED-teması', 'apparentTemperatureMin': 'Minimum hissedilen sıcaklık',
'appearance': 'Görünüm', 'apparentTemperatureMax': 'Maksimum hissedilen sıcaklık',
'functions': 'Fonksiyonlar', 'amoledTheme': 'AMOLED-teması',
'data': 'Veri', 'appearance': 'Görünüm',
'language': 'Dil', 'functions': 'Fonksiyonlar',
'timeRange': 'Sıklık (saat cinsinden)', 'data': 'Veri',
'timeStart': 'Başlangıç zamanı', 'language': 'Dil',
'timeEnd': 'Bitiş zamanı', 'timeRange': 'Sıklık (saat cinsinden)',
'support': 'Destek', 'timeStart': 'Başlangıç zamanı',
'system': 'Sistem', 'timeEnd': 'Bitiş zamanı',
'dark': 'Karanlık', 'support': 'Destek',
'light': 'Aydınlık', 'system': 'Sistem',
'license': 'Lisanslar', 'dark': 'Karanlık',
'widget': 'Araç', 'light': 'Aydınlık',
'widgetBackground': 'Araç Arka Planı', 'license': 'Lisanslar',
'widgetText': 'Araç metni', 'widget': 'Araç',
'dewpoint': 'Çiğ noktası', 'widgetBackground': 'Araç Arka Planı',
'shortwaveRadiation': 'Kısa dalga radyasyonu', 'widgetText': 'Araç metni',
'roundDegree': 'Dereceleri yuvarla', 'dewpoint': 'Çiğ noktası',
'settings_full': 'Ayarlar', 'shortwaveRadiation': 'Kısa dalga radyasyonu',
'cities': 'Şehirler', 'roundDegree': 'Dereceleri yuvarla',
'searchMethod': 'Arama veya konum belirleme kullanın', 'settings_full': 'Ayarlar',
'done': 'Tamam', 'cities': 'Şehirler',
'groups': 'Gruplarımız', 'searchMethod': 'Arama veya konum belirleme kullanın',
'openMeteo': 'Open-Meteo\'dan veriler (CC-BY 4.0)', 'done': 'Tamam',
'hourlyVariables': 'Saatlik hava değişkenleri', 'groups': 'Gruplarımız',
'dailyVariables': 'Günlük hava değişkenleri', 'openMeteo': 'Open-Meteo\'dan veriler (CC-BY 4.0)',
}; 'hourlyVariables': 'Saatlik hava değişkenleri',
'dailyVariables': 'Günlük hava değişkenleri',
'largeElement': 'Büyük hava durumu gösterimi',
'map': 'Harita',
'clearCacheStore': 'Önbelleği temizle',
'deletedCacheStore': 'Önbellek temizleniyor',
'deletedCacheStoreQuery':
'Önbelleği temizlemek istediğinizden emin misiniz?',
'addWidget': 'Widget ekle',
'hideMap': 'Haritayı gizle',
};
} }

50
lib/translation/translation.dart Normal file → Executable file
View file

@ -27,29 +27,29 @@ import 'package:rain/translation/zh_tw.dart';
class Translation extends Translations { class Translation extends Translations {
@override @override
Map<String, Map<String, String>> get keys => { Map<String, Map<String, String>> get keys => {
'ru_RU': RuRu().messages, 'ru_RU': RuRu().messages,
'en_US': EnUs().messages, 'en_US': EnUs().messages,
'fr_FR': FrFr().messages, 'fr_FR': FrFr().messages,
'fa_IR': FaIr().messages, 'fa_IR': FaIr().messages,
'it_IT': ItIt().messages, 'it_IT': ItIt().messages,
'de_DE': DeDe().messages, 'de_DE': DeDe().messages,
'tr_TR': TrTr().messages, 'tr_TR': TrTr().messages,
'pt_BR': PtBr().messages, 'pt_BR': PtBr().messages,
'es_ES': EsEs().messages, 'es_ES': EsEs().messages,
'sk_SK': SkSk().messages, 'sk_SK': SkSk().messages,
'nl_NL': NlNl().messages, 'nl_NL': NlNl().messages,
'hi_IN': HiIn().messages, 'hi_IN': HiIn().messages,
'ro_RO': RoRo().messages, 'ro_RO': RoRo().messages,
'zh_CN': ZhCh().messages, 'zh_CN': ZhCh().messages,
'zh_TW': ZhTw().messages, 'zh_TW': ZhTw().messages,
'pl_PL': PlPl().messages, 'pl_PL': PlPl().messages,
'ur_PK': UrPk().messages, 'ur_PK': UrPk().messages,
'cs_CZ': CsCz().messages, 'cs_CZ': CsCz().messages,
'ka_GE': KaGe().messages, 'ka_GE': KaGe().messages,
'bn_IN': BnIn().messages, 'bn_IN': BnIn().messages,
'ga_IE': GaIe().messages, 'ga_IE': GaIe().messages,
'hu_HU': HuHu().messages, 'hu_HU': HuHu().messages,
'da_DK': DaDk().messages, 'da_DK': DaDk().messages,
'ko_KR': KoKr().messages, 'ko_KR': KoKr().messages,
}; };
} }

Some files were not shown because too many files have changed in this diff Show more