Compare commits
97 commits
Author | SHA1 | Date | |
---|---|---|---|
|
9ba80c3609 | ||
|
33be8dcdc6 | ||
|
089f3ae0b7 | ||
|
fb150421a6 | ||
|
d169f6237f | ||
|
e14dc03524 | ||
|
97aa5024b4 | ||
|
f880c5d274 | ||
|
0973fb5230 | ||
|
416f77765c | ||
|
a59c6b7338 | ||
|
0552a84e6f | ||
|
3a23dd6288 | ||
|
b7d0e8012a | ||
|
fa0921d1b0 | ||
|
7a00917ca2 | ||
|
ddf7115579 | ||
|
014a52c215 | ||
|
07142e25a7 | ||
|
55e813749a | ||
|
1d7cbbd1bf | ||
|
1ea344c69a | ||
|
5cd6e2e6c8 | ||
|
c0c15bb811 | ||
|
d5a34ea11b | ||
|
f174c0f336 | ||
|
d0791279a2 | ||
|
88a7bafffb | ||
|
27e276a092 | ||
|
383fb24881 | ||
|
8ed047a1aa | ||
|
6c7da7b28d | ||
|
b2e843c5d9 | ||
|
91e1757a20 | ||
|
8bce420296 | ||
|
2cc70f9221 | ||
|
dd57938153 | ||
|
fc246ac5a2 | ||
|
33ceb30885 | ||
|
46e1546e5b | ||
|
dd3339bc3b | ||
|
9a7858f279 | ||
|
6d0d0efe36 | ||
|
aa125fcdc1 | ||
|
0d565752d5 | ||
|
6646f657d2 | ||
|
647d620d45 | ||
|
b459a50f60 | ||
|
da64975e68 | ||
|
58dbbe52ce | ||
|
275bbba853 | ||
|
ceb27da369 | ||
|
b8600ab472 | ||
|
3cfd4f8248 | ||
|
8eae7203f0 | ||
|
42f7a2590e | ||
|
4b1536579d | ||
|
f3400916d9 | ||
|
696634c08f | ||
|
a00abd4f3a | ||
|
1342079b6b | ||
|
4d310776ce | ||
|
cb7367c04f | ||
|
51f72b4e7b | ||
|
400614a8f1 | ||
|
1e11b6b775 | ||
|
902bc45207 | ||
|
8275ec8f9e | ||
|
441a5ee680 | ||
|
a46986f050 | ||
|
fa5fbb8ce6 | ||
|
cda285ea15 | ||
|
f08c459bc1 | ||
|
1f945c4dfd | ||
|
c5b55a291b | ||
|
013493c0dd | ||
|
58373c7c9c | ||
|
504a77f6ad | ||
|
0f29d2bdad | ||
|
da07dc23c7 | ||
|
265ba143ab | ||
|
f77d09d147 | ||
|
b160fc8fa4 | ||
|
225a5240b2 | ||
|
dc3f90e346 | ||
|
e391c074c4 | ||
|
d0464a5727 | ||
|
42ad98da43 | ||
|
6f195dc791 | ||
|
4c79b5e8c2 | ||
|
2807fc08fb | ||
|
78c7519673 | ||
|
8435b7e2ce | ||
|
bf7ed5f9da | ||
|
7e13bf32b9 | ||
|
c7798bc4d6 | ||
|
6d249bd7a6 |
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
3
.gitignore
vendored
|
@ -15,6 +15,7 @@ migrate_working_dir/
|
|||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
.cxx/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
|
@ -41,4 +42,4 @@ app.*.map.json
|
|||
# Android Studio will place build artifacts here
|
||||
/android/app/debug
|
||||
/android/app/profile
|
||||
/android/app/release
|
||||
/android/app/release
|
||||
|
|
34
.metadata
|
@ -1,11 +1,11 @@
|
|||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled.
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
channel: stable
|
||||
revision: "2663184aa79047d0a33a14a3b607954f8fdd8730"
|
||||
channel: "stable"
|
||||
|
||||
project_type: app
|
||||
|
||||
|
@ -13,26 +13,26 @@ project_type: app
|
|||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
- platform: android
|
||||
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
- platform: ios
|
||||
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
- platform: linux
|
||||
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
- platform: macos
|
||||
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
- platform: web
|
||||
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
- platform: windows
|
||||
create_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
base_revision: 135454af32477f815a7525073027a3ff9eff1bfd
|
||||
create_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
base_revision: 2663184aa79047d0a33a14a3b607954f8fdd8730
|
||||
|
||||
# User provided section
|
||||
|
||||
|
|
43
CODE_OF_CONDUCT.md
Normal file
|
@ -0,0 +1,43 @@
|
|||
# Code of Conduct
|
||||
|
||||
## Our Commitment
|
||||
|
||||
In the interest of fostering an open and friendly community, we, as contributors and maintainers, pledge to make participation in our project and our community a harassment-free experience for everyone.
|
||||
|
||||
## Standards of Behavior
|
||||
|
||||
1. **Respect**: Be respectful and considerate of different viewpoints and experiences.
|
||||
|
||||
2. **Collaboration**: Collaborate with community members, uphold principles of openness, and assist each other.
|
||||
|
||||
3. **Friendliness**: Remember that diversity of opinions and experiences is valuable for our community. Be friendly and supportive.
|
||||
|
||||
4. **Responsibility**: Be mindful of your words and actions. If you make a commitment, strive to fulfill it.
|
||||
|
||||
## Unacceptable Behavior
|
||||
|
||||
Unacceptable behavior includes but is not limited to:
|
||||
|
||||
1. **Discrimination**: No forms of discrimination or harassment based on race, gender, sexual orientation, nationality, religion, or other characteristics.
|
||||
|
||||
2. **Insults and Threats**: No offensive comments, threats, or bullying.
|
||||
|
||||
3. **Hostile Conduct**: No actions intended to create a hostile atmosphere in the community.
|
||||
|
||||
## Reporting Procedure
|
||||
|
||||
If you believe you're experiencing a violation of the code of conduct, please report it by sending an email to darkmoonight2022@gmail.com.
|
||||
|
||||
## Conclusion
|
||||
|
||||
We encourage all participants to adhere to this code of conduct. Violation of these principles may result in temporary or permanent exclusion from the community.
|
||||
|
||||
Thank you for your contribution and cooperation in creating an open and friendly community!
|
||||
|
||||
## Changes
|
||||
|
||||
This code of conduct may be revised from time to time. The most current version will always be available in this file.
|
||||
|
||||
## Attribution
|
||||
|
||||
This code of conduct is adapted from [Contributor Covenant](https://www.contributor-covenant.org/).
|
37
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,37 @@
|
|||
# Contribution Guidelines
|
||||
|
||||
Thank you for considering contributing to our project! We welcome your input and appreciate your efforts. To ensure a smooth collaboration, please take a moment to review the following guidelines.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project and everyone participating in it are governed by our [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [project email].
|
||||
|
||||
## How to Contribute
|
||||
|
||||
1. Fork the repository and clone it locally.
|
||||
2. Create a new branch for your feature or bug fix.
|
||||
3. Make your changes and commit them.
|
||||
4. Push your changes to your fork on GitHub.
|
||||
5. Open a pull request in the original repository. Provide a clear title and description of your changes.
|
||||
|
||||
## Coding Standards
|
||||
|
||||
Follow the coding standards and style guide used in the project. If there's no specific guide, stick to the existing code style.
|
||||
|
||||
## Testing
|
||||
|
||||
Ensure that your code changes do not break existing functionality. Write tests for new features or bug fixes if applicable.
|
||||
|
||||
## Documentation
|
||||
|
||||
Update the documentation if your changes affect it. This includes the README.md file and any additional documentation files.
|
||||
|
||||
## Issues
|
||||
|
||||
Before starting work on a new feature or bug fix, check the issue tracker for related discussions or known issues.
|
||||
|
||||
## License
|
||||
|
||||
By contributing, you agree that your contributions will be licensed under the project's license.
|
||||
|
||||
Thank you for your contribution!
|
21
README.md
|
@ -1,15 +1,15 @@
|
|||
<div align='center'>
|
||||
<img src='/assets/icons/icon.png' width='150'/>
|
||||
<h2>🌦️ Rain</h2>
|
||||
<img src='/readme/icon.png' width='150'/>
|
||||
<h2>🌦️ Rain</h2>
|
||||
</div>
|
||||
|
||||
<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?style=flat-square&color=abc0d3'/></a>
|
||||
<a href='https://github.com/darkmoonight/Rain/forks'><img alt='Forks' src='https://img.shields.io/github/forks/darkmoonight/Rain?style=flat-square&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>
|
||||
</p>
|
||||
<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/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/blob/main/LICENSE'><img alt='License' src='https://img.shields.io/github/license/darkmoonight/Rain?color=abc0d3'/></a>
|
||||
</p>
|
||||
</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
|
||||
|
||||
<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
|
||||
|
||||
|
@ -52,7 +52,6 @@ If you find Rain valuable and worthy for future innovation, consider supporting
|
|||
### 📥 Get Rain Now
|
||||
|
||||
[](https://play.google.com/store/apps/details?id=com.yoshi.rain)
|
||||
[](https://apps.rustore.ru/app/com.yoshi.rain)
|
||||
|
||||
Or get the latest APK from the [Releases Section](https://github.com/DarkMooNight/Rain/releases/latest). You can also find the app on IzzyOnDroid via a F-Droid client [here](https://apt.izzysoft.de/fdroid/index/apk/com.yoshi.rain).
|
||||
|
||||
|
@ -63,5 +62,5 @@ This project is licensed under the [MIT License](./LICENSE).
|
|||
### 👨💻 Our Contributors
|
||||
|
||||
<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>
|
||||
|
|
|
@ -1,30 +1,9 @@
|
|||
def localProperties = new Properties()
|
||||
def localPropertiesFile = rootProject.file('local.properties')
|
||||
if (localPropertiesFile.exists()) {
|
||||
localPropertiesFile.withReader('UTF-8') { reader ->
|
||||
localProperties.load(reader)
|
||||
}
|
||||
plugins {
|
||||
id "com.android.application"
|
||||
id "kotlin-android"
|
||||
id "dev.flutter.flutter-gradle-plugin"
|
||||
}
|
||||
|
||||
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
||||
if (flutterRoot == null) {
|
||||
throw GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
||||
}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||
if (flutterVersionCode == null) {
|
||||
flutterVersionCode = '1'
|
||||
}
|
||||
|
||||
def flutterVersionName = localProperties.getProperty('flutter.versionName')
|
||||
if (flutterVersionName == null) {
|
||||
flutterVersionName = '1.0'
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
def keystoreProperties = new Properties()
|
||||
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
|
@ -32,64 +11,73 @@ if (keystorePropertiesFile.exists()) {
|
|||
}
|
||||
|
||||
android {
|
||||
compileSdk 34
|
||||
ndkVersion flutter.ndkVersion
|
||||
namespace = 'com.yoshi.rain'
|
||||
compileSdk = 35
|
||||
ndkVersion = '29.0.13113456'
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
coreLibraryDesugaringEnabled = true
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
jvmTarget = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
dependenciesInfo {
|
||||
// Disables dependency metadata when building APKs.
|
||||
includeInApk = false
|
||||
// Disables dependency metadata when building Android App Bundles.
|
||||
includeInBundle = false
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.yoshi.rain"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion flutter.targetSdkVersion
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
applicationId = 'com.yoshi.rain'
|
||||
minSdk = 23
|
||||
targetSdk = flutter.targetSdkVersion
|
||||
versionCode = flutter.versionCode
|
||||
versionName = flutter.versionName
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release {
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
keyPassword keystoreProperties['keyPassword']
|
||||
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||
storePassword keystoreProperties['storePassword']
|
||||
release {
|
||||
keyAlias = keystoreProperties['keyAlias']
|
||||
keyPassword = keystoreProperties['keyPassword']
|
||||
storeFile = keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||
storePassword = keystoreProperties['storePassword']
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
signingConfig signingConfigs.release
|
||||
signingConfig = signingConfigs.release
|
||||
}
|
||||
|
||||
debug {
|
||||
signingConfig signingConfigs.debug
|
||||
minifyEnabled true
|
||||
signingConfig = signingConfigs.debug
|
||||
minifyEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
viewBinding = true
|
||||
}
|
||||
|
||||
namespace 'com.yoshi.rain'
|
||||
}
|
||||
|
||||
flutter {
|
||||
source '../..'
|
||||
source = "../.."
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "androidx.core:core-remoteviews:1.0.0"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation("androidx.core:core-remoteviews:1.1.0")
|
||||
implementation("com.google.android.material:material:1.12.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
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
@ -12,16 +11,6 @@
|
|||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
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
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
|
@ -29,6 +18,7 @@
|
|||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.NormalTheme"
|
||||
|
@ -37,7 +27,32 @@
|
|||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="es.antonborri.home_widget.action.LAUNCH" />
|
||||
</intent-filter>
|
||||
</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
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
|
@ -53,4 +68,4 @@
|
|||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 5.3 KiB |
|
@ -3,6 +3,7 @@
|
|||
style="@style/Widget.Android.AppWidget.Container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSecondaryContainer"
|
||||
android:theme="@style/Theme.Android.AppWidgetContainer"
|
||||
android:id="@+id/widget_day_oreo">
|
||||
|
||||
|
@ -27,7 +28,7 @@
|
|||
android:shadowRadius="1"
|
||||
android:textSize="@dimen/widget_large_title_text_size"
|
||||
tools:ignore="ObsoleteLayoutParam"
|
||||
tools:text="Saturday, September 30 │ " />
|
||||
tools:text="Saturday, September 30 " />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/widget_day_icon"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
style="@style/Widget.Android.AppWidget.Container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSecondaryContainer"
|
||||
android:theme="@style/Theme.Android.AppWidgetContainer"
|
||||
android:id="@+id/widget_day_oreo">
|
||||
|
||||
|
@ -27,7 +28,7 @@
|
|||
android:shadowRadius="1"
|
||||
android:textSize="@dimen/widget_large_title_text_size"
|
||||
tools:ignore="ObsoleteLayoutParam"
|
||||
tools:text="Saturday, September 30 │ " />
|
||||
tools:text="Saturday, September 30 " />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/widget_day_icon"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
style="@style/Widget.Android.AppWidget.Container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSecondaryContainer"
|
||||
android:theme="@style/Theme.Android.AppWidgetContainer"
|
||||
android:id="@+id/widget_day_oreo">
|
||||
|
||||
|
@ -32,8 +33,8 @@
|
|||
android:shadowRadius="1"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Large"
|
||||
android:textSize="@dimen/widget_title_text_size"
|
||||
tools:text="21°"
|
||||
tools:ignore="ObsoleteLayoutParam" />
|
||||
tools:ignore="ObsoleteLayoutParam"
|
||||
tools:text="21°" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
style="@style/Widget.Android.AppWidget.Container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSecondaryContainer"
|
||||
android:theme="@style/Theme.Android.AppWidgetContainer"
|
||||
android:id="@+id/widget_day_oreo">
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<style name="LaunchTheme" parent="@style/Theme.Material3.DynamicColors.Dark.NoActionBar">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
|
@ -14,7 +14,7 @@
|
|||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<style name="NormalTheme" parent="@style/Theme.Material3.DynamicColors.Dark.NoActionBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<!--
|
||||
Having themes.xml for night-v31 because of the priority order of the resource qualifiers.
|
||||
-->
|
||||
<style name="Theme.Android.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault.DayNight">
|
||||
<style name="Theme.Android.AppWidgetContainerParent" parent="@style/Theme.Material3.DynamicColors.DayNight">
|
||||
<item name="appWidgetRadius">@android:dimen/system_app_widget_background_radius</item>
|
||||
<item name="appWidgetInnerRadius">@android:dimen/system_app_widget_inner_radius</item>
|
||||
</style>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<style name="LaunchTheme" parent="@style/Theme.Material3.DynamicColors.Dark.NoActionBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:forceDarkAllowed" tools:targetApi="q">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds" >false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="o_mr1">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
|
@ -16,7 +16,7 @@
|
|||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||
<style name="NormalTheme" parent="@style/Theme.Material3.DynamicColors.Dark.NoActionBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<style name="LaunchTheme" parent="@style/Theme.Material3.DynamicColors.DayNight.NoActionBar">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
|
@ -14,17 +14,15 @@
|
|||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<style name="NormalTheme" parent="@style/Theme.Material3.DynamicColors.DayNight.NoActionBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Android.AppWidget.Container" parent="android:Widget">
|
||||
<item name="android:id">@android:id/background</item>
|
||||
<item name="android:padding">?attr/appWidgetPadding</item>
|
||||
<item name="android:background">@drawable/app_widget_background</item>
|
||||
<item name="android:clipToOutline">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Android.AppWidget.InnerView" parent="android:Widget">
|
||||
<item name="android:padding">?attr/appWidgetPadding</item>
|
||||
<item name="android:background">@drawable/app_widget_inner_view_background</item>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
and @android:dimen/system_app_widget_internal_padding requires API level 31
|
||||
-->
|
||||
<style name="Theme.Android.AppWidgetContainerParent"
|
||||
parent="@android:style/Theme.DeviceDefault.DayNight">
|
||||
parent="@style/Theme.Material3.DynamicColors.DayNight">
|
||||
<item name="appWidgetRadius">@android:dimen/system_app_widget_background_radius</item>
|
||||
<item name="appWidgetInnerRadius">@android:dimen/system_app_widget_inner_radius</item>
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_widget_description">Oreo Widget</string>
|
||||
<string name="app_widget_description">Rain Widget</string>
|
||||
<string name="date_format_widget_oreo_style">EEE, d MMM │</string>
|
||||
<string name="date_format_widget_oreo_big_style">EEEE, d MMM │</string>
|
||||
</resources>
|
|
@ -2,14 +2,14 @@
|
|||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode
|
||||
setting is off -->
|
||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<style name="LaunchTheme" parent="@style/Theme.Material3.DynamicColors.DayNight.NoActionBar">
|
||||
<!-- Show a splash screen on the activity. Automatically removed when
|
||||
the Flutter engine draws its first frame -->
|
||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||
<item name="android:forceDarkAllowed" tools:ignore="NewApi">false</item>
|
||||
<item name="android:forceDarkAllowed" tools:targetApi="q">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:ignore="NewApi">shortEdges</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="o_mr1">shortEdges</item>
|
||||
</style>
|
||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||
This theme determines the color of the Android Window while your
|
||||
|
@ -17,18 +17,15 @@
|
|||
running.
|
||||
|
||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||
<style name="NormalTheme" parent="@style/Theme.Material3.DynamicColors.DayNight.NoActionBar">
|
||||
<item name="android:windowBackground">?android:colorBackground</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Android.AppWidget.Container" parent="android:Widget">
|
||||
<item name="android:id">@android:id/background</item>
|
||||
<item name="android:background">?android:attr/colorBackground</item>
|
||||
<item name="android:background">?attr/colorSurface</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Android.AppWidget.InnerView" parent="android:Widget">
|
||||
<item name="android:background">?android:attr/colorBackground</item>
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
<item name="android:background">?attr/colorSurface</item>
|
||||
<item name="android:textColor">?attr/itemTextColor</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<resources>
|
||||
<style name="Theme.Android.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault">
|
||||
<style name="Theme.Android.AppWidgetContainerParent" parent="@style/Theme.Material3.DynamicColors.DayNight">
|
||||
<!-- Radius of the outer bound of widgets to make the rounded corners -->
|
||||
<item name="appWidgetRadius">16dp</item>
|
||||
<!--
|
||||
|
|
|
@ -1,16 +1,3 @@
|
|||
buildscript {
|
||||
ext.kotlin_version = '1.9.10'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
|
@ -21,6 +8,8 @@ allprojects {
|
|||
rootProject.buildDir = '../build'
|
||||
subprojects {
|
||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
||||
}
|
||||
subprojects {
|
||||
project.evaluationDependsOn(':app')
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
org.gradle.jvmargs=-Xmx1536M
|
||||
org.gradle.jvmargs=-Xmx4G
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.enableR8.fullMode = false
|
||||
|
|
|
@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
|
||||
|
|
|
@ -1,11 +1,25 @@
|
|||
include ':app'
|
||||
pluginManagement {
|
||||
def flutterSdkPath = {
|
||||
def properties = new Properties()
|
||||
file("local.properties").withInputStream { properties.load(it) }
|
||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||
return flutterSdkPath
|
||||
}()
|
||||
|
||||
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
|
||||
def properties = new Properties()
|
||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
|
||||
assert localPropertiesFile.exists()
|
||||
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
def flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
|
||||
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "8.9.0" apply false
|
||||
id "org.jetbrains.kotlin.android" version "2.1.10" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
|
BIN
assets/icons/City.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
assets/icons/Design.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
assets/icons/Rain.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
assets/icons/Team.png
Normal file
After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 452 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 4 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 3 KiB After Width: | Height: | Size: 1,011 B |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 912 B |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 336 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 4 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 5.3 KiB |
|
@ -25,11 +25,11 @@
|
|||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>The Rain App requires access to the device's location.</string>
|
||||
<string>The Rain App requires access to the device's location.</string>
|
||||
<key>NSLocationTemporaryUsageDescriptionDictionary</key>
|
||||
<dict>
|
||||
<key>TemporaryPreciseAccuracy</key>
|
||||
<string>The Rain App requires temporary access to the device's precise location.</string>
|
||||
<string>The Rain App requires temporary access to the device's precise location.</string>
|
||||
</dict>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
|
|
12
ios/RunnerTests/RunnerTests.swift
Normal 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.
|
||||
}
|
||||
|
||||
}
|
237
lib/app/api/api.dart
Normal file → Executable file
|
@ -1,66 +1,38 @@
|
|||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rain/app/api/city.dart';
|
||||
import 'package:rain/app/api/weather.dart';
|
||||
import 'package:rain/app/data/weather.dart';
|
||||
import 'package:rain/app/api/city_api.dart';
|
||||
import 'package:rain/app/api/weather_api.dart';
|
||||
import 'package:rain/app/data/db.dart';
|
||||
import 'package:rain/main.dart';
|
||||
|
||||
class WeatherAPI {
|
||||
final Dio dio = Dio()..options.baseUrl = 'https://api.open-meteo.com/v1/forecast?';
|
||||
final Dio dio =
|
||||
Dio()..options.baseUrl = 'https://api.open-meteo.com/v1/forecast?';
|
||||
final Dio dioLocation = Dio();
|
||||
|
||||
Future<MainWeatherCache> getWeatherData(double? lat, double? lon) async {
|
||||
String url =
|
||||
'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 urlWeather;
|
||||
settings.measurements == 'imperial' && settings.degrees == 'fahrenheit'
|
||||
? urlWeather = '$url&temperature_unit=fahrenheit&windspeed_unit=mph&precipitation_unit=inch'
|
||||
: settings.measurements == 'imperial'
|
||||
? urlWeather = '$url&windspeed_unit=mph&precipitation_unit=inch'
|
||||
: settings.degrees == 'fahrenheit'
|
||||
? urlWeather = '$url&temperature_unit=fahrenheit'
|
||||
: urlWeather = url;
|
||||
static const String _weatherParams =
|
||||
'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 _buildWeatherUrl(double lat, double lon) {
|
||||
String url = 'latitude=$lat&longitude=$lon&$_weatherParams';
|
||||
if (settings.measurements == 'imperial') {
|
||||
url += '&windspeed_unit=mph&precipitation_unit=inch';
|
||||
}
|
||||
if (settings.degrees == 'fahrenheit') {
|
||||
url += '&temperature_unit=fahrenheit';
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
Future<MainWeatherCache> getWeatherData(double lat, double lon) async {
|
||||
final String urlWeather = _buildWeatherUrl(lat, lon);
|
||||
try {
|
||||
Response response = await dio.get(urlWeather);
|
||||
WeatherDataApi weatherData = WeatherDataApi.fromJson(response.data);
|
||||
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(),
|
||||
);
|
||||
return _mapWeatherDataToCache(weatherData);
|
||||
} on DioException catch (e) {
|
||||
if (kDebugMode) {
|
||||
print(e);
|
||||
|
@ -69,60 +41,24 @@ class WeatherAPI {
|
|||
}
|
||||
}
|
||||
|
||||
Future<WeatherCard> getWeatherCard(double? lat, double? lon, String city, String district, String timezone) async {
|
||||
String url =
|
||||
'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 urlWeather;
|
||||
settings.measurements == 'imperial' && settings.degrees == 'fahrenheit'
|
||||
? urlWeather = '$url&temperature_unit=fahrenheit&windspeed_unit=mph&precipitation_unit=inch'
|
||||
: settings.measurements == 'imperial'
|
||||
? urlWeather = '$url&windspeed_unit=mph&precipitation_unit=inch'
|
||||
: settings.degrees == 'fahrenheit'
|
||||
? urlWeather = '$url&temperature_unit=fahrenheit'
|
||||
: urlWeather = url;
|
||||
Future<WeatherCard> getWeatherCard(
|
||||
double lat,
|
||||
double lon,
|
||||
String city,
|
||||
String district,
|
||||
String timezone,
|
||||
) async {
|
||||
final String urlWeather = _buildWeatherUrl(lat, lon);
|
||||
try {
|
||||
Response response = await dio.get(urlWeather);
|
||||
WeatherDataApi weatherData = WeatherDataApi.fromJson(response.data);
|
||||
return 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(),
|
||||
return _mapWeatherDataToCard(
|
||||
weatherData,
|
||||
lat,
|
||||
lon,
|
||||
city,
|
||||
district,
|
||||
timezone,
|
||||
);
|
||||
} on DioException catch (e) {
|
||||
if (kDebugMode) {
|
||||
|
@ -133,7 +69,7 @@ class WeatherAPI {
|
|||
}
|
||||
|
||||
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';
|
||||
try {
|
||||
Response response = await dioLocation.get(url);
|
||||
|
@ -157,4 +93,97 @@ class WeatherAPI {
|
|||
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
|
@ -1,15 +1,14 @@
|
|||
class CityApi {
|
||||
CityApi({
|
||||
required this.results,
|
||||
});
|
||||
CityApi({required this.results});
|
||||
|
||||
List<Result> results;
|
||||
|
||||
factory CityApi.fromJson(Map<String, dynamic> json) => CityApi(
|
||||
results: json['results'] == null
|
||||
results:
|
||||
json['results'] == null
|
||||
? List<Result>.empty()
|
||||
: List<Result>.from(json['results'].map((x) => Result.fromJson(x))),
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
class Result {
|
||||
|
@ -26,9 +25,9 @@ class Result {
|
|||
double longitude;
|
||||
|
||||
factory Result.fromJson(Map<String, dynamic> json) => Result(
|
||||
admin1: json['admin1'] ?? '',
|
||||
name: json['name'],
|
||||
latitude: json['latitude'],
|
||||
longitude: json['longitude'],
|
||||
);
|
||||
admin1: json['admin1'] ?? '',
|
||||
name: json['name'],
|
||||
latitude: json['latitude'],
|
||||
longitude: json['longitude'],
|
||||
);
|
||||
}
|
25
lib/app/api/weather.dart → lib/app/api/weather_api.dart
Normal file → Executable file
|
@ -2,8 +2,8 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
|||
|
||||
//ignore_for_file: invalid_annotation_target
|
||||
|
||||
part 'weather.freezed.dart';
|
||||
part 'weather.g.dart';
|
||||
part 'weather_api.freezed.dart';
|
||||
part 'weather_api.g.dart';
|
||||
|
||||
@freezed
|
||||
class WeatherDataApi with _$WeatherDataApi {
|
||||
|
@ -13,7 +13,8 @@ class WeatherDataApi with _$WeatherDataApi {
|
|||
required String timezone,
|
||||
}) = _WeatherDataApi;
|
||||
|
||||
factory WeatherDataApi.fromJson(Map<String, dynamic> json) => _$WeatherDataApiFromJson(json);
|
||||
factory WeatherDataApi.fromJson(Map<String, dynamic> json) =>
|
||||
_$WeatherDataApiFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -35,14 +36,16 @@ class Hourly with _$Hourly {
|
|||
@JsonKey(name: 'cloudcover') List<int?>? cloudCover,
|
||||
@JsonKey(name: 'uv_index') List<double?>? uvIndex,
|
||||
@JsonKey(name: 'dewpoint_2m') List<double?>? dewpoint2M,
|
||||
@JsonKey(name: 'precipitation_probability') List<int?>? precipitationProbability,
|
||||
@JsonKey(name: 'precipitation_probability')
|
||||
List<int?>? precipitationProbability,
|
||||
@JsonKey(name: 'shortwave_radiation') List<double?>? shortwaveRadiation,
|
||||
}) = _Hourly;
|
||||
|
||||
factory Hourly.fromJson(Map<String, dynamic> json) => _$HourlyFromJson(json);
|
||||
}
|
||||
|
||||
List<DateTime> _dateTimeFromJson(List<dynamic>? json) => json?.map((x) => DateTime.parse(x)).toList() ?? [];
|
||||
List<DateTime> _dateTimeFromJson(List<dynamic>? json) =>
|
||||
json?.map((x) => DateTime.parse(x)).toList() ?? [];
|
||||
|
||||
@freezed
|
||||
class Daily with _$Daily {
|
||||
|
@ -51,17 +54,21 @@ class Daily with _$Daily {
|
|||
@JsonKey(name: 'weathercode') List<int?>? weatherCode,
|
||||
@JsonKey(name: 'temperature_2m_max') List<double?>? temperature2MMax,
|
||||
@JsonKey(name: 'temperature_2m_min') List<double?>? temperature2MMin,
|
||||
@JsonKey(name: 'apparent_temperature_max') List<double?>? apparentTemperatureMax,
|
||||
@JsonKey(name: 'apparent_temperature_min') List<double?>? apparentTemperatureMin,
|
||||
@JsonKey(name: 'apparent_temperature_max')
|
||||
List<double?>? apparentTemperatureMax,
|
||||
@JsonKey(name: 'apparent_temperature_min')
|
||||
List<double?>? apparentTemperatureMin,
|
||||
@JsonKey(name: 'precipitation_sum') List<double?>? precipitationSum,
|
||||
List<String>? sunrise,
|
||||
List<String>? sunset,
|
||||
@JsonKey(name: 'precipitation_probability_max') List<int?>? precipitationProbabilityMax,
|
||||
@JsonKey(name: 'precipitation_probability_max')
|
||||
List<int?>? precipitationProbabilityMax,
|
||||
@JsonKey(name: 'windspeed_10m_max') List<double?>? windSpeed10MMax,
|
||||
@JsonKey(name: 'windgusts_10m_max') List<double?>? windGusts10MMax,
|
||||
@JsonKey(name: 'uv_index_max') List<double?>? uvIndexMax,
|
||||
@JsonKey(name: 'rain_sum') List<double?>? rainSum,
|
||||
@JsonKey(name: 'winddirection_10m_dominant') List<int?>? windDirection10MDominant,
|
||||
@JsonKey(name: 'winddirection_10m_dominant')
|
||||
List<int?>? windDirection10MDominant,
|
||||
}) = _Daily;
|
||||
|
||||
factory Daily.fromJson(Map<String, dynamic> json) => _$DailyFromJson(json);
|
77
lib/app/api/weather.freezed.dart → lib/app/api/weather_api.freezed.dart
Normal file → Executable file
|
@ -3,7 +3,7 @@
|
|||
// 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
|
||||
|
||||
part of 'weather.dart';
|
||||
part of 'weather_api.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
|
@ -12,7 +12,7 @@ part of 'weather.dart';
|
|||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
WeatherDataApi _$WeatherDataApiFromJson(Map<String, dynamic> json) {
|
||||
return _WeatherDataApi.fromJson(json);
|
||||
|
@ -24,8 +24,12 @@ mixin _$WeatherDataApi {
|
|||
Daily get daily => throw _privateConstructorUsedError;
|
||||
String get timezone => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this WeatherDataApi to a JSON map.
|
||||
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 =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
@ -52,6 +56,8 @@ class _$WeatherDataApiCopyWithImpl<$Res, $Val extends WeatherDataApi>
|
|||
// ignore: unused_field
|
||||
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')
|
||||
@override
|
||||
$Res call({
|
||||
|
@ -75,6 +81,8 @@ class _$WeatherDataApiCopyWithImpl<$Res, $Val extends WeatherDataApi>
|
|||
) as $Val);
|
||||
}
|
||||
|
||||
/// Create a copy of WeatherDataApi
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$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
|
||||
@pragma('vm:prefer-inline')
|
||||
$DailyCopyWith<$Res> get daily {
|
||||
|
@ -116,6 +126,8 @@ class __$$WeatherDataApiImplCopyWithImpl<$Res>
|
|||
_$WeatherDataApiImpl _value, $Res Function(_$WeatherDataApiImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of WeatherDataApi
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
|
@ -162,7 +174,7 @@ class _$WeatherDataApiImpl implements _WeatherDataApi {
|
|||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$WeatherDataApiImpl &&
|
||||
|
@ -172,11 +184,13 @@ class _$WeatherDataApiImpl implements _WeatherDataApi {
|
|||
other.timezone == timezone));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
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
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$WeatherDataApiImplCopyWith<_$WeatherDataApiImpl> get copyWith =>
|
||||
|
@ -206,8 +220,11 @@ abstract class _WeatherDataApi implements WeatherDataApi {
|
|||
Daily get daily;
|
||||
@override
|
||||
String get timezone;
|
||||
|
||||
/// Create a copy of WeatherDataApi
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$WeatherDataApiImplCopyWith<_$WeatherDataApiImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
@ -251,8 +268,12 @@ mixin _$Hourly {
|
|||
@JsonKey(name: 'shortwave_radiation')
|
||||
List<double?>? get shortwaveRadiation => throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this Hourly to a JSON map.
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -293,6 +314,8 @@ class _$HourlyCopyWithImpl<$Res, $Val extends Hourly>
|
|||
// ignore: unused_field
|
||||
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')
|
||||
@override
|
||||
$Res call({
|
||||
|
@ -429,6 +452,8 @@ class __$$HourlyImplCopyWithImpl<$Res>
|
|||
_$HourlyImpl _value, $Res Function(_$HourlyImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of Hourly
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
|
@ -781,7 +806,7 @@ class _$HourlyImpl implements _Hourly {
|
|||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$HourlyImpl &&
|
||||
|
@ -820,7 +845,7 @@ class _$HourlyImpl implements _Hourly {
|
|||
.equals(other._shortwaveRadiation, _shortwaveRadiation));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
|
@ -843,7 +868,9 @@ class _$HourlyImpl implements _Hourly {
|
|||
const DeepCollectionEquality().hash(_precipitationProbability),
|
||||
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
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$HourlyImplCopyWith<_$HourlyImpl> get copyWith =>
|
||||
|
@ -933,8 +960,11 @@ abstract class _Hourly implements Hourly {
|
|||
@override
|
||||
@JsonKey(name: 'shortwave_radiation')
|
||||
List<double?>? get shortwaveRadiation;
|
||||
|
||||
/// Create a copy of Hourly
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$HourlyImplCopyWith<_$HourlyImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
@ -978,8 +1008,12 @@ mixin _$Daily {
|
|||
List<int?>? get windDirection10MDominant =>
|
||||
throw _privateConstructorUsedError;
|
||||
|
||||
/// Serializes this Daily to a JSON map.
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1020,6 +1054,8 @@ class _$DailyCopyWithImpl<$Res, $Val extends Daily>
|
|||
// ignore: unused_field
|
||||
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')
|
||||
@override
|
||||
$Res call({
|
||||
|
@ -1141,6 +1177,8 @@ class __$$DailyImplCopyWithImpl<$Res>
|
|||
_$DailyImpl _value, $Res Function(_$DailyImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
/// Create a copy of Daily
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
|
@ -1445,7 +1483,7 @@ class _$DailyImpl implements _Daily {
|
|||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$DailyImpl &&
|
||||
|
@ -1478,7 +1516,7 @@ class _$DailyImpl implements _Daily {
|
|||
other._windDirection10MDominant, _windDirection10MDominant));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
|
@ -1498,7 +1536,9 @@ class _$DailyImpl implements _Daily {
|
|||
const DeepCollectionEquality().hash(_rainSum),
|
||||
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
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$DailyImplCopyWith<_$DailyImpl> get copyWith =>
|
||||
|
@ -1581,8 +1621,11 @@ abstract class _Daily implements Daily {
|
|||
@override
|
||||
@JsonKey(name: 'winddirection_10m_dominant')
|
||||
List<int?>? get windDirection10MDominant;
|
||||
|
||||
/// Create a copy of Daily
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$DailyImplCopyWith<_$DailyImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
18
lib/app/api/weather.g.dart → lib/app/api/weather_api.g.dart
Normal file → Executable file
|
@ -1,6 +1,6 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'weather.dart';
|
||||
part of 'weather_api.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
|
@ -24,7 +24,7 @@ Map<String, dynamic> _$$WeatherDataApiImplToJson(
|
|||
_$HourlyImpl _$$HourlyImplFromJson(Map<String, dynamic> json) => _$HourlyImpl(
|
||||
time: (json['time'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||
weatherCode: (json['weathercode'] as List<dynamic>?)
|
||||
?.map((e) => e as int)
|
||||
?.map((e) => (e as num).toInt())
|
||||
.toList(),
|
||||
temperature2M: (json['temperature_2m'] as List<dynamic>?)
|
||||
?.map((e) => (e as num).toDouble())
|
||||
|
@ -39,7 +39,7 @@ _$HourlyImpl _$$HourlyImplFromJson(Map<String, dynamic> json) => _$HourlyImpl(
|
|||
?.map((e) => (e as num?)?.toDouble())
|
||||
.toList(),
|
||||
relativeHumidity2M: (json['relativehumidity_2m'] as List<dynamic>?)
|
||||
?.map((e) => e as int?)
|
||||
?.map((e) => (e as num?)?.toInt())
|
||||
.toList(),
|
||||
surfacePressure: (json['surface_pressure'] as List<dynamic>?)
|
||||
?.map((e) => (e as num?)?.toDouble())
|
||||
|
@ -54,13 +54,13 @@ _$HourlyImpl _$$HourlyImplFromJson(Map<String, dynamic> json) => _$HourlyImpl(
|
|||
?.map((e) => (e as num?)?.toDouble())
|
||||
.toList(),
|
||||
windDirection10M: (json['winddirection_10m'] as List<dynamic>?)
|
||||
?.map((e) => e as int?)
|
||||
?.map((e) => (e as num?)?.toInt())
|
||||
.toList(),
|
||||
windGusts10M: (json['windgusts_10m'] as List<dynamic>?)
|
||||
?.map((e) => (e as num?)?.toDouble())
|
||||
.toList(),
|
||||
cloudCover: (json['cloudcover'] as List<dynamic>?)
|
||||
?.map((e) => e as int?)
|
||||
?.map((e) => (e as num?)?.toInt())
|
||||
.toList(),
|
||||
uvIndex: (json['uv_index'] as List<dynamic>?)
|
||||
?.map((e) => (e as num?)?.toDouble())
|
||||
|
@ -70,7 +70,7 @@ _$HourlyImpl _$$HourlyImplFromJson(Map<String, dynamic> json) => _$HourlyImpl(
|
|||
.toList(),
|
||||
precipitationProbability:
|
||||
(json['precipitation_probability'] as List<dynamic>?)
|
||||
?.map((e) => e as int?)
|
||||
?.map((e) => (e as num?)?.toInt())
|
||||
.toList(),
|
||||
shortwaveRadiation: (json['shortwave_radiation'] as List<dynamic>?)
|
||||
?.map((e) => (e as num?)?.toDouble())
|
||||
|
@ -102,7 +102,7 @@ Map<String, dynamic> _$$HourlyImplToJson(_$HourlyImpl instance) =>
|
|||
_$DailyImpl _$$DailyImplFromJson(Map<String, dynamic> json) => _$DailyImpl(
|
||||
time: _dateTimeFromJson(json['time'] as List?),
|
||||
weatherCode: (json['weathercode'] as List<dynamic>?)
|
||||
?.map((e) => e as int?)
|
||||
?.map((e) => (e as num?)?.toInt())
|
||||
.toList(),
|
||||
temperature2MMax: (json['temperature_2m_max'] as List<dynamic>?)
|
||||
?.map((e) => (e as num?)?.toDouble())
|
||||
|
@ -127,7 +127,7 @@ _$DailyImpl _$$DailyImplFromJson(Map<String, dynamic> json) => _$DailyImpl(
|
|||
(json['sunset'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||
precipitationProbabilityMax:
|
||||
(json['precipitation_probability_max'] as List<dynamic>?)
|
||||
?.map((e) => e as int?)
|
||||
?.map((e) => (e as num?)?.toInt())
|
||||
.toList(),
|
||||
windSpeed10MMax: (json['windspeed_10m_max'] as List<dynamic>?)
|
||||
?.map((e) => (e as num?)?.toDouble())
|
||||
|
@ -143,7 +143,7 @@ _$DailyImpl _$$DailyImplFromJson(Map<String, dynamic> json) => _$DailyImpl(
|
|||
.toList(),
|
||||
windDirection10MDominant:
|
||||
(json['winddirection_10m_dominant'] as List<dynamic>?)
|
||||
?.map((e) => e as int?)
|
||||
?.map((e) => (e as num?)?.toInt())
|
||||
.toList(),
|
||||
);
|
||||
|
430
lib/app/controller/controller.dart
Normal file → Executable file
|
@ -1,7 +1,6 @@
|
|||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:flutter_timezone/flutter_timezone.dart';
|
||||
import 'package:geocoding/geocoding.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
|
@ -11,16 +10,17 @@ import 'package:isar/isar.dart';
|
|||
import 'package:lat_lng_to_timezone/lat_lng_to_timezone.dart' as tzmap;
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:rain/app/api/api.dart';
|
||||
import 'package:rain/app/data/weather.dart';
|
||||
import 'package:rain/app/services/notification.dart';
|
||||
import 'package:rain/app/services/utils.dart';
|
||||
import 'package:rain/app/widgets/status/status_data.dart';
|
||||
import 'package:rain/app/widgets/status/status_weather.dart';
|
||||
import 'package:rain/app/data/db.dart';
|
||||
import 'package:rain/app/utils/notification.dart';
|
||||
import 'package:rain/app/utils/show_snack_bar.dart';
|
||||
import 'package:rain/app/ui/widgets/weather/status/status_data.dart';
|
||||
import 'package:rain/app/ui/widgets/weather/status/status_weather.dart';
|
||||
import 'package:rain/main.dart';
|
||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
import 'package:timezone/data/latest_all.dart' as tz;
|
||||
import 'package:timezone/standalone.dart' as tz;
|
||||
import 'package:timezone/timezone.dart' as tz;
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:workmanager/workmanager.dart';
|
||||
|
||||
class WeatherController extends GetxController {
|
||||
|
@ -52,15 +52,14 @@ class WeatherController extends GetxController {
|
|||
|
||||
@override
|
||||
void onInit() {
|
||||
weatherCards
|
||||
.assignAll(isar.weatherCards.where().sortByIndex().findAllSync());
|
||||
weatherCards.assignAll(
|
||||
isar.weatherCards.where().sortByIndex().findAllSync(),
|
||||
);
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
Future<Position> determinePosition() async {
|
||||
LocationPermission permission;
|
||||
|
||||
permission = await Geolocator.checkPermission();
|
||||
Future<Position> _determinePosition() async {
|
||||
LocationPermission permission = await Geolocator.checkPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
permission = await Geolocator.requestPermission();
|
||||
if (permission == LocationPermission.denied) {
|
||||
|
@ -70,35 +69,36 @@ class WeatherController extends GetxController {
|
|||
|
||||
if (permission == LocationPermission.deniedForever) {
|
||||
return Future.error(
|
||||
'Location permissions are permanently denied, we cannot request permissions.');
|
||||
'Location permissions are permanently denied, we cannot request permissions.',
|
||||
);
|
||||
}
|
||||
return await Geolocator.getCurrentPosition(
|
||||
desiredAccuracy: LocationAccuracy.high);
|
||||
return await Geolocator.getCurrentPosition();
|
||||
}
|
||||
|
||||
Future<void> setLocation() async {
|
||||
if (settings.location) {
|
||||
await getCurrentLocation();
|
||||
} else {
|
||||
if ((isar.locationCaches.where().findAllSync()).isNotEmpty) {
|
||||
LocationCache locationCity =
|
||||
(isar.locationCaches.where().findFirstSync())!;
|
||||
await getLocation(locationCity.lat!, locationCity.lon!,
|
||||
locationCity.district!, locationCity.city!);
|
||||
final locationCity = isar.locationCaches.where().findFirstSync();
|
||||
if (locationCity != null) {
|
||||
await getLocation(
|
||||
locationCity.lat!,
|
||||
locationCity.lon!,
|
||||
locationCity.district!,
|
||||
locationCity.city!,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> getCurrentLocation() async {
|
||||
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||
|
||||
if (!isOnline) {
|
||||
if (!(await isOnline.value)) {
|
||||
showSnackBar(content: 'no_inter'.tr);
|
||||
await readCache();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!serviceEnabled) {
|
||||
if (!await Geolocator.isLocationServiceEnabled()) {
|
||||
showSnackBar(
|
||||
content: 'no_location'.tr,
|
||||
onPressed: () => Geolocator.openLocationSettings(),
|
||||
|
@ -107,39 +107,73 @@ class WeatherController extends GetxController {
|
|||
return;
|
||||
}
|
||||
|
||||
if ((isar.mainWeatherCaches.where().findAllSync()).isNotEmpty) {
|
||||
if (isar.mainWeatherCaches.where().findAllSync().isNotEmpty) {
|
||||
await readCache();
|
||||
return;
|
||||
}
|
||||
|
||||
Position position = await determinePosition();
|
||||
List<Placemark> placemarks =
|
||||
await placemarkFromCoordinates(position.latitude, position.longitude);
|
||||
Placemark place = placemarks[0];
|
||||
final position = await _determinePosition();
|
||||
final placemarks = await placemarkFromCoordinates(
|
||||
position.latitude,
|
||||
position.longitude,
|
||||
);
|
||||
final place = placemarks[0];
|
||||
|
||||
_latitude.value = position.latitude;
|
||||
_longitude.value = position.longitude;
|
||||
_district.value = '${place.administrativeArea}';
|
||||
_city.value = '${place.locality}';
|
||||
_district.value = place.administrativeArea ?? '';
|
||||
_city.value = place.locality ?? '';
|
||||
|
||||
_mainWeather.value =
|
||||
await WeatherAPI().getWeatherData(_latitude.value, _longitude.value);
|
||||
_mainWeather.value = await WeatherAPI().getWeatherData(
|
||||
_latitude.value,
|
||||
_longitude.value,
|
||||
);
|
||||
|
||||
notificationCheck();
|
||||
|
||||
await writeCache();
|
||||
await readCache();
|
||||
}
|
||||
|
||||
Future<void> getLocation(double latitude, double longitude, String district,
|
||||
String locality) async {
|
||||
if (!isOnline) {
|
||||
Future<Map<String, dynamic>> getCurrentLocationSearch() async {
|
||||
if (!(await isOnline.value)) {
|
||||
showSnackBar(content: 'no_inter'.tr);
|
||||
}
|
||||
|
||||
if (!await Geolocator.isLocationServiceEnabled()) {
|
||||
showSnackBar(
|
||||
content: 'no_location'.tr,
|
||||
onPressed: () => Geolocator.openLocationSettings(),
|
||||
);
|
||||
}
|
||||
|
||||
final position = await _determinePosition();
|
||||
final placemarks = await placemarkFromCoordinates(
|
||||
position.latitude,
|
||||
position.longitude,
|
||||
);
|
||||
final place = placemarks[0];
|
||||
|
||||
return {
|
||||
'lat': position.latitude,
|
||||
'lon': position.longitude,
|
||||
'city': place.administrativeArea ?? '',
|
||||
'district': place.locality ?? '',
|
||||
};
|
||||
}
|
||||
|
||||
Future<void> getLocation(
|
||||
double latitude,
|
||||
double longitude,
|
||||
String district,
|
||||
String locality,
|
||||
) async {
|
||||
if (!(await isOnline.value)) {
|
||||
showSnackBar(content: 'no_inter'.tr);
|
||||
await readCache();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((isar.mainWeatherCaches.where().findAllSync()).isNotEmpty) {
|
||||
if (isar.mainWeatherCaches.where().findAllSync().isNotEmpty) {
|
||||
await readCache();
|
||||
return;
|
||||
}
|
||||
|
@ -149,11 +183,12 @@ class WeatherController extends GetxController {
|
|||
_district.value = district;
|
||||
_city.value = locality;
|
||||
|
||||
_mainWeather.value =
|
||||
await WeatherAPI().getWeatherData(_latitude.value, _longitude.value);
|
||||
_mainWeather.value = await WeatherAPI().getWeatherData(
|
||||
_latitude.value,
|
||||
_longitude.value,
|
||||
);
|
||||
|
||||
notificationCheck();
|
||||
|
||||
await writeCache();
|
||||
await readCache();
|
||||
}
|
||||
|
@ -170,10 +205,14 @@ class WeatherController extends GetxController {
|
|||
_mainWeather.value = mainWeatherCache;
|
||||
_location.value = locationCache;
|
||||
|
||||
hourOfDay.value =
|
||||
getTime(_mainWeather.value.time!, _mainWeather.value.timezone!);
|
||||
dayOfNow.value =
|
||||
getDay(_mainWeather.value.timeDaily!, _mainWeather.value.timezone!);
|
||||
hourOfDay.value = getTime(
|
||||
_mainWeather.value.time!,
|
||||
_mainWeather.value.timezone!,
|
||||
);
|
||||
dayOfNow.value = getDay(
|
||||
_mainWeather.value.timeDaily!,
|
||||
_mainWeather.value.timezone!,
|
||||
);
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
Workmanager().registerPeriodicTask(
|
||||
|
@ -204,23 +243,17 @@ class WeatherController extends GetxController {
|
|||
);
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
final mainWeatherCachesIsEmpty =
|
||||
(isar.mainWeatherCaches.where().findAllSync()).isEmpty;
|
||||
final locationCachesIsEmpty =
|
||||
(isar.locationCaches.where().findAllSync()).isEmpty;
|
||||
|
||||
if (mainWeatherCachesIsEmpty) {
|
||||
if (isar.mainWeatherCaches.where().findAllSync().isEmpty) {
|
||||
isar.mainWeatherCaches.putSync(_mainWeather.value);
|
||||
}
|
||||
|
||||
if (locationCachesIsEmpty) {
|
||||
if (isar.locationCaches.where().findAllSync().isEmpty) {
|
||||
isar.locationCaches.putSync(locationCaches);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> deleteCache() async {
|
||||
if (!isOnline) {
|
||||
if (!(await isOnline.value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -230,41 +263,49 @@ class WeatherController extends GetxController {
|
|||
.timestampLessThan(cacheExpiry)
|
||||
.deleteAllSync();
|
||||
});
|
||||
if ((isar.mainWeatherCaches.where().findAllSync()).isEmpty) {
|
||||
if (isar.mainWeatherCaches.where().findAllSync().isEmpty) {
|
||||
await flutterLocalNotificationsPlugin.cancelAll();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteAll(bool changeCity) async {
|
||||
if (!isOnline) {
|
||||
if (!(await isOnline.value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||
final serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||
await flutterLocalNotificationsPlugin.cancelAll();
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
if (!settings.location) {
|
||||
isar.mainWeatherCaches.where().deleteAllSync();
|
||||
}
|
||||
if ((settings.location && serviceEnabled) || changeCity) {
|
||||
if (settings.location && serviceEnabled || changeCity) {
|
||||
isar.mainWeatherCaches.where().deleteAllSync();
|
||||
isar.locationCaches.where().deleteAllSync();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Card Weather
|
||||
Future<void> addCardWeather(
|
||||
double latitude, double longitude, String city, String district) async {
|
||||
if (!isOnline) {
|
||||
double latitude,
|
||||
double longitude,
|
||||
String city,
|
||||
String district,
|
||||
) async {
|
||||
if (!(await isOnline.value)) {
|
||||
showSnackBar(content: 'no_inter'.tr);
|
||||
return;
|
||||
}
|
||||
|
||||
String tz = tzmap.latLngToTimezoneString(latitude, longitude);
|
||||
_weatherCard.value = await WeatherAPI()
|
||||
.getWeatherCard(latitude, longitude, city, district, tz);
|
||||
final tz = tzmap.latLngToTimezoneString(latitude, longitude);
|
||||
_weatherCard.value = await WeatherAPI().getWeatherCard(
|
||||
latitude,
|
||||
longitude,
|
||||
city,
|
||||
district,
|
||||
tz,
|
||||
);
|
||||
isar.writeTxnSync(() {
|
||||
weatherCards.add(_weatherCard.value);
|
||||
isar.weatherCards.putSync(_weatherCard.value);
|
||||
|
@ -272,120 +313,88 @@ class WeatherController extends GetxController {
|
|||
}
|
||||
|
||||
Future<void> updateCacheCard(bool refresh) async {
|
||||
List<WeatherCard> weatherCard = refresh
|
||||
final weatherCard = refresh
|
||||
? isar.weatherCards.where().sortByIndex().findAllSync()
|
||||
: isar.weatherCards
|
||||
.filter()
|
||||
.timestampLessThan(cacheExpiry)
|
||||
.sortByIndex()
|
||||
.findAllSync();
|
||||
.filter()
|
||||
.timestampLessThan(cacheExpiry)
|
||||
.sortByIndex()
|
||||
.findAllSync();
|
||||
|
||||
if (!isOnline || weatherCard.isEmpty) {
|
||||
if (!(await isOnline.value) || weatherCard.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var oldCard in weatherCard) {
|
||||
var updatedCard = await WeatherAPI().getWeatherCard(oldCard.lat,
|
||||
oldCard.lon, oldCard.city!, oldCard.district!, oldCard.timezone!);
|
||||
final updatedCard = await WeatherAPI().getWeatherCard(
|
||||
oldCard.lat!,
|
||||
oldCard.lon!,
|
||||
oldCard.city!,
|
||||
oldCard.district!,
|
||||
oldCard.timezone!,
|
||||
);
|
||||
isar.writeTxnSync(() {
|
||||
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);
|
||||
|
||||
var newCard = oldCard;
|
||||
int oldIdx = weatherCard.indexOf(oldCard);
|
||||
weatherCards[oldIdx] = newCard;
|
||||
_updateWeatherCard(oldCard, updatedCard);
|
||||
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 {
|
||||
if (!isOnline) {
|
||||
if (!(await isOnline.value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final updatedCard = await WeatherAPI().getWeatherCard(
|
||||
weatherCard.lat,
|
||||
weatherCard.lon,
|
||||
weatherCard.lat!,
|
||||
weatherCard.lon!,
|
||||
weatherCard.city!,
|
||||
weatherCard.district!,
|
||||
weatherCard.timezone!,
|
||||
);
|
||||
|
||||
isar.writeTxnSync(() {
|
||||
weatherCard
|
||||
..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);
|
||||
_updateWeatherCard(weatherCard, updatedCard);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -397,35 +406,26 @@ class WeatherController extends GetxController {
|
|||
}
|
||||
|
||||
int getTime(List<String> time, String timezone) {
|
||||
int getTime = 0;
|
||||
for (var i = 0; i < time.length; i++) {
|
||||
if (tz.TZDateTime.now(tz.getLocation(timezone)).hour ==
|
||||
DateTime.parse(time[i]).hour &&
|
||||
tz.TZDateTime.now(tz.getLocation(timezone)).day ==
|
||||
DateTime.parse(time[i]).day) {
|
||||
getTime = i;
|
||||
}
|
||||
}
|
||||
return getTime;
|
||||
return time.indexWhere((t) {
|
||||
final dateTime = DateTime.parse(t);
|
||||
return tz.TZDateTime.now(tz.getLocation(timezone)).hour ==
|
||||
dateTime.hour &&
|
||||
tz.TZDateTime.now(tz.getLocation(timezone)).day == dateTime.day;
|
||||
});
|
||||
}
|
||||
|
||||
int getDay(List<DateTime> time, String timezone) {
|
||||
int getDay = 0;
|
||||
for (var i = 0; i < time.length; i++) {
|
||||
if (tz.TZDateTime.now(tz.getLocation(timezone)).day == time[i].day) {
|
||||
getDay = i;
|
||||
}
|
||||
}
|
||||
return getDay;
|
||||
return time.indexWhere(
|
||||
(t) => tz.TZDateTime.now(tz.getLocation(timezone)).day == t.day,
|
||||
);
|
||||
}
|
||||
|
||||
TimeOfDay timeConvert(String normTime) {
|
||||
int hh = 0;
|
||||
if (normTime.endsWith('PM')) hh = 12;
|
||||
normTime = normTime.split(' ')[0];
|
||||
final hh = normTime.endsWith('PM') ? 12 : 0;
|
||||
final timeParts = normTime.split(' ')[0].split(':');
|
||||
return TimeOfDay(
|
||||
hour: hh + int.parse(normTime.split(':')[0]) % 24,
|
||||
minute: int.parse(normTime.split(':')[1]) % 60,
|
||||
hour: hh + int.parse(timeParts[0]) % 24,
|
||||
minute: int.parse(timeParts[1]) % 60,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -433,21 +433,21 @@ class WeatherController extends GetxController {
|
|||
final directory = await getTemporaryDirectory();
|
||||
final imagePath = '${directory.path}/$icon';
|
||||
|
||||
final ByteData data = await rootBundle.load('assets/images/$icon');
|
||||
final List<int> bytes = data.buffer.asUint8List();
|
||||
final data = await rootBundle.load('assets/images/$icon');
|
||||
final bytes = data.buffer.asUint8List();
|
||||
|
||||
await File(imagePath).writeAsBytes(bytes);
|
||||
|
||||
return imagePath;
|
||||
}
|
||||
|
||||
void notlification(MainWeatherCache mainWeatherCache) async {
|
||||
DateTime now = DateTime.now();
|
||||
int startHour = timeConvert(timeStart).hour;
|
||||
int endHour = timeConvert(timeEnd).hour;
|
||||
void notification(MainWeatherCache mainWeatherCache) async {
|
||||
final now = DateTime.now();
|
||||
final startHour = timeConvert(timeStart).hour;
|
||||
final endHour = timeConvert(timeEnd).hour;
|
||||
|
||||
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) &&
|
||||
notificationTime.hour >= startHour &&
|
||||
|
@ -474,15 +474,15 @@ class WeatherController extends GetxController {
|
|||
|
||||
void notificationCheck() async {
|
||||
if (settings.notifications) {
|
||||
final List<PendingNotificationRequest> pendingNotificationRequests =
|
||||
await flutterLocalNotificationsPlugin.pendingNotificationRequests();
|
||||
final pendingNotificationRequests = await flutterLocalNotificationsPlugin
|
||||
.pendingNotificationRequests();
|
||||
if (pendingNotificationRequests.isEmpty) {
|
||||
notlification(_mainWeather.value);
|
||||
notification(_mainWeather.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reorder(oldIndex, newIndex) {
|
||||
void reorder(int oldIndex, int newIndex) {
|
||||
if (newIndex > oldIndex) {
|
||||
newIndex -= 1;
|
||||
}
|
||||
|
@ -502,15 +502,11 @@ class WeatherController extends GetxController {
|
|||
isar.settings.putSync(settings);
|
||||
});
|
||||
|
||||
return Future.wait<bool?>([
|
||||
HomeWidget.saveWidgetData(
|
||||
'background_color',
|
||||
color,
|
||||
),
|
||||
final results = await Future.wait<bool?>([
|
||||
HomeWidget.saveWidgetData('background_color', color),
|
||||
HomeWidget.updateWidget(androidName: androidWidgetName),
|
||||
]).then((value) {
|
||||
return !value.contains(false);
|
||||
});
|
||||
]);
|
||||
return !results.contains(false);
|
||||
}
|
||||
|
||||
Future<bool> updateWidgetTextColor(String color) async {
|
||||
|
@ -519,15 +515,11 @@ class WeatherController extends GetxController {
|
|||
isar.settings.putSync(settings);
|
||||
});
|
||||
|
||||
return Future.wait<bool?>([
|
||||
HomeWidget.saveWidgetData(
|
||||
'text_color',
|
||||
color,
|
||||
),
|
||||
final results = await Future.wait<bool?>([
|
||||
HomeWidget.saveWidgetData('text_color', color),
|
||||
HomeWidget.updateWidget(androidName: androidWidgetName),
|
||||
]).then((value) {
|
||||
return !value.contains(false);
|
||||
});
|
||||
]);
|
||||
return !results.contains(false);
|
||||
}
|
||||
|
||||
Future<bool> updateWidget() async {
|
||||
|
@ -542,29 +534,39 @@ class WeatherController extends GetxController {
|
|||
WeatherCardSchema,
|
||||
], directory: (await getApplicationSupportDirectory()).path);
|
||||
|
||||
MainWeatherCache? mainWeatherCache;
|
||||
mainWeatherCache = isarWidget.mainWeatherCaches.where().findFirstSync();
|
||||
final mainWeatherCache = isarWidget.mainWeatherCaches
|
||||
.where()
|
||||
.findFirstSync();
|
||||
if (mainWeatherCache == null) return false;
|
||||
|
||||
int hour = getTime(mainWeatherCache.time!, mainWeatherCache.timezone!);
|
||||
int day = getDay(mainWeatherCache.timeDaily!, mainWeatherCache.timezone!);
|
||||
final hour = getTime(mainWeatherCache.time!, mainWeatherCache.timezone!);
|
||||
final day = getDay(mainWeatherCache.timeDaily!, mainWeatherCache.timezone!);
|
||||
|
||||
return Future.wait<bool?>([
|
||||
final results = await Future.wait<bool?>([
|
||||
HomeWidget.saveWidgetData(
|
||||
'weather_icon',
|
||||
await getLocalImagePath(StatusWeather().getImageNotification(
|
||||
'weather_icon',
|
||||
await getLocalImagePath(
|
||||
StatusWeather().getImageNotification(
|
||||
mainWeatherCache.weathercode![hour],
|
||||
mainWeatherCache.time![hour],
|
||||
mainWeatherCache.sunrise![day],
|
||||
mainWeatherCache.sunset![day],
|
||||
))),
|
||||
),
|
||||
),
|
||||
),
|
||||
HomeWidget.saveWidgetData(
|
||||
'weather_degree',
|
||||
'${mainWeatherCache.temperature2M?[hour].round()}°',
|
||||
),
|
||||
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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
204
lib/app/data/weather.dart → lib/app/data/db.dart
Normal file → Executable file
|
@ -1,6 +1,6 @@
|
|||
import 'package:isar/isar.dart';
|
||||
|
||||
part 'weather.g.dart';
|
||||
part 'db.g.dart';
|
||||
|
||||
@collection
|
||||
class Settings {
|
||||
|
@ -11,10 +11,15 @@ class Settings {
|
|||
bool notifications = false;
|
||||
bool materialColor = false;
|
||||
bool amoledTheme = false;
|
||||
bool roundDegree = false;
|
||||
bool largeElement = false;
|
||||
bool hideMap = false;
|
||||
String? widgetBackgroundColor;
|
||||
String? widgetTextColor;
|
||||
String measurements = 'metric';
|
||||
String degrees = 'celsius';
|
||||
String wind = 'kph';
|
||||
String pressure = 'hPa';
|
||||
String timeformat = '24';
|
||||
String? language;
|
||||
int? timeRange;
|
||||
|
@ -100,43 +105,43 @@ class MainWeatherCache {
|
|||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'time': time,
|
||||
'weathercode': weathercode,
|
||||
'temperature2M': temperature2M,
|
||||
'apparentTemperature': apparentTemperature,
|
||||
'relativehumidity2M': relativehumidity2M,
|
||||
'precipitation': precipitation,
|
||||
'rain': rain,
|
||||
'surfacePressure': surfacePressure,
|
||||
'visibility': visibility,
|
||||
'evapotranspiration': evapotranspiration,
|
||||
'windspeed10M': windspeed10M,
|
||||
'winddirection10M': winddirection10M,
|
||||
'windgusts10M': windgusts10M,
|
||||
'cloudcover': cloudcover,
|
||||
'uvIndex': uvIndex,
|
||||
'dewpoint2M': dewpoint2M,
|
||||
'precipitationProbability': precipitationProbability,
|
||||
'shortwaveRadiation': shortwaveRadiation,
|
||||
'timeDaily': timeDaily,
|
||||
'weathercodeDaily': weathercodeDaily,
|
||||
'temperature2MMax': temperature2MMax,
|
||||
'temperature2MMin': temperature2MMin,
|
||||
'apparentTemperatureMax': apparentTemperatureMax,
|
||||
'apparentTemperatureMin': apparentTemperatureMin,
|
||||
'sunrise': sunrise,
|
||||
'sunset': sunset,
|
||||
'precipitationSum': precipitationSum,
|
||||
'precipitationProbabilityMax': precipitationProbabilityMax,
|
||||
'windspeed10MMax': windspeed10MMax,
|
||||
'windgusts10MMax': windgusts10MMax,
|
||||
'uvIndexMax': uvIndexMax,
|
||||
'rainSum': rainSum,
|
||||
'winddirection10MDominant': winddirection10MDominant,
|
||||
'timezone': timezone,
|
||||
'timestamp': timestamp,
|
||||
};
|
||||
'id': id,
|
||||
'time': time,
|
||||
'weathercode': weathercode,
|
||||
'temperature2M': temperature2M,
|
||||
'apparentTemperature': apparentTemperature,
|
||||
'relativehumidity2M': relativehumidity2M,
|
||||
'precipitation': precipitation,
|
||||
'rain': rain,
|
||||
'surfacePressure': surfacePressure,
|
||||
'visibility': visibility,
|
||||
'evapotranspiration': evapotranspiration,
|
||||
'windspeed10M': windspeed10M,
|
||||
'winddirection10M': winddirection10M,
|
||||
'windgusts10M': windgusts10M,
|
||||
'cloudcover': cloudcover,
|
||||
'uvIndex': uvIndex,
|
||||
'dewpoint2M': dewpoint2M,
|
||||
'precipitationProbability': precipitationProbability,
|
||||
'shortwaveRadiation': shortwaveRadiation,
|
||||
'timeDaily': timeDaily,
|
||||
'weathercodeDaily': weathercodeDaily,
|
||||
'temperature2MMax': temperature2MMax,
|
||||
'temperature2MMin': temperature2MMin,
|
||||
'apparentTemperatureMax': apparentTemperatureMax,
|
||||
'apparentTemperatureMin': apparentTemperatureMin,
|
||||
'sunrise': sunrise,
|
||||
'sunset': sunset,
|
||||
'precipitationSum': precipitationSum,
|
||||
'precipitationProbabilityMax': precipitationProbabilityMax,
|
||||
'windspeed10MMax': windspeed10MMax,
|
||||
'windgusts10MMax': windgusts10MMax,
|
||||
'uvIndexMax': uvIndexMax,
|
||||
'rainSum': rainSum,
|
||||
'winddirection10MDominant': winddirection10MDominant,
|
||||
'timezone': timezone,
|
||||
'timestamp': timestamp,
|
||||
};
|
||||
}
|
||||
|
||||
@collection
|
||||
|
@ -147,12 +152,15 @@ class LocationCache {
|
|||
String? city;
|
||||
String? district;
|
||||
|
||||
LocationCache({
|
||||
this.lat,
|
||||
this.lon,
|
||||
this.city,
|
||||
this.district,
|
||||
});
|
||||
LocationCache({this.lat, this.lon, this.city, this.district});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'lat': lat,
|
||||
'lon': lon,
|
||||
'city': city,
|
||||
'district': district,
|
||||
};
|
||||
}
|
||||
|
||||
@collection
|
||||
|
@ -243,55 +251,57 @@ class WeatherCard {
|
|||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'time': time,
|
||||
'weathercode': weathercode,
|
||||
'temperature2M': temperature2M,
|
||||
'apparentTemperature': apparentTemperature,
|
||||
'relativehumidity2M': relativehumidity2M,
|
||||
'precipitation': precipitation,
|
||||
'rain': rain,
|
||||
'surfacePressure': surfacePressure,
|
||||
'visibility': visibility,
|
||||
'evapotranspiration': evapotranspiration,
|
||||
'windspeed10M': windspeed10M,
|
||||
'winddirection10M': winddirection10M,
|
||||
'windgusts10M': windgusts10M,
|
||||
'cloudcover': cloudcover,
|
||||
'uvIndex': uvIndex,
|
||||
'dewpoint2M': dewpoint2M,
|
||||
'precipitationProbability': precipitationProbability,
|
||||
'shortwaveRadiation': shortwaveRadiation,
|
||||
'timeDaily': timeDaily,
|
||||
'weathercodeDaily': weathercodeDaily,
|
||||
'temperature2MMax': temperature2MMax,
|
||||
'temperature2MMin': temperature2MMin,
|
||||
'apparentTemperatureMax': apparentTemperatureMax,
|
||||
'apparentTemperatureMin': apparentTemperatureMin,
|
||||
'sunrise': sunrise,
|
||||
'sunset': sunset,
|
||||
'precipitationSum': precipitationSum,
|
||||
'precipitationProbabilityMax': precipitationProbabilityMax,
|
||||
'windspeed10MMax': windspeed10MMax,
|
||||
'windgusts10MMax': windgusts10MMax,
|
||||
'uvIndexMax': uvIndexMax,
|
||||
'rainSum': rainSum,
|
||||
'winddirection10MDominant': winddirection10MDominant,
|
||||
'timezone': timezone,
|
||||
'timestamp': timestamp,
|
||||
'lat': lat,
|
||||
'lon': lon,
|
||||
'city': city,
|
||||
'district': district,
|
||||
'index': index,
|
||||
};
|
||||
'id': id,
|
||||
'time': time,
|
||||
'weathercode': weathercode,
|
||||
'temperature2M': temperature2M,
|
||||
'apparentTemperature': apparentTemperature,
|
||||
'relativehumidity2M': relativehumidity2M,
|
||||
'precipitation': precipitation,
|
||||
'rain': rain,
|
||||
'surfacePressure': surfacePressure,
|
||||
'visibility': visibility,
|
||||
'evapotranspiration': evapotranspiration,
|
||||
'windspeed10M': windspeed10M,
|
||||
'winddirection10M': winddirection10M,
|
||||
'windgusts10M': windgusts10M,
|
||||
'cloudcover': cloudcover,
|
||||
'uvIndex': uvIndex,
|
||||
'dewpoint2M': dewpoint2M,
|
||||
'precipitationProbability': precipitationProbability,
|
||||
'shortwaveRadiation': shortwaveRadiation,
|
||||
'timeDaily': timeDaily,
|
||||
'weathercodeDaily': weathercodeDaily,
|
||||
'temperature2MMax': temperature2MMax,
|
||||
'temperature2MMin': temperature2MMin,
|
||||
'apparentTemperatureMax': apparentTemperatureMax,
|
||||
'apparentTemperatureMin': apparentTemperatureMin,
|
||||
'sunrise': sunrise,
|
||||
'sunset': sunset,
|
||||
'precipitationSum': precipitationSum,
|
||||
'precipitationProbabilityMax': precipitationProbabilityMax,
|
||||
'windspeed10MMax': windspeed10MMax,
|
||||
'windgusts10MMax': windgusts10MMax,
|
||||
'uvIndexMax': uvIndexMax,
|
||||
'rainSum': rainSum,
|
||||
'winddirection10MDominant': winddirection10MDominant,
|
||||
'timezone': timezone,
|
||||
'timestamp': timestamp,
|
||||
'lat': lat,
|
||||
'lon': lon,
|
||||
'city': city,
|
||||
'district': district,
|
||||
'index': index,
|
||||
};
|
||||
|
||||
factory WeatherCard.fromJson(Map<String, dynamic> json) {
|
||||
return WeatherCard(
|
||||
time: List<String>.from(json['time'] ?? []),
|
||||
weathercode: List<int>.from(json['weathercode'] ?? []),
|
||||
temperature2M: List<double>.from(json['temperature2M'] ?? []),
|
||||
apparentTemperature: List<double?>.from(json['apparentTemperature'] ?? []),
|
||||
apparentTemperature: List<double?>.from(
|
||||
json['apparentTemperature'] ?? [],
|
||||
),
|
||||
relativehumidity2M: List<int?>.from(json['relativehumidity2M'] ?? []),
|
||||
precipitation: List<double>.from(json['precipitation'] ?? []),
|
||||
rain: List<double?>.from(json['rain'] ?? []),
|
||||
|
@ -304,21 +314,31 @@ class WeatherCard {
|
|||
cloudcover: List<int?>.from(json['cloudcover'] ?? []),
|
||||
uvIndex: List<double?>.from(json['uvIndex'] ?? []),
|
||||
dewpoint2M: List<double?>.from(json['dewpoint2M'] ?? []),
|
||||
precipitationProbability: List<int?>.from(json['precipitationProbability'] ?? []),
|
||||
precipitationProbability: List<int?>.from(
|
||||
json['precipitationProbability'] ?? [],
|
||||
),
|
||||
shortwaveRadiation: List<double?>.from(json['shortwaveRadiation'] ?? []),
|
||||
timeDaily: List<DateTime>.from(json['timeDaily'] ?? []),
|
||||
weathercodeDaily: List<int?>.from(json['weathercodeDaily'] ?? []),
|
||||
temperature2MMax: List<double?>.from(json['temperature2MMax'] ?? []),
|
||||
temperature2MMin: List<double?>.from(json['temperature2MMin'] ?? []),
|
||||
apparentTemperatureMax: List<double?>.from(json['apparentTemperatureMax'] ?? []),
|
||||
apparentTemperatureMin: List<double?>.from(json['apparentTemperatureMin'] ?? []),
|
||||
apparentTemperatureMax: List<double?>.from(
|
||||
json['apparentTemperatureMax'] ?? [],
|
||||
),
|
||||
apparentTemperatureMin: List<double?>.from(
|
||||
json['apparentTemperatureMin'] ?? [],
|
||||
),
|
||||
windspeed10MMax: List<double?>.from(json['windspeed10MMax'] ?? []),
|
||||
windgusts10MMax: List<double?>.from(json['windgusts10MMax'] ?? []),
|
||||
uvIndexMax: List<double?>.from(json['uvIndexMax'] ?? []),
|
||||
rainSum: List<double?>.from(json['rainSum'] ?? []),
|
||||
winddirection10MDominant: List<int?>.from(json['winddirection10MDominant'] ?? []),
|
||||
winddirection10MDominant: List<int?>.from(
|
||||
json['winddirection10MDominant'] ?? [],
|
||||
),
|
||||
precipitationSum: List<double?>.from(json['precipitationSum'] ?? []),
|
||||
precipitationProbabilityMax: List<int?>.from(json['precipitationProbabilityMax'] ?? []),
|
||||
precipitationProbabilityMax: List<int?>.from(
|
||||
json['precipitationProbabilityMax'] ?? [],
|
||||
),
|
||||
sunrise: List<String>.from(json['sunrise'] ?? []),
|
||||
sunset: List<String>.from(json['sunset'] ?? []),
|
||||
lat: json['lat'],
|
633
lib/app/data/weather.g.dart → lib/app/data/db.g.dart
Normal file → Executable file
|
@ -1,6 +1,6 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'weather.dart';
|
||||
part of 'db.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// IsarCollectionGenerator
|
||||
|
@ -27,70 +27,95 @@ const SettingsSchema = CollectionSchema(
|
|||
name: r'degrees',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'language': PropertySchema(
|
||||
r'hideMap': PropertySchema(
|
||||
id: 2,
|
||||
name: r'hideMap',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'language': PropertySchema(
|
||||
id: 3,
|
||||
name: r'language',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'largeElement': PropertySchema(
|
||||
id: 4,
|
||||
name: r'largeElement',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'location': PropertySchema(
|
||||
id: 3,
|
||||
id: 5,
|
||||
name: r'location',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'materialColor': PropertySchema(
|
||||
id: 4,
|
||||
id: 6,
|
||||
name: r'materialColor',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'measurements': PropertySchema(
|
||||
id: 5,
|
||||
id: 7,
|
||||
name: r'measurements',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'notifications': PropertySchema(
|
||||
id: 6,
|
||||
id: 8,
|
||||
name: r'notifications',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'onboard': PropertySchema(
|
||||
id: 7,
|
||||
id: 9,
|
||||
name: r'onboard',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'pressure': PropertySchema(
|
||||
id: 10,
|
||||
name: r'pressure',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'roundDegree': PropertySchema(
|
||||
id: 11,
|
||||
name: r'roundDegree',
|
||||
type: IsarType.bool,
|
||||
),
|
||||
r'theme': PropertySchema(
|
||||
id: 8,
|
||||
id: 12,
|
||||
name: r'theme',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'timeEnd': PropertySchema(
|
||||
id: 9,
|
||||
id: 13,
|
||||
name: r'timeEnd',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'timeRange': PropertySchema(
|
||||
id: 10,
|
||||
id: 14,
|
||||
name: r'timeRange',
|
||||
type: IsarType.long,
|
||||
),
|
||||
r'timeStart': PropertySchema(
|
||||
id: 11,
|
||||
id: 15,
|
||||
name: r'timeStart',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'timeformat': PropertySchema(
|
||||
id: 12,
|
||||
id: 16,
|
||||
name: r'timeformat',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'widgetBackgroundColor': PropertySchema(
|
||||
id: 13,
|
||||
id: 17,
|
||||
name: r'widgetBackgroundColor',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'widgetTextColor': PropertySchema(
|
||||
id: 14,
|
||||
id: 18,
|
||||
name: r'widgetTextColor',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'wind': PropertySchema(
|
||||
id: 19,
|
||||
name: r'wind',
|
||||
type: IsarType.string,
|
||||
)
|
||||
},
|
||||
estimateSize: _settingsEstimateSize,
|
||||
|
@ -104,7 +129,7 @@ const SettingsSchema = CollectionSchema(
|
|||
getId: _settingsGetId,
|
||||
getLinks: _settingsGetLinks,
|
||||
attach: _settingsAttach,
|
||||
version: '3.1.0+1',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _settingsEstimateSize(
|
||||
|
@ -121,6 +146,7 @@ int _settingsEstimateSize(
|
|||
}
|
||||
}
|
||||
bytesCount += 3 + object.measurements.length * 3;
|
||||
bytesCount += 3 + object.pressure.length * 3;
|
||||
{
|
||||
final value = object.theme;
|
||||
if (value != null) {
|
||||
|
@ -152,6 +178,7 @@ int _settingsEstimateSize(
|
|||
bytesCount += 3 + value.length * 3;
|
||||
}
|
||||
}
|
||||
bytesCount += 3 + object.wind.length * 3;
|
||||
return bytesCount;
|
||||
}
|
||||
|
||||
|
@ -163,19 +190,24 @@ void _settingsSerialize(
|
|||
) {
|
||||
writer.writeBool(offsets[0], object.amoledTheme);
|
||||
writer.writeString(offsets[1], object.degrees);
|
||||
writer.writeString(offsets[2], object.language);
|
||||
writer.writeBool(offsets[3], object.location);
|
||||
writer.writeBool(offsets[4], object.materialColor);
|
||||
writer.writeString(offsets[5], object.measurements);
|
||||
writer.writeBool(offsets[6], object.notifications);
|
||||
writer.writeBool(offsets[7], object.onboard);
|
||||
writer.writeString(offsets[8], object.theme);
|
||||
writer.writeString(offsets[9], object.timeEnd);
|
||||
writer.writeLong(offsets[10], object.timeRange);
|
||||
writer.writeString(offsets[11], object.timeStart);
|
||||
writer.writeString(offsets[12], object.timeformat);
|
||||
writer.writeString(offsets[13], object.widgetBackgroundColor);
|
||||
writer.writeString(offsets[14], object.widgetTextColor);
|
||||
writer.writeBool(offsets[2], object.hideMap);
|
||||
writer.writeString(offsets[3], object.language);
|
||||
writer.writeBool(offsets[4], object.largeElement);
|
||||
writer.writeBool(offsets[5], object.location);
|
||||
writer.writeBool(offsets[6], object.materialColor);
|
||||
writer.writeString(offsets[7], object.measurements);
|
||||
writer.writeBool(offsets[8], object.notifications);
|
||||
writer.writeBool(offsets[9], object.onboard);
|
||||
writer.writeString(offsets[10], object.pressure);
|
||||
writer.writeBool(offsets[11], object.roundDegree);
|
||||
writer.writeString(offsets[12], object.theme);
|
||||
writer.writeString(offsets[13], object.timeEnd);
|
||||
writer.writeLong(offsets[14], object.timeRange);
|
||||
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(
|
||||
|
@ -187,20 +219,25 @@ Settings _settingsDeserialize(
|
|||
final object = Settings();
|
||||
object.amoledTheme = reader.readBool(offsets[0]);
|
||||
object.degrees = reader.readString(offsets[1]);
|
||||
object.hideMap = reader.readBool(offsets[2]);
|
||||
object.id = id;
|
||||
object.language = reader.readStringOrNull(offsets[2]);
|
||||
object.location = reader.readBool(offsets[3]);
|
||||
object.materialColor = reader.readBool(offsets[4]);
|
||||
object.measurements = reader.readString(offsets[5]);
|
||||
object.notifications = reader.readBool(offsets[6]);
|
||||
object.onboard = reader.readBool(offsets[7]);
|
||||
object.theme = reader.readStringOrNull(offsets[8]);
|
||||
object.timeEnd = reader.readStringOrNull(offsets[9]);
|
||||
object.timeRange = reader.readLongOrNull(offsets[10]);
|
||||
object.timeStart = reader.readStringOrNull(offsets[11]);
|
||||
object.timeformat = reader.readString(offsets[12]);
|
||||
object.widgetBackgroundColor = reader.readStringOrNull(offsets[13]);
|
||||
object.widgetTextColor = reader.readStringOrNull(offsets[14]);
|
||||
object.language = reader.readStringOrNull(offsets[3]);
|
||||
object.largeElement = reader.readBool(offsets[4]);
|
||||
object.location = reader.readBool(offsets[5]);
|
||||
object.materialColor = reader.readBool(offsets[6]);
|
||||
object.measurements = reader.readString(offsets[7]);
|
||||
object.notifications = reader.readBool(offsets[8]);
|
||||
object.onboard = reader.readBool(offsets[9]);
|
||||
object.pressure = reader.readString(offsets[10]);
|
||||
object.roundDegree = reader.readBool(offsets[11]);
|
||||
object.theme = reader.readStringOrNull(offsets[12]);
|
||||
object.timeEnd = reader.readStringOrNull(offsets[13]);
|
||||
object.timeRange = reader.readLongOrNull(offsets[14]);
|
||||
object.timeStart = 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;
|
||||
}
|
||||
|
||||
|
@ -216,31 +253,41 @@ P _settingsDeserializeProp<P>(
|
|||
case 1:
|
||||
return (reader.readString(offset)) as P;
|
||||
case 2:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 3:
|
||||
return (reader.readBool(offset)) as P;
|
||||
case 3:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 4:
|
||||
return (reader.readBool(offset)) as P;
|
||||
case 5:
|
||||
return (reader.readString(offset)) as P;
|
||||
return (reader.readBool(offset)) as P;
|
||||
case 6:
|
||||
return (reader.readBool(offset)) as P;
|
||||
case 7:
|
||||
return (reader.readBool(offset)) as P;
|
||||
case 8:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 9:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 10:
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
case 11:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 12:
|
||||
return (reader.readString(offset)) as P;
|
||||
case 8:
|
||||
return (reader.readBool(offset)) as P;
|
||||
case 9:
|
||||
return (reader.readBool(offset)) as P;
|
||||
case 10:
|
||||
return (reader.readString(offset)) as P;
|
||||
case 11:
|
||||
return (reader.readBool(offset)) as P;
|
||||
case 12:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 13:
|
||||
return (reader.readStringOrNull(offset)) as P;
|
||||
case 14:
|
||||
return (reader.readLongOrNull(offset)) as P;
|
||||
case 15:
|
||||
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:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
}
|
||||
|
@ -475,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) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
|
@ -673,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(
|
||||
bool value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
|
@ -847,6 +914,146 @@ 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(
|
||||
bool value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'roundDegree',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterFilterCondition> themeIsNull() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(const FilterCondition.isNull(
|
||||
|
@ -1794,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
|
||||
|
@ -1827,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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'language', Sort.asc);
|
||||
|
@ -1839,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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'location', Sort.asc);
|
||||
|
@ -1899,6 +2260,30 @@ 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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'roundDegree', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> sortByRoundDegreeDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'roundDegree', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> sortByTheme() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'theme', Sort.asc);
|
||||
|
@ -1983,6 +2368,18 @@ extension SettingsQuerySortBy on QueryBuilder<Settings, Settings, QSortBy> {
|
|||
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
|
||||
|
@ -2011,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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'id', Sort.asc);
|
||||
|
@ -2035,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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'location', Sort.asc);
|
||||
|
@ -2095,6 +2516,30 @@ 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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'roundDegree', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> thenByRoundDegreeDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'roundDegree', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QAfterSortBy> thenByTheme() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'theme', Sort.asc);
|
||||
|
@ -2179,6 +2624,18 @@ extension SettingsQuerySortThenBy
|
|||
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
|
||||
|
@ -2196,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(
|
||||
{bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
|
@ -2203,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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'location');
|
||||
|
@ -2234,6 +2703,19 @@ 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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'roundDegree');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QDistinct> distinctByTheme(
|
||||
{bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
|
@ -2283,6 +2765,13 @@ extension SettingsQueryWhereDistinct
|
|||
caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, Settings, QDistinct> distinctByWind(
|
||||
{bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'wind', caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension SettingsQueryProperty
|
||||
|
@ -2305,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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
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() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'location');
|
||||
|
@ -2341,6 +2842,18 @@ extension SettingsQueryProperty
|
|||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, String, QQueryOperations> pressureProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'pressure');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, bool, QQueryOperations> roundDegreeProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'roundDegree');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, String?, QQueryOperations> themeProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'theme');
|
||||
|
@ -2383,6 +2896,12 @@ extension SettingsQueryProperty
|
|||
return query.addPropertyName(r'widgetTextColor');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<Settings, String, QQueryOperations> windProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'wind');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// coverage:ignore-file
|
||||
|
@ -2583,7 +3102,7 @@ const MainWeatherCacheSchema = CollectionSchema(
|
|||
getId: _mainWeatherCacheGetId,
|
||||
getLinks: _mainWeatherCacheGetLinks,
|
||||
attach: _mainWeatherCacheAttach,
|
||||
version: '3.1.0+1',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _mainWeatherCacheEstimateSize(
|
||||
|
@ -10306,7 +10825,7 @@ const LocationCacheSchema = CollectionSchema(
|
|||
getId: _locationCacheGetId,
|
||||
getLinks: _locationCacheGetLinks,
|
||||
attach: _locationCacheAttach,
|
||||
version: '3.1.0+1',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _locationCacheEstimateSize(
|
||||
|
@ -11405,7 +11924,7 @@ const WeatherCardSchema = CollectionSchema(
|
|||
getId: _weatherCardGetId,
|
||||
getLinks: _weatherCardGetLinks,
|
||||
attach: _weatherCardAttach,
|
||||
version: '3.1.0+1',
|
||||
version: '3.1.8',
|
||||
);
|
||||
|
||||
int _weatherCardEstimateSize(
|
|
@ -1,182 +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],
|
||||
),
|
||||
Card(
|
||||
margin: const EdgeInsets.symmetric(vertical: 15),
|
||||
child: SizedBox(
|
||||
height: 136,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
child: ScrollablePositionedList.separated(
|
||||
key: const PageStorageKey(1),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
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.primaryContainer : 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],
|
||||
),
|
||||
WeatherDaily(
|
||||
weatherData: weatherCard,
|
||||
onTap: () => Get.to(
|
||||
() => WeatherMore(
|
||||
weatherData: weatherCard,
|
||||
),
|
||||
transition: Transition.downToUp,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,128 +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 ListWeatherCard extends StatefulWidget {
|
||||
const ListWeatherCard({super.key});
|
||||
|
||||
@override
|
||||
State<ListWeatherCard> createState() => _ListWeatherCardState();
|
||||
}
|
||||
|
||||
class _ListWeatherCardState extends State<ListWeatherCard> {
|
||||
final weatherController = Get.put(WeatherController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final textTheme = context.textTheme;
|
||||
final titleMedium = textTheme.titleMedium;
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
await weatherController.updateCacheCard(true);
|
||||
setState(() {});
|
||||
},
|
||||
child: Obx(
|
||||
() => weatherController.weatherCards.isEmpty
|
||||
? Center(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/add_weather.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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: ReorderableListView(
|
||||
onReorder: (oldIndex, newIndex) => weatherController.reorder(oldIndex, newIndex),
|
||||
children: [
|
||||
...weatherController.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!,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,239 +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),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (isLoading)
|
||||
const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,242 +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/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.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: const Icon(
|
||||
Iconsax.location,
|
||||
size: 18,
|
||||
),
|
||||
title: 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,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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: 'city'.tr,
|
||||
),
|
||||
NavigationDestination(
|
||||
icon: const Icon(Iconsax.category),
|
||||
selectedIcon: const Icon(Iconsax.category5),
|
||||
label: 'settings'.tr,
|
||||
),
|
||||
],
|
||||
),
|
||||
floatingActionButton: tabIndex == 1
|
||||
? FloatingActionButton(
|
||||
onPressed: () => showModalBottomSheet(
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
enableDrag: false,
|
||||
builder: (BuildContext context) =>
|
||||
const CreateWeatherCard(),
|
||||
),
|
||||
child: const Icon(
|
||||
Iconsax.add,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,173 +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: ListView(
|
||||
children: [
|
||||
Obx(() {
|
||||
if (weatherController.isLoading.isTrue) {
|
||||
return const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
MyShimmer(
|
||||
hight: 350,
|
||||
),
|
||||
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];
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
WeatherNow(
|
||||
time: mainWeather.time![hourOfDay],
|
||||
weather: mainWeather.weathercode![hourOfDay],
|
||||
degree: mainWeather.temperature2M![hourOfDay],
|
||||
timeDay: sunrise,
|
||||
timeNight: sunset,
|
||||
),
|
||||
Card(
|
||||
margin: const EdgeInsets.symmetric(vertical: 15),
|
||||
child: SizedBox(
|
||||
height: 136,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
|
||||
child: ScrollablePositionedList.separated(
|
||||
key: const PageStorageKey(0),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
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.primaryContainer : 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],
|
||||
),
|
||||
WeatherDaily(
|
||||
weatherData: weatherCard,
|
||||
onTap: () => Get.to(
|
||||
() => WeatherMore(
|
||||
weatherData: weatherCard,
|
||||
),
|
||||
transition: Transition.downToUp,
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:rain/app/data/weather.dart';
|
||||
import 'package:rain/app/modules/home.dart';
|
||||
import 'package:rain/app/widgets/button.dart';
|
||||
import 'package:rain/main.dart';
|
||||
|
||||
class OnboardingPage extends StatefulWidget {
|
||||
const OnboardingPage({super.key});
|
||||
|
||||
@override
|
||||
State<OnboardingPage> createState() => _OnboardingPageState();
|
||||
}
|
||||
|
||||
class _OnboardingPageState extends State<OnboardingPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final textTheme = context.textTheme;
|
||||
return Scaffold(
|
||||
body: SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
'assets/images/weather.png',
|
||||
scale: 7,
|
||||
),
|
||||
const SizedBox(height: 15),
|
||||
Text(
|
||||
'Rain - ${'name'.tr}',
|
||||
style: textTheme.titleLarge?.copyWith(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
child: Text(
|
||||
'description'.tr,
|
||||
style: textTheme.labelMedium?.copyWith(fontSize: 14),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
|
||||
child: MyTextButton(
|
||||
buttonName: 'start'.tr,
|
||||
onPressed: () async {
|
||||
settings.onboard = true;
|
||||
isar.writeTxnSync(() => isar.settings.putSync(settings));
|
||||
Get.off(
|
||||
() => const HomePage(),
|
||||
transition: Transition.downToUp,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,806 +0,0 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_colorpicker/flutter_colorpicker.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) {
|
||||
final theme = context.theme;
|
||||
final textTheme = context.textTheme;
|
||||
final titleMedium = textTheme.titleMedium;
|
||||
final titleLarge = textTheme.titleLarge;
|
||||
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: 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: 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 (!mounted) return;
|
||||
await showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog.adaptive(
|
||||
title: Text(
|
||||
'location'.tr,
|
||||
style: titleLarge,
|
||||
),
|
||||
content: Text('no_location'.tr, style: titleMedium),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Get.back(result: false),
|
||||
child: Text(
|
||||
'cancel'.tr,
|
||||
style: titleMedium?.copyWith(color: Colors.blueAccent),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Geolocator.openLocationSettings();
|
||||
Get.back(result: true);
|
||||
},
|
||||
child: Text(
|
||||
'settings'.tr,
|
||||
style: 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.notlification(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.notlification(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().format(
|
||||
DateFormat.Hm().parse(weatherController.timeConvert(timeStart).format(context)))
|
||||
: DateFormat.Hm().format(DateFormat.Hm()
|
||||
.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 (!mounted) return;
|
||||
MyApp.updateAppState(context, newTimeStart: timeStartPicker.format(context));
|
||||
if (settings.notifications) {
|
||||
flutterLocalNotificationsPlugin.cancelAll();
|
||||
weatherController.notlification(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().format(
|
||||
DateFormat.Hm().parse(weatherController.timeConvert(timeEnd).format(context)))
|
||||
: DateFormat.Hm().format(
|
||||
DateFormat.Hm().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 (!mounted) return;
|
||||
MyApp.updateAppState(context, newTimeEnd: timeEndPicker.format(context));
|
||||
if (settings.notifications) {
|
||||
flutterLocalNotificationsPlugin.cancelAll();
|
||||
weatherController.notlification(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: titleLarge?.copyWith(
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
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: titleLarge?.copyWith(
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
SettingCard(
|
||||
elevation: 4,
|
||||
icon: const Icon(Iconsax.bucket_square),
|
||||
text: 'widgetBackground'.tr,
|
||||
info: true,
|
||||
infoWidget: CircleAvatar(
|
||||
backgroundColor: theme.indicatorColor,
|
||||
radius: 11,
|
||||
child: CircleAvatar(
|
||||
backgroundColor: widgetBackgroundColor.isEmpty
|
||||
? 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: theme.copyWith(
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: ColorPicker(
|
||||
pickerColor: widgetBackgroundColor.isEmpty
|
||||
? theme.primaryColor
|
||||
: HexColor.fromHex(widgetBackgroundColor),
|
||||
onColorChanged: (pickedColor) {
|
||||
colorBackground = pickedColor.toHex();
|
||||
},
|
||||
hexInputBar: true,
|
||||
labelTypes: const [],
|
||||
pickerAreaHeightPercent: 0.7,
|
||||
pickerAreaBorderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
),
|
||||
),
|
||||
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: theme.indicatorColor,
|
||||
radius: 11,
|
||||
child: CircleAvatar(
|
||||
backgroundColor:
|
||||
widgetTextColor.isEmpty ? 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: theme.copyWith(
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: ColorPicker(
|
||||
pickerColor: widgetTextColor.isEmpty
|
||||
? theme.primaryColor
|
||||
: HexColor.fromHex(widgetTextColor),
|
||||
onColorChanged: (pickedColor) {
|
||||
colorText = pickedColor.toHex();
|
||||
},
|
||||
hexInputBar: true,
|
||||
labelTypes: const [],
|
||||
pickerAreaHeightPercent: 0.7,
|
||||
pickerAreaBorderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
),
|
||||
),
|
||||
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: 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: 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: 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.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'),
|
||||
),
|
||||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|