diff --git a/.github/workflows/default.yaml b/.github/workflows/default.yaml
index 7c789d85..64fa60eb 100644
--- a/.github/workflows/default.yaml
+++ b/.github/workflows/default.yaml
@@ -10,14 +10,14 @@ jobs:
flutter-test-analyze:
uses: ./.github/workflows/flutter.analyze-test.action.yaml
with:
- flutter_version: '3.7.7'
+ flutter_version: '3.10.0'
secrets:
passphrase: ${{ secrets.PASSPHRASE }}
flutter-build:
needs: [flutter-test-analyze]
uses: ./.github/workflows/flutter.build.action.yaml
with:
- flutter_version: '3.7.7'
+ flutter_version: '3.10.0'
android_output: 'apk'
secrets:
passphrase: ${{ secrets.PASSPHRASE }}
\ No newline at end of file
diff --git a/.github/workflows/dev.yaml b/.github/workflows/dev.yaml
index ed5216cc..c9465037 100644
--- a/.github/workflows/dev.yaml
+++ b/.github/workflows/dev.yaml
@@ -9,7 +9,7 @@ jobs:
flutter-test-analyze:
uses: ./.github/workflows/flutter.analyze-test.action.yaml
with:
- flutter_version: '3.7.7'
+ flutter_version: '3.10.0'
secrets:
passphrase: ${{ secrets.PASSPHRASE }}
page:
@@ -18,7 +18,7 @@ jobs:
needs: [flutter-test-analyze]
uses: ./.github/workflows/flutter.build.action.yaml
with:
- flutter_version: '3.7.7'
+ flutter_version: '3.10.0'
android_output: 'aab'
secrets:
passphrase: ${{ secrets.PASSPHRASE }}
diff --git a/.github/workflows/fastlane.action.yaml b/.github/workflows/fastlane.action.yaml
index 93accf78..e734eee3 100644
--- a/.github/workflows/fastlane.action.yaml
+++ b/.github/workflows/fastlane.action.yaml
@@ -34,7 +34,7 @@ jobs:
- name: 'Generate changelog'
run: ./.github/scripts/generate_changelog.sh
- name: 'Setup Ruby'
- uses: ruby/setup-ruby@v1.148.0
+ uses: ruby/setup-ruby@v1.149.0
with:
ruby-version: '3.0'
bundler-cache: true
diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml
index 5db0da7a..fd077079 100644
--- a/.github/workflows/main.yaml
+++ b/.github/workflows/main.yaml
@@ -9,14 +9,14 @@ jobs:
flutter-test-analyze:
uses: ./.github/workflows/flutter.analyze-test.action.yaml
with:
- flutter_version: '3.7.7'
+ flutter_version: '3.10.0'
secrets:
passphrase: ${{ secrets.PASSPHRASE }}
flutter-build:
needs: [flutter-test-analyze]
uses: ./.github/workflows/flutter.build.action.yaml
with:
- flutter_version: '3.7.7'
+ flutter_version: '3.10.0'
android_output: 'aab'
secrets:
passphrase: ${{ secrets.PASSPHRASE }}
diff --git a/.github/workflows/tag.yaml b/.github/workflows/tag.yaml
index 1491e7d4..33c3233b 100644
--- a/.github/workflows/tag.yaml
+++ b/.github/workflows/tag.yaml
@@ -9,14 +9,14 @@ jobs:
flutter-test-analyze:
uses: ./.github/workflows/flutter.analyze-test.action.yaml
with:
- flutter_version: '3.7.7'
+ flutter_version: '3.10.0'
secrets:
passphrase: ${{ secrets.PASSPHRASE }}
flutter-build:
needs: [flutter-test-analyze]
uses: ./.github/workflows/flutter.build.action.yaml
with:
- flutter_version: '3.7.7'
+ flutter_version: '3.10.0'
android_output: 'aab'
secrets:
passphrase: ${{ secrets.PASSPHRASE }}
diff --git a/.gitignore b/.gitignore
index 504d1e56..fc773cb5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,47 +1,50 @@
-# Miscellaneous
-*.class
-*.log
-*.pyc
-*.swp
-.DS_Store
-.atom/
-.buildlog/
-.history
-.svn/
-migrate_working_dir/
-
-# IntelliJ related
-*.iml
-*.ipr
-*.iws
-.idea/
-
-# 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
-# is commented out by default.
-#.vscode/
-
-# Flutter/Dart/Pub related
-**/doc/api/
-**/ios/Flutter/.last_build_id
-.dart_tool/
-.flutter-plugins
-.flutter-plugins-dependencies
-.packages
-.pub-cache/
-.pub/
-/build/
-
-# Web related
-lib/generated_plugin_registrant.dart
-
-# Symbolication related
-app.*.symbols
-
-# Obfuscation related
-app.*.map.json
-
-# Android Studio will place build artifacts here
-/android/app/debug
-/android/app/profile
-/android/app/release
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# 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
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+.packages
+.pub-cache/
+.pub/
+/build/
+
+# Web related
+lib/generated_plugin_registrant.dart
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
+
+# Code coverage
+**/lcov.info
diff --git a/CHANGELOG_en.md b/CHANGELOG_en.md
index c22a47a6..b8f8fc51 100644
--- a/CHANGELOG_en.md
+++ b/CHANGELOG_en.md
@@ -1,3 +1,21 @@
+# **v1.8.1**:
+
+- *Fix*:
+ - Slots on two-day events are now functioning normally
+- *Interface*:
+ - Added support for Android tablets
+***
+# **v1.8.0** :
+
+- *Fix*:
+ - Certain niches were not taken into account properly
+- *Interface*:
+ - Past closures are no longer displayed
+ - Main window is more organic
+ - Added a button to go directly to check the configured slots
+- *Core*:
+ - Update to Flutter 3.10.0
+***
# **v1.6.1** :
- *Fix*:
diff --git a/CHANGELOG_es.md b/CHANGELOG_es.md
index fe6d1750..990f8523 100644
--- a/CHANGELOG_es.md
+++ b/CHANGELOG_es.md
@@ -1,3 +1,21 @@
+# **v1.8.1**:
+
+- *Fix*:
+ - Las franjas horarias para eventos de dos días ya funcionan normalmente
+- *Interfaz*:
+ - Añadido soporte para tabletas Android
+***
+# **v1.8.0** :
+
+- *Fix*:
+ - Algunas franjas horarias no se tuvieron debidamente en cuenta
+- *Interfaz*:
+ - Los cierres pasados ya no se muestran
+ - La ventana principal es más orgánica
+ - Se agregó un botón para ir directamente a comprobar las ranuras configuradas
+- *Core*:
+ - Actualización a Flutter 3.10.0
+***
# **v1.6.1** :
- *Fix*:
diff --git a/CHANGELOG_fr.md b/CHANGELOG_fr.md
index 2fd68345..d0b00cc4 100644
--- a/CHANGELOG_fr.md
+++ b/CHANGELOG_fr.md
@@ -1,3 +1,21 @@
+# **v1.8.1** :
+
+- *Fix*:
+ - Les créneaux horaires sur des évènements d'étalant sur deux jours fonctionnent maintenant normalement
+- *Interface*:
+ - Ajout du support pour les tablettes
+***
+# **v1.8.0** :
+
+- *Fix*:
+ - Certains créneux n'étaient pas pris bien pris en compte
+- *Interface*:
+ - Les fermetures passées ne sont plus affichées
+ - La fenêtre principale est plus organique
+ - Ajout d'un bouton permettant d'aller directement vérifier les créneaux configurés
+- *Core*:
+ - Mise à jour en Flutter 3.10.0
+***
# **v1.6.1** :
- *Fix*:
diff --git a/README.md b/README.md
index a866f235..9767eb9b 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,7 @@
+
Mobile app to track the schedules of the [Chaban Delmas bridge](https://fr.wikipedia.org/wiki/Pont_Jacques-Chaban-Delmas) located in Bordeaux, France.
diff --git a/android/build.gradle b/android/build.gradle
index 13b3050e..d02fac26 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,31 +1,31 @@
-buildscript {
- ext.kotlin_version = '1.8.21'
- 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()
- mavenCentral()
- }
-}
-
-rootProject.buildDir = '../build'
-subprojects {
- project.buildDir = "${rootProject.buildDir}/${project.name}"
-}
-subprojects {
- project.evaluationDependsOn(':app')
-}
-
-task clean(type: Delete) {
- delete rootProject.buildDir
-}
+buildscript {
+ ext.kotlin_version = '1.8.21'
+ 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()
+ mavenCentral()
+ }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(':app')
+}
+
+tasks.register("clean", Delete) {
+ delete rootProject.buildDir
+}
diff --git a/android/fastlane/metadata/android/en-GB/full_description.txt b/android/fastlane/metadata/android/en-GB/full_description.txt
index 108d4bdc..4a863287 100644
--- a/android/fastlane/metadata/android/en-GB/full_description.txt
+++ b/android/fastlane/metadata/android/en-GB/full_description.txt
@@ -6,4 +6,6 @@ Several types of notifications are available:
- One day before closing at the time you want
- A summary of upcoming closures for the coming week
-Disclaimer: Chabo uses the web services provided by Bordeaux Métropole but is in no way affiliated with the latter or any other public entity whatsoever and does not represent any government entity.
\ No newline at end of file
+You also have the possibility to fill in slots in order to be informed only of events that impact you!
+
+Disclaimer: Chabo uses the web services provided by Bordeaux Métropole. It does not represent any government entity or the agglomeration of Bordeaux Métropole.
\ No newline at end of file
diff --git a/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/1_en-GB.png b/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/1_en-GB.png
index e48230cd..11cdfedf 100644
Binary files a/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/1_en-GB.png and b/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/1_en-GB.png differ
diff --git a/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/2_en-GB.png b/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/2_en-GB.png
index 9228c31b..fc2cd8e8 100644
Binary files a/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/2_en-GB.png and b/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/2_en-GB.png differ
diff --git a/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/3_en-GB.png b/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/3_en-GB.png
index 75ac1c9d..a3a57b5d 100644
Binary files a/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/3_en-GB.png and b/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/3_en-GB.png differ
diff --git a/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/4_en-GB.png b/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/4_en-GB.png
index 2c458fa5..07f9233d 100644
Binary files a/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/4_en-GB.png and b/android/fastlane/metadata/android/en-GB/images/phoneScreenshots/4_en-GB.png differ
diff --git a/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/1_en-GB.png b/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/1_en-GB.png
index e48230cd..5b425b21 100644
Binary files a/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/1_en-GB.png and b/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/1_en-GB.png differ
diff --git a/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/2_en-GB.png b/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/2_en-GB.png
index 9228c31b..c615aa4b 100644
Binary files a/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/2_en-GB.png and b/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/2_en-GB.png differ
diff --git a/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/3_en-GB.png b/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/3_en-GB.png
index 75ac1c9d..4fb82428 100644
Binary files a/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/3_en-GB.png and b/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/3_en-GB.png differ
diff --git a/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/4_en-GB.png b/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/4_en-GB.png
index 2c458fa5..d1f60778 100644
Binary files a/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/4_en-GB.png and b/android/fastlane/metadata/android/en-GB/images/sevenInchScreenshots/4_en-GB.png differ
diff --git a/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/1_en-GB.png b/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/1_en-GB.png
index e48230cd..6b116eb5 100644
Binary files a/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/1_en-GB.png and b/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/1_en-GB.png differ
diff --git a/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/2_en-GB.png b/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/2_en-GB.png
index 9228c31b..3aeb8e06 100644
Binary files a/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/2_en-GB.png and b/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/2_en-GB.png differ
diff --git a/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/3_en-GB.png b/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/3_en-GB.png
index 75ac1c9d..af76e0f0 100644
Binary files a/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/3_en-GB.png and b/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/3_en-GB.png differ
diff --git a/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/4_en-GB.png b/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/4_en-GB.png
index 2c458fa5..766354aa 100644
Binary files a/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/4_en-GB.png and b/android/fastlane/metadata/android/en-GB/images/tenInchScreenshots/4_en-GB.png differ
diff --git a/android/fastlane/metadata/android/en-GB/short_description.txt b/android/fastlane/metadata/android/en-GB/short_description.txt
index 102a7680..dfcd6029 100644
--- a/android/fastlane/metadata/android/en-GB/short_description.txt
+++ b/android/fastlane/metadata/android/en-GB/short_description.txt
@@ -1 +1 @@
-Chabo, the mobile app that gives you the timetables of the Chaban bridge
\ No newline at end of file
+Chabo, the application that allows you to know the events of the Chaban bridge
\ No newline at end of file
diff --git a/android/fastlane/metadata/android/en-US/full_description.txt b/android/fastlane/metadata/android/en-US/full_description.txt
index 108d4bdc..4a863287 100644
--- a/android/fastlane/metadata/android/en-US/full_description.txt
+++ b/android/fastlane/metadata/android/en-US/full_description.txt
@@ -6,4 +6,6 @@ Several types of notifications are available:
- One day before closing at the time you want
- A summary of upcoming closures for the coming week
-Disclaimer: Chabo uses the web services provided by Bordeaux Métropole but is in no way affiliated with the latter or any other public entity whatsoever and does not represent any government entity.
\ No newline at end of file
+You also have the possibility to fill in slots in order to be informed only of events that impact you!
+
+Disclaimer: Chabo uses the web services provided by Bordeaux Métropole. It does not represent any government entity or the agglomeration of Bordeaux Métropole.
\ No newline at end of file
diff --git a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png
index e48230cd..11cdfedf 100644
Binary files a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png and b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.png differ
diff --git a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png
index 9228c31b..fc2cd8e8 100644
Binary files a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png and b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.png differ
diff --git a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png
index 75ac1c9d..a3a57b5d 100644
Binary files a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png and b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.png differ
diff --git a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png
index 2c458fa5..07f9233d 100644
Binary files a/android/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png and b/android/fastlane/metadata/android/en-US/images/phoneScreenshots/4_en-US.png differ
diff --git a/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/1_en-US.png b/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/1_en-US.png
index e48230cd..5b425b21 100644
Binary files a/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/1_en-US.png and b/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/1_en-US.png differ
diff --git a/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/2_en-US.png b/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/2_en-US.png
index 9228c31b..c615aa4b 100644
Binary files a/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/2_en-US.png and b/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/2_en-US.png differ
diff --git a/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/3_en-US.png b/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/3_en-US.png
index 75ac1c9d..4fb82428 100644
Binary files a/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/3_en-US.png and b/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/3_en-US.png differ
diff --git a/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/4_en-US.png b/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/4_en-US.png
index 2c458fa5..d1f60778 100644
Binary files a/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/4_en-US.png and b/android/fastlane/metadata/android/en-US/images/sevenInchScreenshots/4_en-US.png differ
diff --git a/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/1_en-US.png b/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/1_en-US.png
index e48230cd..6b116eb5 100644
Binary files a/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/1_en-US.png and b/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/1_en-US.png differ
diff --git a/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/2_en-US.png b/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/2_en-US.png
index 9228c31b..3aeb8e06 100644
Binary files a/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/2_en-US.png and b/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/2_en-US.png differ
diff --git a/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/3_en-US.png b/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/3_en-US.png
index 75ac1c9d..af76e0f0 100644
Binary files a/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/3_en-US.png and b/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/3_en-US.png differ
diff --git a/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/4_en-US.png b/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/4_en-US.png
index 2c458fa5..766354aa 100644
Binary files a/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/4_en-US.png and b/android/fastlane/metadata/android/en-US/images/tenInchScreenshots/4_en-US.png differ
diff --git a/android/fastlane/metadata/android/en-US/short_description.txt b/android/fastlane/metadata/android/en-US/short_description.txt
index 102a7680..dfcd6029 100644
--- a/android/fastlane/metadata/android/en-US/short_description.txt
+++ b/android/fastlane/metadata/android/en-US/short_description.txt
@@ -1 +1 @@
-Chabo, the mobile app that gives you the timetables of the Chaban bridge
\ No newline at end of file
+Chabo, the application that allows you to know the events of the Chaban bridge
\ No newline at end of file
diff --git a/android/fastlane/metadata/android/es-ES/full_description.txt b/android/fastlane/metadata/android/es-ES/full_description.txt
index 17440558..98e4d2a3 100644
--- a/android/fastlane/metadata/android/es-ES/full_description.txt
+++ b/android/fastlane/metadata/android/es-ES/full_description.txt
@@ -6,4 +6,6 @@ Hay varios tipos de notificaciones disponibles:
- Un día antes del cierre a la hora que quieras
- Un resumen de los próximos cierres para la próxima semana.
-Descargo de responsabilidad: Chabo utiliza los servicios web proporcionados por Bordeaux Métropole, pero de ninguna manera está afiliado a este último ni a ninguna otra entidad pública y no representa a ninguna entidad gubernamental.
\ No newline at end of file
+¡También tienes la opción de introducir franjas horarias para que solo te avisen de los eventos que te afectan!
+
+Descargo de responsabilidad: Chabo utiliza los servicios web proporcionados por Bordeaux Métropole. No representa ninguna entidad gubernamental ni la aglomeración de Burdeos.
\ No newline at end of file
diff --git a/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/1_es-ES.png b/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/1_es-ES.png
index 19d95bb5..73c69f9c 100644
Binary files a/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/1_es-ES.png and b/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/1_es-ES.png differ
diff --git a/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/2_es-ES.png b/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/2_es-ES.png
index bc3d7564..9962276a 100644
Binary files a/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/2_es-ES.png and b/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/2_es-ES.png differ
diff --git a/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/3_es-ES.png b/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/3_es-ES.png
index e9ed4878..b84acaa6 100644
Binary files a/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/3_es-ES.png and b/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/3_es-ES.png differ
diff --git a/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/4_es-ES.png b/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/4_es-ES.png
index 1dfe12cd..2e73e868 100644
Binary files a/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/4_es-ES.png and b/android/fastlane/metadata/android/es-ES/images/phoneScreenshots/4_es-ES.png differ
diff --git a/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/1_es-ES.png b/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/1_es-ES.png
index 19d95bb5..46bfbbeb 100644
Binary files a/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/1_es-ES.png and b/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/1_es-ES.png differ
diff --git a/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/2_es-ES.png b/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/2_es-ES.png
index bc3d7564..4b6727fc 100644
Binary files a/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/2_es-ES.png and b/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/2_es-ES.png differ
diff --git a/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/3_es-ES.png b/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/3_es-ES.png
index e9ed4878..dd761683 100644
Binary files a/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/3_es-ES.png and b/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/3_es-ES.png differ
diff --git a/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/4_es-ES.png b/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/4_es-ES.png
index 1dfe12cd..9696928e 100644
Binary files a/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/4_es-ES.png and b/android/fastlane/metadata/android/es-ES/images/sevenInchScreenshots/4_es-ES.png differ
diff --git a/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/1_es-ES.png b/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/1_es-ES.png
index 19d95bb5..0e5f13bf 100644
Binary files a/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/1_es-ES.png and b/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/1_es-ES.png differ
diff --git a/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/2_es-ES.png b/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/2_es-ES.png
index bc3d7564..a8e78e85 100644
Binary files a/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/2_es-ES.png and b/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/2_es-ES.png differ
diff --git a/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/3_es-ES.png b/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/3_es-ES.png
index e9ed4878..a091097e 100644
Binary files a/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/3_es-ES.png and b/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/3_es-ES.png differ
diff --git a/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/4_es-ES.png b/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/4_es-ES.png
index 1dfe12cd..a2fd387f 100644
Binary files a/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/4_es-ES.png and b/android/fastlane/metadata/android/es-ES/images/tenInchScreenshots/4_es-ES.png differ
diff --git a/android/fastlane/metadata/android/es-ES/short_description.txt b/android/fastlane/metadata/android/es-ES/short_description.txt
index 5baa2790..d125e6c7 100644
--- a/android/fastlane/metadata/android/es-ES/short_description.txt
+++ b/android/fastlane/metadata/android/es-ES/short_description.txt
@@ -1 +1 @@
-Chabo, la aplicación que permite conocer los horarios del puente Chaban
\ No newline at end of file
+Chabo, la aplicación que te permite conocer los eventos del puente Chaban
\ No newline at end of file
diff --git a/android/fastlane/metadata/android/fr-FR/full_description.txt b/android/fastlane/metadata/android/fr-FR/full_description.txt
index 1aed863c..f50ec670 100644
--- a/android/fastlane/metadata/android/fr-FR/full_description.txt
+++ b/android/fastlane/metadata/android/fr-FR/full_description.txt
@@ -5,5 +5,7 @@ Plusieurs types de notifications sont disponibles :
- Le jour de la fermeture au moment où vous le souhaitez
- Un jour avant fermeture à l'heure que vous souhaitez
- Un récapitulatif des fermetures à venir pour la semaine qui arrive
+
+Vous avez aussi la possibilité de renseigner des créneaux horaires afin d'être uniquement avertis des évènements qui vous impactent !
-Avis de non-responsabilité : Chabo utilise les services web fournis par Bordeaux métropole mais n'est en aucun cas affilié à cette dernière ou à aucune autre entité publique que ce soit et ne représente aucune entité gouvernementale
\ No newline at end of file
+Avis de non-responsabilité : Chabo utilise les services web fournis par Bordeaux Métropole. Elle ne représente aucune entité gouvernementale ni l'agglomération de Bordeaux Métropole.
\ No newline at end of file
diff --git a/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/1_fr-FR.png b/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/1_fr-FR.png
index ed40e494..00d7df4e 100644
Binary files a/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/1_fr-FR.png and b/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/1_fr-FR.png differ
diff --git a/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/2_fr-FR.png b/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/2_fr-FR.png
index e346dbf9..96ddf6ca 100644
Binary files a/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/2_fr-FR.png and b/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/2_fr-FR.png differ
diff --git a/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/3_fr-FR.png b/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/3_fr-FR.png
index 351bec2e..0f3e6e8e 100644
Binary files a/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/3_fr-FR.png and b/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/3_fr-FR.png differ
diff --git a/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/4_fr-FR.png b/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/4_fr-FR.png
index c7f4c9b0..9556ab8a 100644
Binary files a/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/4_fr-FR.png and b/android/fastlane/metadata/android/fr-FR/images/phoneScreenshots/4_fr-FR.png differ
diff --git a/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/1_fr-FR.png b/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/1_fr-FR.png
index ed40e494..80965f0f 100644
Binary files a/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/1_fr-FR.png and b/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/1_fr-FR.png differ
diff --git a/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/2_fr-FR.png b/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/2_fr-FR.png
index e346dbf9..89c2486c 100644
Binary files a/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/2_fr-FR.png and b/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/2_fr-FR.png differ
diff --git a/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/3_fr-FR.png b/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/3_fr-FR.png
index 351bec2e..c7957694 100644
Binary files a/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/3_fr-FR.png and b/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/3_fr-FR.png differ
diff --git a/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/4_fr-FR.png b/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/4_fr-FR.png
index c7f4c9b0..de82613a 100644
Binary files a/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/4_fr-FR.png and b/android/fastlane/metadata/android/fr-FR/images/sevenInchScreenshots/4_fr-FR.png differ
diff --git a/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/1_fr-FR.png b/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/1_fr-FR.png
index ed40e494..cd389dbf 100644
Binary files a/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/1_fr-FR.png and b/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/1_fr-FR.png differ
diff --git a/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/2_fr-FR.png b/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/2_fr-FR.png
index e346dbf9..430dcefb 100644
Binary files a/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/2_fr-FR.png and b/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/2_fr-FR.png differ
diff --git a/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/3_fr-FR.png b/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/3_fr-FR.png
index 351bec2e..74a409e6 100644
Binary files a/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/3_fr-FR.png and b/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/3_fr-FR.png differ
diff --git a/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/4_fr-FR.png b/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/4_fr-FR.png
index c7f4c9b0..d8fd8256 100644
Binary files a/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/4_fr-FR.png and b/android/fastlane/metadata/android/fr-FR/images/tenInchScreenshots/4_fr-FR.png differ
diff --git a/android/fastlane/metadata/android/fr-FR/short_description.txt b/android/fastlane/metadata/android/fr-FR/short_description.txt
index 16c7be9c..e8759d7b 100644
--- a/android/fastlane/metadata/android/fr-FR/short_description.txt
+++ b/android/fastlane/metadata/android/fr-FR/short_description.txt
@@ -1 +1 @@
-Chabo, l'application qui vous permet de connaître les horaires du pont Chaban
\ No newline at end of file
+Chabo, l'application qui vous permet de connaître les évènements du pont Chaban
\ No newline at end of file
diff --git a/lib/bloc/scroll_status/scroll_status_bloc.dart b/lib/bloc/scroll_status/scroll_status_bloc.dart
index f56c9c17..6f9d6a98 100644
--- a/lib/bloc/scroll_status/scroll_status_bloc.dart
+++ b/lib/bloc/scroll_status/scroll_status_bloc.dart
@@ -1,17 +1,20 @@
import 'package:bloc_concurrency/bloc_concurrency.dart';
import 'package:chabo/bloc/chabo_event.dart';
+import 'package:chabo/custom_properties.dart';
import 'package:chabo/models/abstract_forecast.dart';
+import 'package:equatable/equatable.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
part 'scroll_status_event.dart';
+
part 'scroll_status_state.dart';
class ScrollStatusBloc extends Bloc {
final ScrollController scrollController;
ScrollStatusBloc({required this.scrollController})
- : super(ScrollStatusState(
+ : super(const ScrollStatusState(
showCurrentStatus: true,
status: ScrollStatus.ok,
currentTarget: null,
@@ -34,7 +37,6 @@ class ScrollStatusBloc extends Bloc {
state.copyWith(
showCurrentStatus: true,
status: ScrollStatus.ok,
- currentTarget: state.currentTarget,
),
);
}
@@ -50,7 +52,9 @@ class ScrollStatusBloc extends Bloc {
await scrollController.animateTo(
pixel,
- duration: const Duration(milliseconds: 300),
+ duration: const Duration(
+ milliseconds: CustomProperties.animationDurationMs,
+ ),
curve: Curves.linear,
);
targetContext = GlobalObjectKey(event.goTo.hashCode).currentContext;
diff --git a/lib/bloc/scroll_status/scroll_status_state.dart b/lib/bloc/scroll_status/scroll_status_state.dart
index df7344ab..f1d97b6d 100644
--- a/lib/bloc/scroll_status/scroll_status_state.dart
+++ b/lib/bloc/scroll_status/scroll_status_state.dart
@@ -1,11 +1,11 @@
part of 'scroll_status_bloc.dart';
-class ScrollStatusState {
+class ScrollStatusState extends Equatable {
final AbstractForecast? currentTarget;
final bool showCurrentStatus;
final ScrollStatus status;
- ScrollStatusState({
+ const ScrollStatusState({
required this.status,
required this.showCurrentStatus,
required this.currentTarget,
@@ -22,6 +22,9 @@ class ScrollStatusState {
currentTarget: currentTarget ?? this.currentTarget,
);
}
+
+ @override
+ List get props => [currentTarget, showCurrentStatus, status];
}
enum ScrollStatus { ok, error }
diff --git a/lib/bloc/status/status_bloc.dart b/lib/bloc/status/status_bloc.dart
index 99111b4b..8379139a 100644
--- a/lib/bloc/status/status_bloc.dart
+++ b/lib/bloc/status/status_bloc.dart
@@ -10,6 +10,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart';
part 'status_event.dart';
+
part 'status_state.dart';
class StatusBloc extends Bloc {
@@ -23,6 +24,23 @@ class StatusBloc extends Bloc {
on(
_onDurationChanged,
);
+ on(
+ _onStatusWidgetDimensionChanged,
+ );
+ }
+
+ void _onStatusWidgetDimensionChanged(
+ StatusWidgetDimensionChanged event,
+ Emitter emit,
+ ) {
+ emit(
+ state.copyWith(
+ statusWidgetDimension: event.dimension,
+ mainMessageStatus: _getMainStatus(
+ event.context,
+ ),
+ ),
+ );
}
void _onDurationChanged(
@@ -133,14 +151,20 @@ class StatusBloc extends Bloc {
!currentForecast.isCurrentlyClosed() &&
state.durationUntilNextEvent.inMinutes >=
state.durationForCloseClosing.inMinutes) {
- return '${_getGreetings(context)}, ${AppLocalizations.of(context)!.theBridgeIsCurrently} ${AppLocalizations.of(context)!.open}';
+ return state.statusWidgetDimension == StatusWidgetDimension.large
+ ? '${_getGreetings(context)}, ${AppLocalizations.of(context)!.theBridgeIsCurrently} ${AppLocalizations.of(context)!.open}'
+ : AppLocalizations.of(context)!.open.capitalize();
} else if (currentForecast != null &&
!currentForecast.isCurrentlyClosed() &&
state.durationUntilNextEvent.inMinutes <
state.durationForCloseClosing.inMinutes) {
- return '${_getGreetings(context)}, ${AppLocalizations.of(context)!.theBridgeIsCurrently} ${AppLocalizations.of(context)!.aboutToClose}';
+ return state.statusWidgetDimension == StatusWidgetDimension.large
+ ? '${_getGreetings(context)}, ${AppLocalizations.of(context)!.theBridgeIsCurrently} ${AppLocalizations.of(context)!.aboutToClose}'
+ : AppLocalizations.of(context)!.aboutToClose.capitalize();
} else {
- return '${_getGreetings(context)}, ${AppLocalizations.of(context)!.theBridgeIsCurrently} ${AppLocalizations.of(context)!.closed}';
+ return state.statusWidgetDimension == StatusWidgetDimension.large
+ ? '${_getGreetings(context)}, ${AppLocalizations.of(context)!.theBridgeIsCurrently} ${AppLocalizations.of(context)!.closed}'
+ : AppLocalizations.of(context)!.closed.capitalize();
}
}
diff --git a/lib/bloc/status/status_event.dart b/lib/bloc/status/status_event.dart
index fbb1f278..fcd36a43 100644
--- a/lib/bloc/status/status_event.dart
+++ b/lib/bloc/status/status_event.dart
@@ -27,3 +27,13 @@ class StatusDurationChanged extends StatusEvent {
required this.duration,
}) : super();
}
+
+class StatusWidgetDimensionChanged extends StatusEvent {
+ final StatusWidgetDimension dimension;
+ final BuildContext context;
+
+ StatusWidgetDimensionChanged({
+ required this.dimension,
+ required this.context,
+ }) : super();
+}
diff --git a/lib/bloc/status/status_state.dart b/lib/bloc/status/status_state.dart
index 318f6b35..012281f1 100644
--- a/lib/bloc/status/status_state.dart
+++ b/lib/bloc/status/status_state.dart
@@ -12,6 +12,7 @@ class StatusState extends Equatable {
final String timeMessagePrefix;
final Color foregroundColor;
final Color backgroundColor;
+ final StatusWidgetDimension statusWidgetDimension;
const StatusState({
required this.statusLifecycle,
@@ -25,6 +26,7 @@ class StatusState extends Equatable {
required this.timeMessagePrefix,
required this.foregroundColor,
required this.backgroundColor,
+ required this.statusWidgetDimension,
});
StatusState copyWith({
@@ -39,6 +41,7 @@ class StatusState extends Equatable {
String? timeMessagePrefix,
Color? foregroundColor,
Color? backgroundColor,
+ StatusWidgetDimension? statusWidgetDimension,
}) {
return StatusState(
statusLifecycle: statusLifecycle ?? this.statusLifecycle,
@@ -56,6 +59,8 @@ class StatusState extends Equatable {
timeMessagePrefix: timeMessagePrefix ?? this.timeMessagePrefix,
foregroundColor: foregroundColor ?? this.foregroundColor,
backgroundColor: backgroundColor ?? this.backgroundColor,
+ statusWidgetDimension:
+ statusWidgetDimension ?? this.statusWidgetDimension,
);
}
@@ -72,6 +77,7 @@ class StatusState extends Equatable {
timeMessagePrefix,
foregroundColor,
backgroundColor,
+ statusWidgetDimension,
];
}
@@ -89,7 +95,10 @@ class StatusStateInitial extends StatusState {
timeMessagePrefix: '',
foregroundColor: Colors.white,
backgroundColor: Colors.white,
+ statusWidgetDimension: StatusWidgetDimension.large,
);
}
enum StatusLifecycle { empty, populated }
+
+enum StatusWidgetDimension { small, large }
diff --git a/lib/chabo.dart b/lib/chabo.dart
index a09ebe5d..28951ee3 100644
--- a/lib/chabo.dart
+++ b/lib/chabo.dart
@@ -1,13 +1,16 @@
+import 'package:chabo/app_theme.dart';
import 'package:chabo/bloc/forecast/forecast_bloc.dart';
import 'package:chabo/bloc/notification/notification_bloc.dart';
import 'package:chabo/bloc/scroll_status/scroll_status_bloc.dart';
import 'package:chabo/bloc/status/status_bloc.dart';
import 'package:chabo/bloc/theme/theme_bloc.dart';
import 'package:chabo/cubits/floating_actions_cubit.dart';
+import 'package:chabo/helpers/device_helper.dart';
import 'package:chabo/screens/forecast_screen.dart';
import 'package:chabo/service/notification_service.dart';
import 'package:chabo/service/storage_service.dart';
import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
@@ -25,6 +28,8 @@ class Chabo extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ DeviceHelper.computePreferredOrientation(context);
+
return MultiBlocProvider(
providers: [
/// Bloc intended to manage the theme of the App
@@ -77,6 +82,16 @@ class Chabo extends StatelessWidget {
],
child: BlocBuilder(
builder: (context, state) {
+ SystemChrome.setSystemUIOverlayStyle(
+ SystemUiOverlayStyle(
+ statusBarColor: Colors.transparent,
+ systemStatusBarContrastEnforced: false,
+ statusBarIconBrightness: state.themeData == AppTheme.darkTheme
+ ? Brightness.light
+ : Brightness.dark,
+ ),
+ );
+
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: state.themeData,
diff --git a/lib/custom_properties.dart b/lib/custom_properties.dart
index f4a70526..b94dc9bc 100644
--- a/lib/custom_properties.dart
+++ b/lib/custom_properties.dart
@@ -1,6 +1,7 @@
class CustomProperties {
static const double borderRadius = 17;
- static const int animationDurationMs = 200;
+ static const int animationDurationMs = 400;
+ static const int shortAnimationDurationMs = 200;
static const double blurSigmaX = 4;
static const double blurSigmaY = 4;
diff --git a/lib/dialogs/chabo_about_dialog.dart b/lib/dialogs/chabo_about_dialog.dart
deleted file mode 100644
index a3b4c502..00000000
--- a/lib/dialogs/chabo_about_dialog.dart
+++ /dev/null
@@ -1,283 +0,0 @@
-import 'package:chabo/const.dart';
-import 'package:chabo/custom_properties.dart';
-import 'package:chabo/screens/changelog_screen.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-import 'package:font_awesome_flutter/font_awesome_flutter.dart';
-import 'package:package_info_plus/package_info_plus.dart';
-
-class ChaboAboutDialog extends StatelessWidget {
- final Widget _iconWidget = Padding(
- padding: const EdgeInsets.all(5),
- child: SizedBox(
- height: 60,
- width: 60,
- child: Image.asset(Const.appLogoPath),
- ),
- );
-
- ChaboAboutDialog({Key? key}) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- final colorScheme = Theme.of(context).colorScheme;
- final textTheme = Theme.of(context).textTheme;
-
- return FutureBuilder(
- builder: (context, snapshot) {
- if (snapshot.connectionState == ConnectionState.waiting) {
- return const Center(child: CircularProgressIndicator());
- }
- if (snapshot.connectionState == ConnectionState.none &&
- snapshot.data == null) {
- return Text(AppLocalizations.of(context)!.unableAppInfo);
- }
-
- return AlertDialog(
- insetPadding: const EdgeInsets.symmetric(horizontal: 20),
- titlePadding: const EdgeInsets.all(20),
- contentPadding: const EdgeInsets.symmetric(horizontal: 20),
- actionsPadding: const EdgeInsets.fromLTRB(0, 10, 20, 20),
- title: Row(
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- IconTheme(
- data: Theme.of(context).iconTheme,
- child: Container(
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.all(
- Radius.circular(
- CustomProperties.borderRadius,
- ),
- ),
- ),
- child: _iconWidget,
- ),
- ),
- Expanded(
- child: Padding(
- padding: const EdgeInsets.symmetric(horizontal: 16.0),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- children: [
- Text(
- snapshot.data!.appName,
- style: Theme.of(context)
- .textTheme
- .headlineSmall!
- .copyWith(
- fontWeight: FontWeight.bold,
- fontSize: 30,
- ),
- ),
- Text(
- ' | v${snapshot.data!.version} (${snapshot.data!.buildNumber})',
- style: textTheme.bodyMedium,
- ),
- ],
- ),
- Text(
- Const.legalLease,
- style: textTheme.bodySmall!.copyWith(),
- ),
- ],
- ),
- ),
- ),
- ],
- ),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- CustomProperties.borderRadius,
- ),
- ),
- content: ListBody(
- children: [
- Text(
- AppLocalizations.of(context)!.appDescription,
- style: textTheme.bodyLarge,
- ),
- const SizedBox(
- height: 15,
- ),
- Text(
- AppLocalizations.of(context)!.disclaimer,
- style: Theme.of(context)
- .textTheme
- .bodyMedium
- ?.copyWith(fontStyle: FontStyle.italic),
- ),
- const SizedBox(
- height: 15,
- ),
- Wrap(
- alignment: WrapAlignment.center,
- spacing: 10,
- runSpacing: 10,
- children: Const.usefulLinks
- .map(
- (link) => ElevatedButton(
- onPressed: () => link.launchURL(),
- child: Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- Icon(
- link.iconData,
- size: 20,
- ),
- const SizedBox(
- width: 10,
- ),
- Padding(
- padding:
- const EdgeInsets.symmetric(vertical: 8.0),
- child: Text(
- AppLocalizations.of(context)!.selectAboutDialog(
- link.translationKey,
- ),
- ),
- ),
- const SizedBox(
- width: 10,
- ),
- ],
- ),
- ),
- )
- .toList(),
- ),
- const SizedBox(
- height: 10,
- ),
- Wrap(
- spacing: 10,
- runSpacing: 5,
- alignment: WrapAlignment.center,
- children: [
- ElevatedButton(
- style: ButtonStyle(
- backgroundColor: MaterialStateProperty.all(
- colorScheme.secondaryContainer,
- ),
- foregroundColor: MaterialStateProperty.all(
- colorScheme.onSecondaryContainer,
- ),
- ),
- onPressed: () => Navigator.push(
- context,
- MaterialPageRoute(
- builder: (context) => const ChangeLogScreen(),
- ),
- ),
- child: Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- const Icon(
- FontAwesomeIcons.codeMerge,
- size: 20,
- ),
- const SizedBox(
- width: 10,
- ),
- Padding(
- padding: const EdgeInsets.symmetric(vertical: 8.0),
- child: Text(
- AppLocalizations.of(context)!.selectAboutDialog(
- 'changelog',
- ),
- ),
- ),
- ],
- ),
- ),
- ElevatedButton(
- style: ButtonStyle(
- backgroundColor: MaterialStateProperty.all(
- colorScheme.secondaryContainer,
- ),
- foregroundColor: MaterialStateProperty.all(
- colorScheme.onSecondaryContainer,
- ),
- ),
- onPressed: () {
- showLicensePage(
- context: context,
- applicationName: snapshot.data!.appName,
- applicationVersion:
- 'v${snapshot.data!.version}+${snapshot.data!.buildNumber}',
- applicationIcon: Padding(
- padding: const EdgeInsets.all(8.0),
- child: IconTheme(
- data: Theme.of(context).iconTheme,
- child: Container(
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.all(
- Radius.circular(
- CustomProperties.borderRadius,
- ),
- ),
- ),
- child: _iconWidget,
- ),
- ),
- ),
- applicationLegalese: Const.legalLease,
- );
- },
- child: Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- const Icon(
- FontAwesomeIcons.fileLines,
- size: 20,
- ),
- const SizedBox(
- width: 10,
- ),
- Padding(
- padding: const EdgeInsets.symmetric(vertical: 8.0),
- child: Text(
- AppLocalizations.of(context)!
- .selectAboutDialog('licenses'),
- ),
- ),
- ],
- ),
- ),
- ],
- ),
- ],
- ),
- actions: [
- ElevatedButton.icon(
- style: ButtonStyle(
- backgroundColor: MaterialStateProperty.all(Colors.white),
- foregroundColor: MaterialStateProperty.all(
- Theme.of(context).primaryColor,
- ),
- shape: MaterialStateProperty.all(
- RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(
- CustomProperties.borderRadius,
- ),
- ),
- ),
- ),
- onPressed: () => {Navigator.pop(context)},
- icon: const Icon(Icons.close),
- label: Text(
- MaterialLocalizations.of(context).closeButtonLabel,
- ),
- ),
- ],
- scrollable: true,
- );
- },
- future: PackageInfo.fromPlatform(),
- );
- }
-}
diff --git a/lib/dialogs/chabo_about_dialog/chabo_about_dialog.dart b/lib/dialogs/chabo_about_dialog/chabo_about_dialog.dart
new file mode 100644
index 00000000..a90e79cc
--- /dev/null
+++ b/lib/dialogs/chabo_about_dialog/chabo_about_dialog.dart
@@ -0,0 +1,197 @@
+import 'package:chabo/const.dart';
+import 'package:chabo/custom_properties.dart';
+import 'package:chabo/helpers/device_helper.dart';
+import 'package:chabo/screens/changelog_screen.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:font_awesome_flutter/font_awesome_flutter.dart';
+import 'package:package_info_plus/package_info_plus.dart';
+
+part 'close_button.dart';
+
+part 'page_links_widget.dart';
+
+part 'web_links_widget.dart';
+
+class ChaboAboutDialog extends StatelessWidget {
+ final Widget _iconWidget = Padding(
+ padding: const EdgeInsets.all(5),
+ child: SizedBox(
+ height: 60,
+ width: 60,
+ child: Image.asset(Const.appLogoPath),
+ ),
+ );
+
+ ChaboAboutDialog({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ final textTheme = Theme.of(context).textTheme;
+
+ return FutureBuilder(
+ builder: (context, snapshot) {
+ if (snapshot.connectionState == ConnectionState.waiting) {
+ return const Center(child: CircularProgressIndicator());
+ }
+ if (snapshot.connectionState == ConnectionState.none &&
+ snapshot.data == null) {
+ return Text(AppLocalizations.of(context)!.unableAppInfo);
+ }
+
+ return AlertDialog(
+ insetPadding: const EdgeInsets.symmetric(horizontal: 20),
+ titlePadding: const EdgeInsets.all(20),
+ contentPadding: const EdgeInsets.symmetric(
+ horizontal: 20,
+ ),
+ actionsPadding: const EdgeInsets.fromLTRB(0, 10, 20, 20),
+ title: Row(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ IconTheme(
+ data: Theme.of(context).iconTheme,
+ child: Container(
+ decoration: const BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.all(
+ Radius.circular(
+ CustomProperties.borderRadius,
+ ),
+ ),
+ ),
+ child: _iconWidget,
+ ),
+ ),
+ Expanded(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16.0),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Row(
+ children: [
+ Text(
+ snapshot.data!.appName,
+ style: Theme.of(context)
+ .textTheme
+ .headlineSmall!
+ .copyWith(
+ fontWeight: FontWeight.bold,
+ fontSize: 30,
+ ),
+ ),
+ Text(
+ ' | v${snapshot.data!.version} (${snapshot.data!.buildNumber})',
+ style: textTheme.bodyMedium,
+ ),
+ ],
+ ),
+ Text(
+ Const.legalLease,
+ style: textTheme.bodySmall!.copyWith(),
+ ),
+ ],
+ ),
+ ),
+ ),
+ !DeviceHelper.isPortrait(context)
+ ? const _CloseButton()
+ : const SizedBox.shrink(),
+ ],
+ ),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(
+ CustomProperties.borderRadius,
+ ),
+ ),
+ content: Container(
+ constraints: DeviceHelper.isMobile(context)
+ ? DeviceHelper.isPortrait(context)
+ ? null
+ : BoxConstraints(
+ maxWidth: MediaQuery.of(context).size.width / 1.2,
+ )
+ : BoxConstraints(
+ maxWidth: MediaQuery.of(context).size.width / 1.9,
+ ),
+ child: DeviceHelper.isPortrait(context)
+ ? Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text(
+ AppLocalizations.of(context)!.appDescription,
+ style: textTheme.bodyLarge,
+ ),
+ const SizedBox(
+ height: 15,
+ ),
+ Text(
+ AppLocalizations.of(context)!.disclaimer,
+ style: Theme.of(context)
+ .textTheme
+ .bodyMedium
+ ?.copyWith(fontStyle: FontStyle.italic),
+ ),
+ const SizedBox(
+ height: 15,
+ ),
+ _PageLinksWidget(
+ packageInfo: snapshot.data!,
+ iconWidget: _iconWidget,
+ ),
+ const SizedBox(
+ height: 15,
+ ),
+ const _WebLinksWidget(),
+ ],
+ )
+ : Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Flexible(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text(
+ AppLocalizations.of(context)!.appDescription,
+ style: textTheme.bodyLarge,
+ ),
+ const SizedBox(
+ height: 15,
+ ),
+ Text(
+ AppLocalizations.of(context)!.disclaimer,
+ style: Theme.of(context)
+ .textTheme
+ .bodyMedium
+ ?.copyWith(fontStyle: FontStyle.italic),
+ ),
+ const SizedBox(
+ height: 15,
+ ),
+ _PageLinksWidget(
+ packageInfo: snapshot.data!,
+ iconWidget: _iconWidget,
+ ),
+ const SizedBox(
+ height: 15,
+ ),
+ ],
+ ),
+ ),
+ const Flexible(
+ child: _WebLinksWidget(),
+ ),
+ ],
+ ),
+ ),
+ scrollable: true,
+ actions:
+ DeviceHelper.isPortrait(context) ? [const _CloseButton()] : [],
+ );
+ },
+ future: PackageInfo.fromPlatform(),
+ );
+ }
+}
diff --git a/lib/dialogs/chabo_about_dialog/close_button.dart b/lib/dialogs/chabo_about_dialog/close_button.dart
new file mode 100644
index 00000000..c5ad6805
--- /dev/null
+++ b/lib/dialogs/chabo_about_dialog/close_button.dart
@@ -0,0 +1,29 @@
+part of 'chabo_about_dialog.dart';
+
+class _CloseButton extends StatelessWidget {
+ const _CloseButton({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return ElevatedButton.icon(
+ style: ButtonStyle(
+ backgroundColor: MaterialStateProperty.all(Colors.white),
+ foregroundColor: MaterialStateProperty.all(
+ Theme.of(context).primaryColor,
+ ),
+ shape: MaterialStateProperty.all(
+ RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(
+ CustomProperties.borderRadius,
+ ),
+ ),
+ ),
+ ),
+ onPressed: () => {Navigator.pop(context)},
+ icon: const Icon(Icons.close),
+ label: Text(
+ MaterialLocalizations.of(context).closeButtonLabel,
+ ),
+ );
+ }
+}
diff --git a/lib/dialogs/chabo_about_dialog/page_links_widget.dart b/lib/dialogs/chabo_about_dialog/page_links_widget.dart
new file mode 100644
index 00000000..78cafdb6
--- /dev/null
+++ b/lib/dialogs/chabo_about_dialog/page_links_widget.dart
@@ -0,0 +1,115 @@
+part of 'chabo_about_dialog.dart';
+
+class _PageLinksWidget extends StatelessWidget {
+ final PackageInfo packageInfo;
+ final Widget iconWidget;
+
+ const _PageLinksWidget({
+ Key? key,
+ required this.packageInfo,
+ required this.iconWidget,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ final colorScheme = Theme.of(context).colorScheme;
+
+ return Wrap(
+ spacing: 10,
+ runSpacing: 5,
+ alignment: WrapAlignment.center,
+ children: [
+ ElevatedButton(
+ style: ButtonStyle(
+ backgroundColor: MaterialStateProperty.all(
+ colorScheme.secondaryContainer,
+ ),
+ foregroundColor: MaterialStateProperty.all(
+ colorScheme.onSecondaryContainer,
+ ),
+ ),
+ onPressed: () => Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const ChangeLogScreen(),
+ ),
+ ),
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const Icon(
+ FontAwesomeIcons.codeMerge,
+ size: 20,
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 8.0),
+ child: Text(
+ AppLocalizations.of(context)!.selectAboutDialog(
+ 'changelog',
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ElevatedButton(
+ style: ButtonStyle(
+ backgroundColor: MaterialStateProperty.all(
+ colorScheme.secondaryContainer,
+ ),
+ foregroundColor: MaterialStateProperty.all(
+ colorScheme.onSecondaryContainer,
+ ),
+ ),
+ onPressed: () {
+ showLicensePage(
+ context: context,
+ applicationName: packageInfo.appName,
+ applicationVersion:
+ 'v${packageInfo.version}+${packageInfo.buildNumber}',
+ applicationIcon: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: IconTheme(
+ data: Theme.of(context).iconTheme,
+ child: Container(
+ decoration: const BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.all(
+ Radius.circular(
+ CustomProperties.borderRadius,
+ ),
+ ),
+ ),
+ child: iconWidget,
+ ),
+ ),
+ ),
+ applicationLegalese: Const.legalLease,
+ );
+ },
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ const Icon(
+ FontAwesomeIcons.fileLines,
+ size: 20,
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 8.0),
+ child: Text(
+ AppLocalizations.of(context)!.selectAboutDialog('licenses'),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/dialogs/chabo_about_dialog/web_links_widget.dart b/lib/dialogs/chabo_about_dialog/web_links_widget.dart
new file mode 100644
index 00000000..f9003c2f
--- /dev/null
+++ b/lib/dialogs/chabo_about_dialog/web_links_widget.dart
@@ -0,0 +1,48 @@
+part of 'chabo_about_dialog.dart';
+
+class _WebLinksWidget extends StatelessWidget {
+ const _WebLinksWidget({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ Wrap(
+ alignment: WrapAlignment.center,
+ spacing: 10,
+ runSpacing: 10,
+ children: Const.usefulLinks
+ .map(
+ (link) => ElevatedButton(
+ onPressed: () => link.launchURL(),
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Icon(
+ link.iconData,
+ size: 20,
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 8.0),
+ child: Text(
+ AppLocalizations.of(context)!.selectAboutDialog(
+ link.translationKey,
+ ),
+ ),
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ ],
+ ),
+ ),
+ )
+ .toList(),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/dialogs/days_of_the_week_dialog.dart b/lib/dialogs/days_of_the_week_dialog.dart
index cf550f2d..9c7dc1af 100644
--- a/lib/dialogs/days_of_the_week_dialog.dart
+++ b/lib/dialogs/days_of_the_week_dialog.dart
@@ -1,4 +1,5 @@
import 'package:chabo/bloc/notification/notification_bloc.dart';
+import 'package:chabo/custom_properties.dart';
import 'package:chabo/models/enums/day.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -13,7 +14,7 @@ class DaysOfTheWeekDialog extends StatelessWidget {
contentPadding: const EdgeInsets.all(15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
- 15,
+ CustomProperties.borderRadius,
),
),
content: BlocBuilder(
diff --git a/lib/dialogs/forecast_information_dialog.dart b/lib/dialogs/forecast_information_dialog.dart
index 982deb62..bb750130 100644
--- a/lib/dialogs/forecast_information_dialog.dart
+++ b/lib/dialogs/forecast_information_dialog.dart
@@ -1,5 +1,8 @@
-import 'package:chabo/extensions/color_scheme_extension.dart';
+import 'package:chabo/custom_properties.dart';
+import 'package:chabo/helpers/custom_page_routes.dart';
+import 'package:chabo/helpers/device_helper.dart';
import 'package:chabo/models/abstract_forecast.dart';
+import 'package:chabo/screens/notification_screen/notification_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -13,6 +16,8 @@ class ForecastInformationDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
+ final colorScheme = Theme.of(context).colorScheme;
+
return AlertDialog(
insetPadding: const EdgeInsets.symmetric(
horizontal: 20,
@@ -59,47 +64,82 @@ class ForecastInformationDialog extends StatelessWidget {
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
- 15,
+ CustomProperties.borderRadius,
),
),
- content: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Padding(
- padding: const EdgeInsets.all(20),
- child: forecast.getInformationWidget(context),
- ),
- if (forecast.interferingTimeSlots.isNotEmpty)
- Container(
- padding: const EdgeInsets.all(5),
- decoration: BoxDecoration(
- color: Theme.of(context).colorScheme.warningColor,
- borderRadius: const BorderRadius.only(
- bottomLeft: Radius.circular(
- 15.0,
- ),
- bottomRight: Radius.circular(
- 15.0,
+ content: Container(
+ constraints: DeviceHelper.isMobile(context)
+ ? DeviceHelper.isPortrait(context)
+ ? null
+ : BoxConstraints(
+ maxWidth: MediaQuery.of(context).size.width * 0.5,
+ )
+ : BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.5),
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Padding(
+ padding: const EdgeInsets.all(20),
+ child: forecast.getInformationWidget(context),
+ ),
+ if (forecast.interferingTimeSlots.isNotEmpty)
+ Container(
+ padding: const EdgeInsets.all(5),
+ decoration: BoxDecoration(
+ color: Theme.of(context).colorScheme.primary,
+ borderRadius: const BorderRadius.only(
+ bottomLeft: Radius.circular(
+ 15.0,
+ ),
+ bottomRight: Radius.circular(
+ 15.0,
+ ),
),
),
- ),
- child: Row(
- children: [
- const SizedBox(width: 10),
- Flexible(
- child: Text(
- AppLocalizations.of(context)!
- .favoriteSlotsInterferenceWarning,
- overflow: TextOverflow.clip,
- style: TextStyle(
- color: Theme.of(context).cardColor,
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 10),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Flexible(
+ child: Text(
+ AppLocalizations.of(context)!
+ .favoriteSlotsInterferenceWarning,
+ overflow: TextOverflow.clip,
+ style: TextStyle(
+ color: Theme.of(context).cardColor,
+ ),
+ ),
),
- ),
+ ElevatedButton(
+ style: ButtonStyle(
+ backgroundColor: MaterialStateProperty.all(
+ colorScheme.secondaryContainer,
+ ),
+ foregroundColor: MaterialStateProperty.all(
+ colorScheme.onSecondaryContainer,
+ ),
+ ),
+ onPressed: () => {
+ Navigator.of(context).pop(),
+ Navigator.of(context).push(
+ BottomToTopPageRoute(
+ builder: (context) => const NotificationScreen(
+ highlightTimeSlots: true,
+ ),
+ ),
+ ),
+ },
+ child: const Icon(
+ Icons.notifications_active,
+ ),
+ ),
+ ],
),
- ],
+ ),
),
- ),
- ],
+ ],
+ ),
),
);
}
diff --git a/lib/dialogs/time_slot_dialog.dart b/lib/dialogs/time_slot_dialog.dart
index dbfe8c6d..fdefc20a 100644
--- a/lib/dialogs/time_slot_dialog.dart
+++ b/lib/dialogs/time_slot_dialog.dart
@@ -1,4 +1,5 @@
import 'package:chabo/bloc/notification/notification_bloc.dart';
+import 'package:chabo/custom_properties.dart';
import 'package:chabo/models/time_slot.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -17,7 +18,7 @@ class TimeSlotDialog extends StatelessWidget {
contentPadding: const EdgeInsets.all(15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
- 15,
+ CustomProperties.borderRadius,
),
),
content: BlocBuilder(
diff --git a/lib/extensions/date_time_extension.dart b/lib/extensions/date_time_extension.dart
index 70f19b77..c4a8831d 100644
--- a/lib/extensions/date_time_extension.dart
+++ b/lib/extensions/date_time_extension.dart
@@ -3,7 +3,11 @@ import 'package:flutter/material.dart';
extension DateTimeExtension on DateTime {
DateTime previous(int day) {
return day == weekday
- ? subtract(const Duration(days: 7))
+ ? subtract(Duration(
+ days: 7,
+ hours: hour,
+ minutes: minute,
+ ))
: subtract(
Duration(
days: (weekday - day) % DateTime.daysPerWeek,
diff --git a/lib/helpers/custom_page_routes.dart b/lib/helpers/custom_page_routes.dart
new file mode 100644
index 00000000..4b7483e7
--- /dev/null
+++ b/lib/helpers/custom_page_routes.dart
@@ -0,0 +1,28 @@
+import 'package:flutter/material.dart';
+
+//ignore: prefer-match-file-name
+class BottomToTopPageRoute extends MaterialPageRoute {
+ BottomToTopPageRoute({
+ required WidgetBuilder builder,
+ RouteSettings? settings,
+ }) : super(builder: builder, settings: settings);
+
+ @override
+ Widget buildTransitions(
+ BuildContext context,
+ Animation animation,
+ Animation secondaryAnimation,
+ Widget child,
+ ) {
+ var begin = const Offset(0.0, 1.0);
+ var end = Offset.zero;
+ var curve = Curves.ease;
+
+ var tween = Tween(begin: begin, end: end).chain(CurveTween(curve: curve));
+
+ return SlideTransition(
+ position: animation.drive(tween),
+ child: child,
+ );
+ }
+}
diff --git a/lib/helpers/device_helper.dart b/lib/helpers/device_helper.dart
new file mode 100644
index 00000000..352cea29
--- /dev/null
+++ b/lib/helpers/device_helper.dart
@@ -0,0 +1,29 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+
+class DeviceHelper {
+ static computePreferredOrientation(BuildContext context) {
+ if (isMobile(context)) {
+ SystemChrome.setPreferredOrientations([
+ DeviceOrientation.portraitUp,
+ DeviceOrientation.landscapeLeft,
+ DeviceOrientation.landscapeRight,
+ ]);
+ } else {
+ SystemChrome.setPreferredOrientations([
+ DeviceOrientation.landscapeLeft,
+ DeviceOrientation.landscapeRight,
+ ]);
+ }
+ }
+
+ static isPortrait(BuildContext context) {
+ return MediaQuery.of(context).orientation == Orientation.portrait;
+ }
+
+ static isMobile(BuildContext context) {
+ var shortestSide = MediaQuery.of(context).size.shortestSide;
+
+ return shortestSide < 620;
+ }
+}
diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb
index cc14bdac..815921f6 100644
--- a/lib/l10n/app_en.arb
+++ b/lib/l10n/app_en.arb
@@ -3,16 +3,16 @@
"and": "and",
"circulationClosing": "closing",
"circulationReOpening": "re opening",
- "closed": "closed",
+ "closed": "closed to traffic",
"daySmall": "d",
"goodAfternoon": "good afternoon",
"goodEvening": "good evening",
"goodMorning": "good morning",
"nextClosingScheduled": "next closing scheduled in",
- "open": "open",
+ "open": "open to traffic",
"scheduledToOpen": "scheduled to open in",
"theBridgeIsCurrently": "the Chaban bridge is",
- "aboutToClose": "about to close",
+ "aboutToClose": "about to close to traffic",
"settingsTitle": "Settings",
"notificationsTitle": "Notifications",
"information": "Information",
@@ -30,7 +30,6 @@
"errorScreenContentError": "Error",
"errorScreenContentMessage": "An error occurred while opening this page. Please find technical information below",
"errorScreenContentTechnical_Info": "Technical information",
- "lisOfUpcomingClosures": "List of upcoming closures",
"unableAppInfo": "Unable to get application information",
"appDescription": "The Mobile app to get the closing and opening schedules of the Chaban Delmas bridge located in Bordeaux, France",
"changelog": "Changelog",
diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb
index cbe7c664..a74917b8 100644
--- a/lib/l10n/app_es.arb
+++ b/lib/l10n/app_es.arb
@@ -3,16 +3,16 @@
"and": "y",
"circulationClosing": "cerrado",
"circulationReOpening": "reapertura",
- "closed": "cerrado",
+ "closed": "cerrado al tráfico",
"daySmall": "d",
"goodAfternoon": "buenas tardes",
"goodEvening": "buenas noches",
"goodMorning": "buenos días",
"nextClosingScheduled": "próximo cierre programado en",
- "open": "abierto",
+ "open": "abierto al tráfico",
"scheduledToOpen": "programado para abrir en",
"theBridgeIsCurrently": "el puente Chaban está",
- "aboutToClose": "a punto de cerrarse",
+ "aboutToClose": "a punto de cerrarse al tráfico",
"settingsTitle": "Ajustes",
"notificationsTitle": "Notificaciónes",
"information": "Información",
@@ -30,7 +30,6 @@
"errorScreenContentError": "Error",
"errorScreenContentMessage": "Se produjo un error al abrir esta página. Encuentre la información técnica a continuación",
"errorScreenContentTechnical_Info": "Información técnica",
- "lisOfUpcomingClosures": "Lista de próximos cierres",
"unableAppInfo": "No se puede obtener información de la aplicación",
"appDescription": "La aplicación móvil para obtener los horarios de cierre y apertura del puente Chaban Delmas ubicado en Bordeaux, Francia",
"changelog": "Registro de cambios",
diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb
index 7312e65d..b1622ea3 100644
--- a/lib/l10n/app_fr.arb
+++ b/lib/l10n/app_fr.arb
@@ -3,16 +3,16 @@
"and": "et",
"circulationClosing": "fermeture",
"circulationReOpening": "réouverture",
- "closed": "fermé",
+ "closed": "fermé à la circulation",
"daySmall": "j",
"goodAfternoon": "bonne après-midi",
"goodEvening": "bonsoir",
"goodMorning": "bonjour",
"nextClosingScheduled": "prochaine fermeture prévue dans",
- "open": "ouvert",
+ "open": "ouvert à la circulation",
"scheduledToOpen": "ouverture prévue dans",
"theBridgeIsCurrently": "le pont Chaban est",
- "aboutToClose": "sur le point de fermer",
+ "aboutToClose": "sur le point de fermer à la circulation",
"settingsTitle": "Paramètres",
"notificationsTitle": "Notifications",
"information": "Information",
@@ -30,7 +30,6 @@
"errorScreenContentError": "Erreur",
"errorScreenContentMessage": "Une erreur est survenue lors de l'ouverture de cette page. Veuillez trouver les informations techniques ci-dessous",
"errorScreenContentTechnical_Info": "Informations techniques",
- "lisOfUpcomingClosures": "Liste des prochaines perturbations",
"unableAppInfo": "Impossible d'obtenir les informations de l'application",
"appDescription": "L'application Mobile pour connaître les horaires de fermeture et d'ouverture du pont Chaban Delmas situé à Bordeaux, France",
"changelog": "Journal des modifications",
diff --git a/lib/models/abstract_forecast.dart b/lib/models/abstract_forecast.dart
index f9acb8d8..3674970d 100644
--- a/lib/models/abstract_forecast.dart
+++ b/lib/models/abstract_forecast.dart
@@ -82,7 +82,7 @@ abstract class AbstractForecast extends Equatable {
void computeSlotInterference(List timeSlots) {
interferingTimeSlots.clear();
for (var timeSlot in timeSlots) {
- if (isOverlappingWithPeriod(timeSlot.from, timeSlot.to)) {
+ if (isOverlappingWithTimeSlot(timeSlot)) {
interferingTimeSlots.add(timeSlot);
}
}
@@ -92,14 +92,18 @@ abstract class AbstractForecast extends Equatable {
return isOverlappingWith(DateTime.now());
}
+ bool hasPassed() {
+ return circulationReOpeningDate.isBefore(DateTime.now());
+ }
+
bool isOverlappingWith(DateTime dateTime) {
return dateTime.isAfter(circulationClosingDate) &&
dateTime.isBefore(circulationReOpeningDate);
}
- bool isOverlappingWithPeriod(TimeOfDay start, TimeOfDay end) {
- final startDateTime = circulationClosingDate.applied(start);
- final endDateTime = circulationClosingDate.applied(end);
+ bool _isOverlapping(DateTime dateTimeToCompare, TimeSlot timeSlot) {
+ final startDateTime = dateTimeToCompare.applied(timeSlot.from);
+ final endDateTime = dateTimeToCompare.applied(timeSlot.to);
final startIsBeforeClosing = startDateTime.isBefore(
circulationClosingDate,
@@ -120,10 +124,6 @@ abstract class AbstractForecast extends Equatable {
startIsBeforeReopening &&
!endIsBeforeClosing &&
endIsBeforeReopening) ||
- (!startIsBeforeClosing &&
- startIsBeforeReopening &&
- endIsBeforeClosing &&
- !endIsBeforeClosing) ||
(!startIsBeforeClosing &&
startIsBeforeReopening &&
!endIsBeforeClosing &&
@@ -131,7 +131,20 @@ abstract class AbstractForecast extends Equatable {
(startIsBeforeClosing &&
startIsBeforeReopening &&
!endIsBeforeClosing &&
- !endIsBeforeReopening);
+ !endIsBeforeReopening) ||
+ (!startIsBeforeClosing &&
+ startIsBeforeReopening &&
+ !endIsBeforeClosing &&
+ endIsBeforeReopening);
+ }
+
+ bool isOverlappingWithTimeSlot(TimeSlot timeSlot) {
+ /// We must compute the overlapping for the open and closing date separately
+ /// if open and closing dates are not during the same day
+ return circulationClosingDate.day != circulationReOpeningDate.day
+ ? _isOverlapping(circulationClosingDate, timeSlot) ||
+ _isOverlapping(circulationReOpeningDate, timeSlot)
+ : _isOverlapping(circulationClosingDate, timeSlot);
}
static bool getBooleanTotalClosingValue(String stringValue) {
diff --git a/lib/screens/forecast_screen.dart b/lib/screens/forecast_screen.dart
index e4ddb0da..e7090a42 100644
--- a/lib/screens/forecast_screen.dart
+++ b/lib/screens/forecast_screen.dart
@@ -3,13 +3,15 @@ import 'package:chabo/bloc/notification/notification_bloc.dart';
import 'package:chabo/bloc/scroll_status/scroll_status_bloc.dart';
import 'package:chabo/bloc/status/status_bloc.dart';
import 'package:chabo/cubits/floating_actions_cubit.dart';
+import 'package:chabo/custom_properties.dart';
import 'package:chabo/custom_widget_state.dart';
+import 'package:chabo/helpers/device_helper.dart';
import 'package:chabo/misc/no_scaling_animation.dart';
import 'package:chabo/screens/error_screen.dart';
import 'package:chabo/widgets/ad_banner_widget.dart';
import 'package:chabo/widgets/floating_actions/floating_actions_widget.dart';
import 'package:chabo/widgets/forecast/forecast_list_widget.dart';
-import 'package:chabo/widgets/forecast/status_widget.dart';
+import 'package:chabo/widgets/forecast/status_widget/status_widget.dart';
import 'package:chabo/widgets/progress_indicator/custom_circular_progress_indicator.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -35,14 +37,20 @@ class _ForecastScreenState extends CustomWidgetState {
? CrossAxisAlignment.end
: CrossAxisAlignment.start,
children: [
- const Expanded(child: FloatingActionsWidget()),
- Padding(
- padding: EdgeInsets.only(
- left: state.isRightHanded ? 32 : 0,
- right: state.isRightHanded ? 0 : 32,
- top: 15,
- ),
- child: const AdBannerWidget(),
+ const Expanded(
+ child: FloatingActionsWidget(),
+ ),
+ Row(
+ children: [
+ Padding(
+ padding: EdgeInsets.only(
+ left: state.isRightHanded ? 32 : 0,
+ right: state.isRightHanded ? 0 : 32,
+ top: 5,
+ ),
+ child: const AdBannerWidget(),
+ ),
+ ],
),
],
),
@@ -51,10 +59,8 @@ class _ForecastScreenState extends CustomWidgetState {
: FloatingActionButtonLocation.startFloat,
floatingActionButtonAnimator: NoScalingAnimation(),
body: SafeArea(
+ top: false,
child: BlocBuilder(
- buildWhen: (previous, current) =>
- previous.status == ForecastStatus.initial &&
- current.status == ForecastStatus.success,
builder: (context, state) {
switch (state.status) {
case ForecastStatus.failure:
@@ -68,12 +74,15 @@ class _ForecastScreenState extends CustomWidgetState {
listeners: [
BlocListener(
listener: (context, state) {
+ /// If the ForecastState changes, update the previous and current forecasts
BlocProvider.of(context).add(
StatusChanged(
currentForecast: state.currentForecast,
previousForecast: state.previousForecast,
),
);
+
+ /// And scroll to the new one
BlocProvider.of(context).add(
GoTo(goTo: state.currentForecast),
);
@@ -81,11 +90,14 @@ class _ForecastScreenState extends CustomWidgetState {
),
BlocListener(
listener: (context, state) {
+ /// If the NotificationState changes, update the durationNotificationValue to get the right color of the current status widget
BlocProvider.of(context).add(
StatusDurationChanged(
duration: state.durationNotificationValue,
),
);
+
+ /// And compute all notifications
BlocProvider.of(context).add(
ComputeNotificationEvent(
forecasts: BlocProvider.of(
@@ -97,14 +109,115 @@ class _ForecastScreenState extends CustomWidgetState {
},
),
],
- child: Column(
- children: const [
- StatusWidget(),
- Expanded(
- flex: 11,
- child: ForecastListWidget(),
- ),
- ],
+ child: NotificationListener(
+ onNotification: (scrollNotification) {
+ if (scrollNotification is! UserScrollNotification) {
+ BlocProvider.of(context).add(
+ ScrollStatusChanged(),
+ );
+
+ /// Scroll reach the top and display the large layout for the status widget
+ if (scrollNotification.metrics.pixels <= 100) {
+ BlocProvider.of(context)
+ .add(StatusWidgetDimensionChanged(
+ context: context,
+ dimension: StatusWidgetDimension.large,
+ ));
+ } else {
+ /// Else, display the small one
+ BlocProvider.of(context)
+ .add(StatusWidgetDimensionChanged(
+ context: context,
+ dimension: StatusWidgetDimension.small,
+ ));
+ }
+ }
+
+ return true;
+ },
+ child: BlocBuilder(
+ builder: (context, state) {
+ return DeviceHelper.isPortrait(context)
+ ? CustomScrollView(
+ physics: const BouncingScrollPhysics(),
+ slivers: [
+ SliverAppBar(
+ pinned: true,
+ snap: false,
+ stretch: true,
+ collapsedHeight: 250,
+ expandedHeight: 250,
+ shadowColor: Colors.black,
+ backgroundColor: Theme.of(context)
+ .colorScheme
+ .surfaceVariant,
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.vertical(
+ bottom: Radius.circular(
+ CustomProperties.borderRadius * 2,
+ ),
+ ),
+ ),
+ flexibleSpace: const FlexibleSpaceBar(
+ titlePadding: EdgeInsets.zero,
+ centerTitle: true,
+ expandedTitleScale: 1,
+ title: StatusWidget(),
+ ),
+ ),
+ const ForecastListWidget(),
+ ],
+ )
+ : Row(
+ children: [
+ Flexible(
+ flex: !DeviceHelper.isMobile(context)
+ ? 2
+ : 1,
+ child: Column(
+ children: [
+ Container(
+ decoration: BoxDecoration(
+ color: Theme.of(context)
+ .colorScheme
+ .surfaceVariant,
+ borderRadius:
+ const BorderRadius.vertical(
+ bottom: Radius.circular(
+ CustomProperties
+ .borderRadius *
+ 2,
+ ),
+ ),
+ ),
+ constraints: BoxConstraints(
+ minHeight:
+ DeviceHelper.isMobile(
+ context,
+ )
+ ? 270
+ : 380,
+ ),
+ child: const StatusWidget(),
+ ),
+ const SizedBox(
+ height: 50,
+ ),
+ ],
+ ),
+ ),
+ const Flexible(
+ child: CustomScrollView(
+ physics: BouncingScrollPhysics(),
+ slivers: [
+ ForecastListWidget(),
+ ],
+ ),
+ ),
+ ],
+ );
+ },
+ ),
),
);
default:
diff --git a/lib/screens/notification_screen/custom_list_tile_widget.dart b/lib/screens/notification_screen/custom_list_tile_widget.dart
new file mode 100644
index 00000000..a651ff9d
--- /dev/null
+++ b/lib/screens/notification_screen/custom_list_tile_widget.dart
@@ -0,0 +1,95 @@
+part of 'notification_screen.dart';
+
+class _CustomListTileWidget extends StatelessWidget {
+ final bool enabled;
+ final bool constrainedBySlots;
+ final Function()? onTap;
+ final Function(bool) onChanged;
+ final String title;
+ final String subtitle;
+ final IconData leadingIcon;
+ final Color? iconColor;
+
+ const _CustomListTileWidget({
+ Key? key,
+ required this.enabled,
+ this.onTap,
+ this.iconColor,
+ required this.title,
+ required this.subtitle,
+ required this.leadingIcon,
+ required this.onChanged,
+ required this.constrainedBySlots,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return ListTile(
+ title: Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Flexible(
+ flex: 3,
+ child: Text(
+ title,
+ style: Theme.of(context).textTheme.titleLarge,
+ overflow: TextOverflow.clip,
+ ),
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ Flexible(
+ child: AnimatedSwitcher(
+ duration: const Duration(
+ milliseconds: CustomProperties.animationDurationMs,
+ ),
+ transitionBuilder: (Widget child, Animation animation) {
+ return FadeTransition(
+ opacity:
+ CurvedAnimation(parent: animation, curve: Curves.easeIn),
+ child: SlideTransition(
+ position: Tween(
+ begin: const Offset(-1.0, 0.0),
+ end: const Offset(0.0, 0.0),
+ ).animate(animation),
+ child: child,
+ ),
+ );
+ },
+ child: constrainedBySlots && enabled
+ ? CircleAvatar(
+ radius: 5,
+ backgroundColor:
+ Theme.of(context).colorScheme.warningColor,
+ child: Container(),
+ )
+ : const SizedBox(),
+ ),
+ ),
+ ],
+ ),
+ subtitle: Text(subtitle),
+ leading: Icon(
+ leadingIcon,
+ ),
+ onTap: onTap,
+ trailing: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ onTap != null
+ ? const VerticalDivider(
+ width: 20,
+ )
+ : const SizedBox.shrink(),
+ Switch.adaptive(
+ value: enabled,
+ onChanged: onChanged,
+ ),
+ ],
+ ),
+ iconColor: iconColor ?? Theme.of(context).colorScheme.primary,
+ enabled: enabled,
+ );
+ }
+}
diff --git a/lib/screens/notification_screen/favorite_slots_widget.dart b/lib/screens/notification_screen/favorite_slots_widget.dart
new file mode 100644
index 00000000..f0d40bbe
--- /dev/null
+++ b/lib/screens/notification_screen/favorite_slots_widget.dart
@@ -0,0 +1,131 @@
+part of 'notification_screen.dart';
+
+class _FavoriteSlotsWidget extends StatefulWidget {
+ final NotificationState notificationState;
+ final bool highlightTimeSlots;
+
+ const _FavoriteSlotsWidget({
+ Key? key,
+ required this.notificationState,
+ required this.highlightTimeSlots,
+ }) : super(key: key);
+
+ @override
+ State createState() {
+ return _FavoriteSlotsWidgetState();
+ }
+}
+
+class _FavoriteSlotsWidgetState extends State<_FavoriteSlotsWidget>
+ with SingleTickerProviderStateMixin {
+ late AnimationController _controller;
+ late Animation _animation;
+
+ @override
+ void initState() {
+ super.initState();
+ _controller = AnimationController(
+ duration: const Duration(milliseconds: 500),
+ vsync: this,
+ )..repeat(reverse: true);
+ Future.delayed(const Duration(milliseconds: 2000), () {
+ if (mounted) {
+ _controller.stop();
+ _controller.forward();
+ }
+ });
+ }
+
+ @override
+ void dispose() {
+ _controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ _animation = ColorTween(
+ begin: Theme.of(context).colorScheme.primary,
+ end: Theme.of(context).colorScheme.background,
+ ).animate(
+ CurvedAnimation(
+ parent: _controller,
+ curve: Curves.easeInQuad,
+ ),
+ )..addListener(
+ () {
+ /// Trigger le rebuild of the widget
+ // ignore: no-empty-block
+ setState(() {});
+ },
+ );
+
+ return Column(
+ children: [
+ _CustomListTileWidget(
+ onChanged: (bool value) => {
+ BlocProvider.of(context).add(
+ EnabledTimeSlotEvent(
+ enabled: value,
+ ),
+ ),
+ if (value)
+ {
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(
+ duration: const Duration(seconds: 7),
+ showCloseIcon: true,
+ backgroundColor: Theme.of(context).colorScheme.warningColor,
+ content: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Flexible(
+ child: Text(
+ AppLocalizations.of(context)!
+ .favoriteTimeSlotEnabledWarning,
+ style: const TextStyle(
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ }
+ else
+ {
+ ScaffoldMessenger.of(context).hideCurrentSnackBar(
+ reason: SnackBarClosedReason.action,
+ ),
+ },
+ },
+ enabled: widget.notificationState.timeSlotsEnabledForNotifications,
+ title: AppLocalizations.of(context)!.favoriteSlots,
+ subtitle: AppLocalizations.of(context)!.favoriteSlotsDescription,
+ leadingIcon: Icons.warning_rounded,
+ iconColor: Theme.of(context).colorScheme.warningColor,
+ constrainedBySlots: false,
+ ),
+ Container(
+ color:
+ widget.highlightTimeSlots ? _animation.value : Colors.transparent,
+ padding: const EdgeInsets.all(8.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ for (var i = 0;
+ i < widget.notificationState.timeSlotsValue.length;
+ i++) ...[
+ TimeSlotWidget(
+ timeSlot: widget.notificationState.timeSlotsValue[i],
+ index: i,
+ ),
+ ],
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/screens/notification_screen.dart b/lib/screens/notification_screen/notification_screen.dart
similarity index 70%
rename from lib/screens/notification_screen.dart
rename to lib/screens/notification_screen/notification_screen.dart
index 4f39bfc2..bdfdba7b 100644
--- a/lib/screens/notification_screen.dart
+++ b/lib/screens/notification_screen/notification_screen.dart
@@ -15,8 +15,17 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+part 'custom_list_tile_widget.dart';
+
+part 'favorite_slots_widget.dart';
+
class NotificationScreen extends StatefulWidget {
- const NotificationScreen({Key? key}) : super(key: key);
+ final bool highlightTimeSlots;
+
+ const NotificationScreen({
+ Key? key,
+ required this.highlightTimeSlots,
+ }) : super(key: key);
@override
State createState() => _NotificationScreenState();
@@ -60,6 +69,7 @@ class _NotificationScreenState extends CustomWidgetState {
body: SingleChildScrollView(
padding: const EdgeInsets.only(
top: 20,
+ bottom: 100,
),
child: BlocBuilder(
builder: (context, notificationState) {
@@ -115,72 +125,9 @@ class _NotificationScreenState extends CustomWidgetState {
),
Column(
children: [
- _CustomListTile(
- onChanged: (bool value) => {
- BlocProvider.of(context).add(
- EnabledTimeSlotEvent(
- enabled: value,
- ),
- ),
- if (value)
- {
- ScaffoldMessenger.of(context).showSnackBar(
- SnackBar(
- duration: const Duration(seconds: 7),
- showCloseIcon: true,
- backgroundColor: Theme.of(context)
- .colorScheme
- .warningColor,
- content: Row(
- mainAxisAlignment:
- MainAxisAlignment.spaceBetween,
- children: [
- Flexible(
- child: Text(
- AppLocalizations.of(context)!
- .favoriteTimeSlotEnabledWarning,
- style: const TextStyle(
- fontWeight: FontWeight.bold,
- ),
- ),
- ),
- ],
- ),
- ),
- ),
- }
- else
- {
- ScaffoldMessenger.of(context)
- .hideCurrentSnackBar(
- reason: SnackBarClosedReason.action,
- ),
- },
- },
- enabled: notificationState
- .timeSlotsEnabledForNotifications,
- title: AppLocalizations.of(context)!.favoriteSlots,
- subtitle: AppLocalizations.of(context)!
- .favoriteSlotsDescription,
- leadingIcon: Icons.warning_rounded,
- iconColor: Theme.of(context).colorScheme.warningColor,
- constrainedBySlots: false,
- ),
- Padding(
- padding: const EdgeInsets.all(8.0),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- for (var i = 0;
- i < notificationState.timeSlotsValue.length;
- i++) ...[
- TimeSlotWidget(
- timeSlot: notificationState.timeSlotsValue[i],
- index: i,
- ),
- ],
- ],
- ),
+ _FavoriteSlotsWidget(
+ highlightTimeSlots: widget.highlightTimeSlots,
+ notificationState: notificationState,
),
],
),
@@ -195,7 +142,7 @@ class _NotificationScreenState extends CustomWidgetState {
const SizedBox(
height: 10,
),
- _CustomListTile(
+ _CustomListTileWidget(
onChanged: (bool value) =>
BlocProvider.of(context).add(
OpeningNotificationStateEvent(
@@ -212,7 +159,7 @@ class _NotificationScreenState extends CustomWidgetState {
constrainedBySlots:
notificationState.timeSlotsEnabledForNotifications,
),
- _CustomListTile(
+ _CustomListTileWidget(
onChanged: (bool value) =>
BlocProvider.of(context).add(
ClosingNotificationStateEvent(
@@ -232,7 +179,7 @@ class _NotificationScreenState extends CustomWidgetState {
const SizedBox(
height: 20,
),
- _CustomListTile(
+ _CustomListTileWidget(
onTap: () {
showTimePicker(
initialEntryMode: TimePickerEntryMode.dialOnly,
@@ -285,7 +232,7 @@ class _NotificationScreenState extends CustomWidgetState {
constrainedBySlots:
notificationState.timeSlotsEnabledForNotifications,
),
- _CustomListTile(
+ _CustomListTileWidget(
onTap: () {
showTimePicker(
initialEntryMode: TimePickerEntryMode.dialOnly,
@@ -334,7 +281,7 @@ class _NotificationScreenState extends CustomWidgetState {
constrainedBySlots:
notificationState.timeSlotsEnabledForNotifications,
),
- _CustomListTile(
+ _CustomListTileWidget(
onTap: () {
showDialog(
context: context,
@@ -395,96 +342,3 @@ class _NotificationScreenState extends CustomWidgetState {
);
}
}
-
-class _CustomListTile extends StatelessWidget {
- final bool enabled;
- final bool constrainedBySlots;
- final Function()? onTap;
- final Function(bool) onChanged;
- final String title;
- final String subtitle;
- final IconData leadingIcon;
- final Color? iconColor;
-
- const _CustomListTile({
- Key? key,
- required this.enabled,
- this.onTap,
- this.iconColor,
- required this.title,
- required this.subtitle,
- required this.leadingIcon,
- required this.onChanged,
- required this.constrainedBySlots,
- }) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- return ListTile(
- title: Row(
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- Flexible(
- flex: 3,
- child: Text(
- title,
- style: Theme.of(context).textTheme.titleLarge,
- overflow: TextOverflow.clip,
- ),
- ),
- const SizedBox(
- width: 10,
- ),
- Flexible(
- child: AnimatedSwitcher(
- duration: const Duration(milliseconds: 200),
- transitionBuilder: (Widget child, Animation animation) {
- return FadeTransition(
- opacity:
- CurvedAnimation(parent: animation, curve: Curves.easeIn),
- child: SlideTransition(
- position: Tween(
- begin: const Offset(-1.0, 0.0),
- end: const Offset(0.0, 0.0),
- ).animate(animation),
- child: child,
- ),
- );
- },
- child: constrainedBySlots && enabled
- ? CircleAvatar(
- radius: 5,
- backgroundColor:
- Theme.of(context).colorScheme.warningColor,
- child: Container(),
- )
- : const SizedBox(),
- ),
- ),
- ],
- ),
- horizontalTitleGap: 0,
- subtitle: Text(subtitle),
- leading: Icon(
- leadingIcon,
- ),
- onTap: onTap,
- trailing: Row(
- mainAxisSize: MainAxisSize.min,
- children: [
- onTap != null
- ? const VerticalDivider(
- width: 20,
- )
- : const SizedBox.shrink(),
- Switch.adaptive(
- value: enabled,
- onChanged: onChanged,
- ),
- ],
- ),
- iconColor: iconColor ?? Theme.of(context).colorScheme.primary,
- enabled: enabled,
- );
- }
-}
diff --git a/lib/service/storage_service.dart b/lib/service/storage_service.dart
index 8e5e0214..ffe9ce89 100644
--- a/lib/service/storage_service.dart
+++ b/lib/service/storage_service.dart
@@ -32,12 +32,6 @@ class StorageService {
return await sharedPreferences.setString(key, value.inMinutes.toString());
}
- Future saveDateTime(String key, DateTime value) async {
- developer.log('{$key: $value}', name: 'storage-service.on.saveDuration');
-
- return await sharedPreferences.setString(key, value.toString());
- }
-
Future saveTimeOfDay(String key, TimeOfDay value) async {
developer.log('{$key: $value}', name: 'storage-service.on.saveTimeOfDay');
diff --git a/lib/widgets/ad_banner_widget.dart b/lib/widgets/ad_banner_widget.dart
index 3822e6da..754e126d 100644
--- a/lib/widgets/ad_banner_widget.dart
+++ b/lib/widgets/ad_banner_widget.dart
@@ -1,6 +1,8 @@
import 'dart:developer' as developer;
+import 'package:chabo/custom_properties.dart';
import 'package:chabo/helpers/ad_helper.dart';
+import 'package:chabo/helpers/device_helper.dart';
import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
@@ -56,18 +58,30 @@ class _AdBannerWidgetState extends State {
@override
Widget build(BuildContext context) {
+ final screenWidth = MediaQuery.of(context).size.width;
+
return _ad != null
? Card(
child: Container(
key: const ValueKey('adContent'),
- height: 55,
+ constraints: BoxConstraints(
+ maxHeight: 55,
+ maxWidth: DeviceHelper.isPortrait(context)
+ ? screenWidth / 1.11
+ //ignore: avoid-nested-conditional-expressions
+ : !DeviceHelper.isMobile(context)
+ ? screenWidth / 1.55
+ : screenWidth / 2.13,
+ ),
alignment: Alignment.center,
child: AnimatedSize(
curve: Curves.ease,
duration: const Duration(seconds: 1),
child: AnimatedSwitcher(
duration: const Duration(seconds: 1),
- reverseDuration: const Duration(milliseconds: 500),
+ reverseDuration: const Duration(
+ milliseconds: CustomProperties.animationDurationMs,
+ ),
transitionBuilder: (child, animation) {
return FadeTransition(
opacity: animation,
diff --git a/lib/widgets/floating_actions/floating_actions_widget.dart b/lib/widgets/floating_actions/floating_actions_widget.dart
index a89555e4..01053c13 100644
--- a/lib/widgets/floating_actions/floating_actions_widget.dart
+++ b/lib/widgets/floating_actions/floating_actions_widget.dart
@@ -2,8 +2,10 @@ import 'dart:ui';
import 'package:chabo/cubits/floating_actions_cubit.dart';
import 'package:chabo/custom_properties.dart';
-import 'package:chabo/dialogs/chabo_about_dialog.dart';
-import 'package:chabo/screens/notification_screen.dart';
+import 'package:chabo/dialogs/chabo_about_dialog/chabo_about_dialog.dart';
+import 'package:chabo/helpers/custom_page_routes.dart';
+import 'package:chabo/helpers/device_helper.dart';
+import 'package:chabo/screens/notification_screen/notification_screen.dart';
import 'package:chabo/widgets/floating_actions/floating_actions_item.dart';
import 'package:chabo/widgets/theme_switcher_widget.dart';
import 'package:flutter/material.dart';
@@ -34,10 +36,10 @@ class _FloatingActionsWidgetState extends State
children: [
AnimatedSwitcher(
duration: const Duration(
- milliseconds: 200,
+ milliseconds: CustomProperties.shortAnimationDurationMs,
),
reverseDuration: const Duration(
- milliseconds: 200,
+ milliseconds: CustomProperties.shortAnimationDurationMs,
),
transitionBuilder: (Widget child, Animation animation) {
return FadeTransition(
@@ -61,7 +63,10 @@ class _FloatingActionsWidgetState extends State
sigmaY: CustomProperties.blurSigmaY,
),
child: Wrap(
- direction: Axis.vertical,
+ direction: DeviceHelper.isMobile(context) &&
+ !DeviceHelper.isPortrait(context)
+ ? Axis.horizontal
+ : Axis.vertical,
crossAxisAlignment: state.isRightHanded
? WrapCrossAlignment.end
: WrapCrossAlignment.start,
@@ -90,10 +95,18 @@ class _FloatingActionsWidgetState extends State
onPressed: () {
showModalBottomSheet(
useSafeArea: true,
+ constraints: BoxConstraints(
+ minWidth: DeviceHelper.isPortrait(context)
+ ? double.infinity
+ : MediaQuery.of(context).size.width / 3,
+ ),
+ enableDrag: false,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
- top: Radius.circular(25.0),
+ top: Radius.circular(
+ CustomProperties.borderRadius * 2,
+ ),
),
),
builder: (context) {
@@ -114,34 +127,13 @@ class _FloatingActionsWidgetState extends State
isSpaced: true,
),
FloatingActionsItem(
- onPressed: () async {
+ onPressed: () {
Navigator.of(context).push(
- PageRouteBuilder(
- pageBuilder:
- (context, animation1, animation2) =>
- const NotificationScreen(),
- transitionsBuilder: (
- context,
- animation,
- secondaryAnimation,
- child,
- ) {
- const begin = Offset(0.0, 1.0);
- const end = Offset.zero;
- const curve = Curves.ease;
-
- var tween =
- Tween(begin: begin, end: end).chain(
- CurveTween(
- curve: curve,
- ),
- );
-
- return SlideTransition(
- position: animation.drive(tween),
- child: child,
- );
- },
+ BottomToTopPageRoute(
+ builder: (context) =>
+ const NotificationScreen(
+ highlightTimeSlots: false,
+ ),
),
);
context
@@ -206,41 +198,19 @@ class _FloatingActionsWidgetState extends State
content: [
AnimatedSize(
curve: Curves.easeIn,
- duration: const Duration(milliseconds: 200),
- reverseDuration: const Duration(
- milliseconds: 200,
+ duration: const Duration(
+ milliseconds: CustomProperties.shortAnimationDurationMs,
),
- child: AnimatedSwitcher(
- duration: const Duration(
- milliseconds: 200,
- ),
- reverseDuration: const Duration(
- milliseconds: 200,
- ),
- transitionBuilder:
- (Widget child, Animation animation) {
- return SlideTransition(
- position: Tween(
- begin: Offset(state.isRightHanded ? .5 : -.5, 0.0),
- end: const Offset(0.0, 0.0),
- ).animate(animation),
- child: FadeTransition(
- opacity: CurvedAnimation(
- parent: animation,
- curve: Curves.easeIn,
- ),
- child: child,
- ),
- );
- },
- child: state.isMenuOpen
- ? Text(
- AppLocalizations.of(context)!.settingsTitle,
- style: Theme.of(context).textTheme.titleMedium,
- textAlign: TextAlign.start,
- )
- : const SizedBox.shrink(),
+ reverseDuration: const Duration(
+ milliseconds: 0,
),
+ child: state.isMenuOpen
+ ? Text(
+ AppLocalizations.of(context)!.settingsTitle,
+ style: Theme.of(context).textTheme.titleMedium,
+ textAlign: TextAlign.start,
+ )
+ : const SizedBox.shrink(),
),
state.isMenuOpen
? const Icon(
diff --git a/lib/widgets/forecast/forecast_list_item_widget.dart b/lib/widgets/forecast/forecast_list_item_widget.dart
deleted file mode 100644
index 7643782c..00000000
--- a/lib/widgets/forecast/forecast_list_item_widget.dart
+++ /dev/null
@@ -1,252 +0,0 @@
-import 'dart:ui';
-
-import 'package:chabo/custom_properties.dart';
-import 'package:chabo/dialogs/forecast_information_dialog.dart';
-import 'package:chabo/extensions/color_scheme_extension.dart';
-import 'package:chabo/extensions/duration_extension.dart';
-import 'package:chabo/models/abstract_forecast.dart';
-import 'package:chabo/models/time_slot.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-import 'package:font_awesome_flutter/font_awesome_flutter.dart';
-
-class ForecastListItemWidget extends StatelessWidget {
- final AbstractForecast forecast;
- final Function()? onTap;
- final bool hasPassed;
- final List timeSlots;
- final bool isCurrent;
- final int index;
-
- const ForecastListItemWidget({
- Key? key,
- required this.forecast,
- required this.index,
- required this.hasPassed,
- required this.isCurrent,
- this.onTap,
- required this.timeSlots,
- }) : super(key: key);
-
- @override
- Widget build(BuildContext context) {
- final textTheme = Theme.of(context).textTheme;
-
- return Padding(
- padding: const EdgeInsets.all(5),
- child: Stack(
- children: [
- ElevatedButton(
- style: ButtonStyle(
- tapTargetSize: MaterialTapTargetSize.shrinkWrap,
- shape: MaterialStateProperty.all(
- RoundedRectangleBorder(
- borderRadius:
- BorderRadius.circular(CustomProperties.borderRadius),
- side: isCurrent
- ? BorderSide(
- width: 2,
- color: forecast.getColor(context, false),
- )
- : BorderSide.none,
- ),
- ),
- padding: MaterialStateProperty.all(
- const EdgeInsets.only(
- right: 0,
- ),
- ),
- ),
- onPressed: onTap ??
- () async => {
- await showGeneralDialog(
- context: context,
- pageBuilder: (BuildContext context, _, __) {
- return const SizedBox.shrink();
- },
- barrierDismissible: true,
- transitionBuilder: (context, a1, a2, widget) {
- return FadeTransition(
- opacity:
- Tween(begin: 0.0, end: 1.0).animate(a1),
- child: BackdropFilter(
- filter: ImageFilter.blur(
- sigmaX: CustomProperties.blurSigmaX,
- sigmaY: CustomProperties.blurSigmaY,
- ),
- child: ForecastInformationDialog(
- forecast: forecast,
- ),
- ),
- );
- },
- barrierLabel: MaterialLocalizations.of(context)
- .modalBarrierDismissLabel,
- transitionDuration: const Duration(
- milliseconds: 300,
- ),
- ),
- },
- child: SizedBox(
- height: 60,
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Container(
- width: 55,
- height: 60,
- decoration: BoxDecoration(
- borderRadius: const BorderRadius.only(
- topLeft: Radius.circular(
- CustomProperties.borderRadius,
- ),
- bottomLeft: Radius.circular(
- CustomProperties.borderRadius,
- ),
- ),
- color: forecast.getColor(
- context,
- false,
- ),
- ),
- child: Center(
- child: forecast.getIconWidget(
- context,
- true,
- ),
- ),
- ),
- Flexible(
- flex: 2,
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- const Icon(
- Icons.block_rounded,
- size: 18,
- color: Colors.red,
- ),
- Text(
- MaterialLocalizations.of(context)
- .formatMediumDate(
- forecast.circulationClosingDate,
- ),
- style: textTheme.bodySmall,
- ),
- ],
- ),
- Text(
- forecast.circulationClosingDateString(
- context,
- ),
- style: textTheme.headlineSmall,
- ),
- ],
- ),
- ),
- Flexible(
- fit: FlexFit.loose,
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Text(
- forecast.closedDuration.durationToString(context),
- style: TextStyle(
- color: Theme.of(context).colorScheme.timeColor,
- fontWeight: FontWeight.bold,
- fontSize: 15,
- ),
- ),
- const Icon(
- FontAwesomeIcons.arrowRightLong,
- size: 20,
- ),
- ],
- ),
- ),
- Flexible(
- flex: 2,
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceEvenly,
- children: [
- const Icon(
- Icons.check_circle,
- size: 18,
- color: Colors.green,
- ),
- Text(
- MaterialLocalizations.of(context)
- .formatMediumDate(
- forecast.circulationReOpeningDate,
- ),
- style: textTheme.bodySmall,
- ),
- ],
- ),
- Text(
- forecast.circulationReOpeningDateString(
- context,
- ),
- style: textTheme.headlineSmall,
- ),
- ],
- ),
- ),
- timeSlots.isNotEmpty
- ? Container(
- width: 30,
- height: 60,
- decoration: BoxDecoration(
- borderRadius: const BorderRadius.only(
- topRight: Radius.circular(
- CustomProperties.borderRadius,
- ),
- bottomRight: Radius.circular(
- CustomProperties.borderRadius,
- ),
- ),
- color: Theme.of(context).colorScheme.warningColor,
- ),
- child: Icon(
- Icons.warning_rounded,
- size: 20,
- color: Theme.of(context).cardColor,
- ),
- )
- : Container(
- width: 15,
- ),
- ],
- ),
- ),
- ),
- if (hasPassed)
- Positioned.fill(
- child: ClipRect(
- child: BackdropFilter(
- filter: ImageFilter.blur(
- sigmaX: CustomProperties.blurSigmaX,
- sigmaY: CustomProperties.blurSigmaY,
- ),
- child: Center(
- child: Text(
- AppLocalizations.of(context)!.passedClosure,
- style: const TextStyle(
- fontWeight: FontWeight.bold,
- ),
- ),
- ),
- ),
- ),
- ),
- ],
- ),
- );
- }
-}
diff --git a/lib/widgets/forecast/forecast_list_widget.dart b/lib/widgets/forecast/forecast_list_widget.dart
index d825ec22..3d0ef8a6 100644
--- a/lib/widgets/forecast/forecast_list_widget.dart
+++ b/lib/widgets/forecast/forecast_list_widget.dart
@@ -2,7 +2,7 @@ import 'package:chabo/bloc/forecast/forecast_bloc.dart';
import 'package:chabo/bloc/notification/notification_bloc.dart';
import 'package:chabo/bloc/scroll_status/scroll_status_bloc.dart';
import 'package:chabo/models/abstract_forecast.dart';
-import 'package:chabo/widgets/forecast/forecast_list_item_widget.dart';
+import 'package:chabo/widgets/forecast/forecast_widget/forecast_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
@@ -19,58 +19,51 @@ class ForecastListWidget extends StatefulWidget {
class _ForecastListWidgetState extends State {
@override
Widget build(BuildContext context) {
- return NotificationListener(
- onNotification: (scrollNotification) {
- if (scrollNotification is UserScrollNotification) {
- BlocProvider.of(context).add(
- ScrollStatusChanged(),
- );
- }
-
- return true;
- },
- child: BlocBuilder(
- builder: (context, forecastState) {
- return BlocBuilder(
- buildWhen: (previous, next) =>
- previous.timeSlotsValue != next.timeSlotsValue,
- builder: (context, timeSlotState) {
- return ListView.separated(
+ return BlocBuilder(
+ builder: (context, forecastState) {
+ return BlocBuilder(
+ buildWhen: (previous, next) =>
+ previous.timeSlotsValue != next.timeSlotsValue,
+ builder: (context, timeSlotState) {
+ return SliverToBoxAdapter(
+ child: ListView.separated(
+ shrinkWrap: true,
cacheExtent: 5000,
padding: const EdgeInsets.symmetric(horizontal: 5).copyWith(
- bottom: 200,
+ bottom: 150,
),
itemBuilder: (
BuildContext context,
int index,
) {
- forecastState.forecasts[index]
+ final AbstractForecast forecast =
+ forecastState.forecasts[index];
+ forecast
.computeSlotInterference(timeSlotState.timeSlotsValue);
- return ForecastListItemWidget(
- key: GlobalObjectKey(
- forecastState.forecasts[index].hashCode,
- ),
- isCurrent: forecastState.forecasts[index] ==
- forecastState.currentForecast,
- hasPassed: forecastState
- .forecasts[index].circulationReOpeningDate
- .isBefore(DateTime.now()),
- forecast: forecastState.forecasts[index],
- index: index,
- timeSlots:
- forecastState.forecasts[index].interferingTimeSlots,
- );
+ return !forecast.hasPassed()
+ ? ForecastWidget(
+ key: GlobalObjectKey(forecast.hashCode),
+ isCurrent: forecast == forecastState.currentForecast,
+ hasPassed: forecast.hasPassed(),
+ forecast: forecast,
+ index: index,
+ timeSlots: forecast.interferingTimeSlots,
+ )
+ : const SizedBox.shrink();
},
itemCount: forecastState.forecasts.length,
controller:
BlocProvider.of(context).scrollController,
separatorBuilder: (BuildContext context, int index) {
- if ((index + 1 <= forecastState.forecasts.length &&
- forecastState
- .forecasts[index].circulationClosingDate.month !=
- forecastState.forecasts[index + 1]
- .circulationClosingDate.month)) {
+ final AbstractForecast forecast =
+ forecastState.forecasts[index];
+ if ((forecast.circulationClosingDate.month !=
+ forecastState.forecasts[index + 1]
+ .circulationClosingDate.month) &&
+ !forecast.hasPassed() ||
+ forecastState.forecasts[index + 1] ==
+ forecastState.currentForecast) {
return _MonthWidget(
forecast: forecastState.forecasts[index + 1],
);
@@ -78,11 +71,11 @@ class _ForecastListWidgetState extends State {
return const SizedBox.shrink();
},
- );
- },
- );
- },
- ),
+ ),
+ );
+ },
+ );
+ },
);
}
}
diff --git a/lib/widgets/forecast/forecast_widget/closing_info_widget.dart b/lib/widgets/forecast/forecast_widget/closing_info_widget.dart
new file mode 100644
index 00000000..3acfa86e
--- /dev/null
+++ b/lib/widgets/forecast/forecast_widget/closing_info_widget.dart
@@ -0,0 +1,41 @@
+part of 'forecast_widget.dart';
+
+class _ClosingInfoWidget extends StatelessWidget {
+ final AbstractForecast forecast;
+
+ const _ClosingInfoWidget({Key? key, required this.forecast})
+ : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ final textTheme = Theme.of(context).textTheme;
+
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ const Icon(
+ Icons.block_rounded,
+ size: 18,
+ color: Colors.red,
+ ),
+ Text(
+ MaterialLocalizations.of(context).formatMediumDate(
+ forecast.circulationClosingDate,
+ ),
+ style: textTheme.bodySmall,
+ ),
+ ],
+ ),
+ Text(
+ forecast.circulationClosingDateString(
+ context,
+ ),
+ style: textTheme.headlineSmall,
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/forecast/forecast_widget/duration_widget.dart b/lib/widgets/forecast/forecast_widget/duration_widget.dart
new file mode 100644
index 00000000..3e8f920a
--- /dev/null
+++ b/lib/widgets/forecast/forecast_widget/duration_widget.dart
@@ -0,0 +1,31 @@
+part of 'forecast_widget.dart';
+
+class _DurationWidget extends StatelessWidget {
+ final AbstractForecast forecast;
+
+ const _DurationWidget({
+ Key? key,
+ required this.forecast,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ forecast.closedDuration.durationToString(context),
+ style: TextStyle(
+ color: Theme.of(context).colorScheme.timeColor,
+ fontWeight: FontWeight.bold,
+ fontSize: 15,
+ ),
+ ),
+ const Icon(
+ FontAwesomeIcons.arrowRightLong,
+ size: 20,
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/forecast/forecast_widget/forecast_widget.dart b/lib/widgets/forecast/forecast_widget/forecast_widget.dart
new file mode 100644
index 00000000..bf4b410d
--- /dev/null
+++ b/lib/widgets/forecast/forecast_widget/forecast_widget.dart
@@ -0,0 +1,164 @@
+import 'dart:ui';
+
+import 'package:chabo/custom_properties.dart';
+import 'package:chabo/dialogs/forecast_information_dialog.dart';
+import 'package:chabo/extensions/color_scheme_extension.dart';
+import 'package:chabo/extensions/duration_extension.dart';
+import 'package:chabo/models/abstract_forecast.dart';
+import 'package:chabo/models/time_slot.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+import 'package:font_awesome_flutter/font_awesome_flutter.dart';
+
+part 'closing_info_widget.dart';
+
+part 'duration_widget.dart';
+
+part 'leading_icon_widget.dart';
+
+part 'opening_info_widget.dart';
+
+part 'time_slot_warning_widget.dart';
+
+class ForecastWidget extends StatelessWidget {
+ final AbstractForecast forecast;
+ final Function()? onTap;
+ final bool hasPassed;
+ final List timeSlots;
+ final bool isCurrent;
+ final int index;
+ final Color? backgroundColor;
+
+ const ForecastWidget({
+ Key? key,
+ required this.forecast,
+ required this.index,
+ required this.hasPassed,
+ required this.isCurrent,
+ this.onTap,
+ required this.timeSlots,
+ this.backgroundColor,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.all(5),
+ child: Stack(
+ children: [
+ ElevatedButton(
+ style: ButtonStyle(
+ tapTargetSize: MaterialTapTargetSize.shrinkWrap,
+ shape: MaterialStateProperty.all(
+ RoundedRectangleBorder(
+ borderRadius:
+ BorderRadius.circular(CustomProperties.borderRadius),
+ side: isCurrent
+ ? BorderSide(
+ width: 2,
+ color: backgroundColor ??
+ forecast.getColor(context, false),
+ )
+ : BorderSide.none,
+ ),
+ ),
+ padding: MaterialStateProperty.all(
+ const EdgeInsets.only(
+ right: 0,
+ ),
+ ),
+ ),
+ onPressed: onTap ??
+ () async => {
+ await showGeneralDialog(
+ context: context,
+ pageBuilder: (BuildContext context, _, __) {
+ return const SizedBox.shrink();
+ },
+ barrierDismissible: true,
+ transitionBuilder: (context, a1, a2, widget) {
+ return FadeTransition(
+ opacity:
+ Tween(begin: 0.0, end: 1.0).animate(a1),
+ child: BackdropFilter(
+ filter: ImageFilter.blur(
+ sigmaX: CustomProperties.blurSigmaX,
+ sigmaY: CustomProperties.blurSigmaY,
+ ),
+ child: ForecastInformationDialog(
+ forecast: forecast,
+ ),
+ ),
+ );
+ },
+ barrierLabel: MaterialLocalizations.of(context)
+ .modalBarrierDismissLabel,
+ transitionDuration: const Duration(
+ milliseconds: 300,
+ ),
+ ),
+ },
+ child: SizedBox(
+ height: 60,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ _LeadingIconWidget(
+ forecast: forecast,
+ backgroundColor: backgroundColor ??
+ forecast.getColor(
+ context,
+ false,
+ ),
+ ),
+ Flexible(
+ flex: 2,
+ child: _ClosingInfoWidget(
+ forecast: forecast,
+ ),
+ ),
+ Flexible(
+ fit: FlexFit.loose,
+ child: _DurationWidget(
+ forecast: forecast,
+ ),
+ ),
+ Flexible(
+ flex: 2,
+ child: _OpeningInfoWidget(
+ forecast: forecast,
+ ),
+ ),
+ timeSlots.isNotEmpty
+ ? const _TimeSlotWarningWidget()
+ : Container(
+ width: 15,
+ ),
+ ],
+ ),
+ ),
+ ),
+ if (hasPassed)
+ Positioned.fill(
+ child: ClipRect(
+ child: BackdropFilter(
+ filter: ImageFilter.blur(
+ sigmaX: CustomProperties.blurSigmaX,
+ sigmaY: CustomProperties.blurSigmaY,
+ ),
+ child: Center(
+ child: Text(
+ AppLocalizations.of(context)!.passedClosure,
+ style: const TextStyle(
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/forecast/forecast_widget/leading_icon_widget.dart b/lib/widgets/forecast/forecast_widget/leading_icon_widget.dart
new file mode 100644
index 00000000..5823f0df
--- /dev/null
+++ b/lib/widgets/forecast/forecast_widget/leading_icon_widget.dart
@@ -0,0 +1,37 @@
+part of 'forecast_widget.dart';
+
+class _LeadingIconWidget extends StatelessWidget {
+ final AbstractForecast forecast;
+ final Color? backgroundColor;
+
+ const _LeadingIconWidget({
+ Key? key,
+ required this.forecast,
+ required this.backgroundColor,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ width: 55,
+ height: 60,
+ decoration: BoxDecoration(
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(
+ CustomProperties.borderRadius,
+ ),
+ bottomLeft: Radius.circular(
+ CustomProperties.borderRadius,
+ ),
+ ),
+ color: backgroundColor,
+ ),
+ child: Center(
+ child: forecast.getIconWidget(
+ context,
+ true,
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/forecast/forecast_widget/opening_info_widget.dart b/lib/widgets/forecast/forecast_widget/opening_info_widget.dart
new file mode 100644
index 00000000..032c53db
--- /dev/null
+++ b/lib/widgets/forecast/forecast_widget/opening_info_widget.dart
@@ -0,0 +1,41 @@
+part of 'forecast_widget.dart';
+
+class _OpeningInfoWidget extends StatelessWidget {
+ final AbstractForecast forecast;
+
+ const _OpeningInfoWidget({Key? key, required this.forecast})
+ : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ final textTheme = Theme.of(context).textTheme;
+
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ const Icon(
+ Icons.check_circle,
+ size: 18,
+ color: Colors.green,
+ ),
+ Text(
+ MaterialLocalizations.of(context).formatMediumDate(
+ forecast.circulationReOpeningDate,
+ ),
+ style: textTheme.bodySmall,
+ ),
+ ],
+ ),
+ Text(
+ forecast.circulationReOpeningDateString(
+ context,
+ ),
+ style: textTheme.headlineSmall,
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/forecast/forecast_widget/time_slot_warning_widget.dart b/lib/widgets/forecast/forecast_widget/time_slot_warning_widget.dart
new file mode 100644
index 00000000..bf3853c5
--- /dev/null
+++ b/lib/widgets/forecast/forecast_widget/time_slot_warning_widget.dart
@@ -0,0 +1,29 @@
+part of 'forecast_widget.dart';
+
+class _TimeSlotWarningWidget extends StatelessWidget {
+ const _TimeSlotWarningWidget({Key? key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ width: 30,
+ height: 60,
+ decoration: BoxDecoration(
+ borderRadius: const BorderRadius.only(
+ topRight: Radius.circular(
+ CustomProperties.borderRadius,
+ ),
+ bottomRight: Radius.circular(
+ CustomProperties.borderRadius,
+ ),
+ ),
+ color: Theme.of(context).colorScheme.primary,
+ ),
+ child: Icon(
+ Icons.warning_rounded,
+ size: 20,
+ color: Theme.of(context).cardColor,
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/forecast/status_widget.dart b/lib/widgets/forecast/status_widget.dart
deleted file mode 100644
index a58451c7..00000000
--- a/lib/widgets/forecast/status_widget.dart
+++ /dev/null
@@ -1,224 +0,0 @@
-import 'dart:async';
-
-import 'package:chabo/bloc/scroll_status/scroll_status_bloc.dart';
-import 'package:chabo/bloc/status/status_bloc.dart';
-import 'package:chabo/custom_properties.dart';
-import 'package:chabo/custom_widget_state.dart';
-import 'package:chabo/extensions/duration_extension.dart';
-import 'package:chabo/widgets/forecast/forecast_list_item_widget.dart';
-import 'package:chabo/widgets/progress_indicator/custom_circular_progress_indicator.dart';
-import 'package:chabo/widgets/progress_indicator/custom_progress_bar_indicator.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter/scheduler.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:flutter_gen/gen_l10n/app_localizations.dart';
-
-class StatusWidget extends StatefulWidget {
- const StatusWidget({super.key});
-
- @override
- State createState() {
- return StatusWidgetState();
- }
-}
-
-class StatusWidgetState extends CustomWidgetState {
- @override
- void initState() {
- SchedulerBinding.instance.addPostFrameCallback(
- (_) {
- Timer.periodic(
- const Duration(seconds: 1),
- (Timer t) => BlocProvider.of(context).add(
- StatusRefresh(
- context: context,
- ),
- ),
- );
- },
- );
- super.initState();
- }
-
- @override
- Widget build(BuildContext context) {
- return BlocBuilder(
- builder: (context, state) {
- return AnimatedSize(
- curve: Curves.ease,
- duration: const Duration(milliseconds: 800),
- child: AnimatedSwitcher(
- duration: const Duration(seconds: 1),
- reverseDuration: const Duration(milliseconds: 200),
- transitionBuilder: (child, animation) {
- return FadeTransition(
- opacity: animation,
- child: child,
- );
- },
- child: state.statusLifecycle == StatusLifecycle.empty
- ? Padding(
- padding: EdgeInsets.symmetric(
- vertical: MediaQuery.of(context).size.height / 5,
- ),
- child: CustomCircularProgressIndicator(
- message: AppLocalizations.of(context)!.statusLoadMessage,
- ),
- )
- : Column(
- mainAxisSize: MainAxisSize.min,
- mainAxisAlignment: MainAxisAlignment.start,
- children: [
- Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: 30,
- vertical: 10,
- ),
- child: AnimatedContainer(
- duration: const Duration(milliseconds: 500),
- padding: const EdgeInsets.all(10),
- decoration: BoxDecoration(
- color: state.backgroundColor,
- borderRadius: const BorderRadius.all(
- Radius.circular(
- CustomProperties.borderRadius,
- ),
- ),
- ),
- child: AnimatedSwitcher(
- duration: const Duration(milliseconds: 500),
- transitionBuilder:
- (Widget child, Animation animation) {
- return FadeTransition(
- opacity: animation,
- child: child,
- );
- },
- child: Text(
- state.mainMessageStatus,
- key: ValueKey(state.mainMessageStatus),
- textAlign: TextAlign.center,
- style: TextStyle(
- fontSize: 40,
- color: state.foregroundColor,
- ),
- ),
- ),
- ),
- ),
- Padding(
- padding: const EdgeInsets.symmetric(vertical: 5.0),
- child: Column(
- children: [
- Text(
- state.timeMessagePrefix,
- style: const TextStyle(
- fontSize: 20,
- ),
- ),
- !state.durationUntilNextEvent.isNegative
- ? Text(
- state.durationUntilNextEvent
- .durationToString(context),
- style: const TextStyle(
- fontWeight: FontWeight.bold,
- fontSize: 18,
- ),
- )
- : const SizedBox.shrink(),
- state.completionPercentage != -1
- ? Padding(
- padding: const EdgeInsets.symmetric(
- horizontal: 20.0,
- vertical: 5,
- ),
- child: SizedBox(
- height: 10,
- child: ClipRRect(
- borderRadius: const BorderRadius.all(
- Radius.circular(
- CustomProperties.borderRadius,
- ),
- ),
- child: CustomProgressBarIndicator(
- max: 1,
- current: state.completionPercentage,
- color: state.backgroundColor,
- ),
- ),
- ),
- )
- : const SizedBox.shrink(),
- ],
- ),
- ),
- Flexible(
- child: BlocBuilder(
- builder: (context, state) {
- return AnimatedSize(
- curve: Curves.ease,
- duration: const Duration(milliseconds: 800),
- child: AnimatedSwitcher(
- duration: const Duration(seconds: 1),
- reverseDuration:
- const Duration(milliseconds: 200),
- transitionBuilder: (child, animation) {
- return FadeTransition(
- opacity: animation,
- child: child,
- );
- },
- child: state.showCurrentStatus &&
- state.currentTarget != null
- ? Padding(
- padding: const EdgeInsets.only(
- left: 10.0,
- right: 10.0,
- bottom: 15.0,
- ),
- child: ForecastListItemWidget(
- onTap: () =>
- BlocProvider.of(
- context,
- ).add(
- GoTo(
- goTo: state.currentTarget,
- ),
- ),
- hasPassed: false,
- isCurrent: true,
- forecast: state.currentTarget!,
- index: -1,
- timeSlots: const [],
- ),
- )
- : const SizedBox.shrink(),
- ),
- );
- },
- ),
- ),
- Padding(
- padding: const EdgeInsets.only(bottom: 10.0),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceAround,
- children: [
- Text(
- AppLocalizations.of(context)!
- .lisOfUpcomingClosures,
- style: const TextStyle(
- fontSize: 20,
- ),
- ),
- const Icon(Icons.arrow_circle_down),
- ],
- ),
- ),
- ],
- ),
- ),
- );
- },
- );
- }
-}
diff --git a/lib/widgets/forecast/status_widget/current_status_widget.dart b/lib/widgets/forecast/status_widget/current_status_widget.dart
new file mode 100644
index 00000000..02800f11
--- /dev/null
+++ b/lib/widgets/forecast/status_widget/current_status_widget.dart
@@ -0,0 +1,62 @@
+part of 'status_widget.dart';
+
+class _CurrentStatusWidget extends StatelessWidget {
+ final StatusState statusState;
+
+ const _CurrentStatusWidget({Key? key, required this.statusState})
+ : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder(
+ builder: (context, state) {
+ return AnimatedSize(
+ curve: Curves.easeOut,
+ duration: const Duration(
+ milliseconds: CustomProperties.animationDurationMs,
+ ),
+ reverseDuration: const Duration(milliseconds: 0),
+ child: AnimatedSwitcher(
+ duration: const Duration(
+ seconds: 1,
+ ),
+ reverseDuration: const Duration(milliseconds: 0),
+ transitionBuilder: (child, animation) {
+ return FadeTransition(
+ opacity: animation,
+ child: child,
+ );
+ },
+ child: state.showCurrentStatus &&
+ state.currentTarget != null &&
+ statusState.statusWidgetDimension ==
+ StatusWidgetDimension.small
+ ? Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 10,
+ ),
+ child: ForecastWidget(
+ onTap: () => {
+ BlocProvider.of(
+ context,
+ ).add(
+ GoTo(
+ goTo: state.currentTarget,
+ ),
+ ),
+ },
+ hasPassed: false,
+ isCurrent: true,
+ forecast: state.currentTarget!,
+ index: -1,
+ timeSlots: const [],
+ backgroundColor: statusState.backgroundColor,
+ ),
+ )
+ : const SizedBox.shrink(),
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/widgets/forecast/status_widget/layout_widget.dart b/lib/widgets/forecast/status_widget/layout_widget.dart
new file mode 100644
index 00000000..5422214c
--- /dev/null
+++ b/lib/widgets/forecast/status_widget/layout_widget.dart
@@ -0,0 +1,31 @@
+part of 'status_widget.dart';
+
+class _LayoutWidget extends StatelessWidget {
+ final StatusState statusState;
+
+ const _LayoutWidget({
+ Key? key,
+ required this.statusState,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ _TextWidget(
+ statusState: statusState,
+ ),
+ _ProgressIndicatorWidget(
+ statusState: statusState,
+ ),
+ const SizedBox(
+ height: 10,
+ ),
+ _CurrentStatusWidget(
+ statusState: statusState,
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/forecast/status_widget/progress_indicator_widget.dart b/lib/widgets/forecast/status_widget/progress_indicator_widget.dart
new file mode 100644
index 00000000..aa58bb66
--- /dev/null
+++ b/lib/widgets/forecast/status_widget/progress_indicator_widget.dart
@@ -0,0 +1,74 @@
+part of 'status_widget.dart';
+
+class _ProgressIndicatorWidget extends StatelessWidget {
+ final StatusState statusState;
+
+ const _ProgressIndicatorWidget({
+ Key? key,
+ required this.statusState,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ AnimatedSwitcher(
+ duration: const Duration(
+ milliseconds: CustomProperties.shortAnimationDurationMs,
+ ),
+ reverseDuration: const Duration(
+ milliseconds: 0,
+ ),
+ switchInCurve: Curves.ease,
+ switchOutCurve: Curves.ease,
+ transitionBuilder: (child, animation) {
+ return FadeTransition(
+ opacity: animation,
+ child: child,
+ );
+ },
+ child: !(statusState.statusWidgetDimension ==
+ StatusWidgetDimension.small)
+ ? Text(
+ statusState.timeMessagePrefix,
+ style: Theme.of(context).textTheme.labelLarge!.copyWith(
+ fontSize: 20,
+ ),
+ )
+ : const SizedBox.shrink(),
+ ),
+ !statusState.durationUntilNextEvent.isNegative
+ ? Text(
+ statusState.durationUntilNextEvent.durationToString(context),
+ style: Theme.of(context).textTheme.titleMedium!.copyWith(
+ fontSize: 18,
+ fontWeight: FontWeight.bold,
+ ),
+ )
+ : const SizedBox.shrink(),
+ statusState.completionPercentage != -1
+ ? Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 20.0,
+ ),
+ child: SizedBox(
+ height: 10,
+ child: ClipRRect(
+ borderRadius: const BorderRadius.all(
+ Radius.circular(
+ CustomProperties.borderRadius,
+ ),
+ ),
+ child: CustomProgressBarIndicator(
+ max: 1,
+ current: statusState.completionPercentage,
+ color: statusState.backgroundColor,
+ ),
+ ),
+ ),
+ )
+ : const SizedBox.shrink(),
+ ],
+ );
+ }
+}
diff --git a/lib/widgets/forecast/status_widget/status_widget.dart b/lib/widgets/forecast/status_widget/status_widget.dart
new file mode 100644
index 00000000..cedc2281
--- /dev/null
+++ b/lib/widgets/forecast/status_widget/status_widget.dart
@@ -0,0 +1,80 @@
+import 'dart:async';
+
+import 'package:chabo/bloc/scroll_status/scroll_status_bloc.dart';
+import 'package:chabo/bloc/status/status_bloc.dart';
+import 'package:chabo/custom_properties.dart';
+import 'package:chabo/custom_widget_state.dart';
+import 'package:chabo/extensions/duration_extension.dart';
+import 'package:chabo/helpers/device_helper.dart';
+import 'package:chabo/widgets/forecast/forecast_widget/forecast_widget.dart';
+import 'package:chabo/widgets/progress_indicator/custom_circular_progress_indicator.dart';
+import 'package:chabo/widgets/progress_indicator/custom_progress_bar_indicator.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/scheduler.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+
+part 'current_status_widget.dart';
+
+part 'layout_widget.dart';
+
+part 'progress_indicator_widget.dart';
+
+part 'text_widget.dart';
+
+class StatusWidget extends StatefulWidget {
+ const StatusWidget({super.key});
+
+ @override
+ State createState() {
+ return StatusWidgetState();
+ }
+}
+
+class StatusWidgetState extends CustomWidgetState {
+ @override
+ void initState() {
+ SchedulerBinding.instance.addPostFrameCallback(
+ (_) {
+ if (mounted) {
+ Timer.periodic(
+ const Duration(seconds: 1),
+ (Timer t) => BlocProvider.of(context).add(
+ StatusRefresh(
+ context: context,
+ ),
+ ),
+ );
+ }
+ },
+ );
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder(
+ builder: (context, state) {
+ return AnimatedSwitcher(
+ duration: const Duration(seconds: 1),
+ reverseDuration: const Duration(
+ milliseconds: CustomProperties.shortAnimationDurationMs,
+ ),
+ transitionBuilder: (child, animation) {
+ return FadeTransition(
+ opacity: animation,
+ child: child,
+ );
+ },
+ child: state.statusLifecycle == StatusLifecycle.empty
+ ? CustomCircularProgressIndicator(
+ message: AppLocalizations.of(context)!.statusLoadMessage,
+ )
+ : _LayoutWidget(
+ statusState: state,
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/widgets/forecast/status_widget/text_widget.dart b/lib/widgets/forecast/status_widget/text_widget.dart
new file mode 100644
index 00000000..1ca739d8
--- /dev/null
+++ b/lib/widgets/forecast/status_widget/text_widget.dart
@@ -0,0 +1,68 @@
+part of 'status_widget.dart';
+
+class _TextWidget extends StatelessWidget {
+ final StatusState statusState;
+
+ const _TextWidget({
+ Key? key,
+ required this.statusState,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 15,
+ vertical: 5,
+ ),
+ child: Container(
+ width: double.infinity,
+ padding: const EdgeInsets.symmetric(vertical: 13, horizontal: 8),
+ decoration: BoxDecoration(
+ color: statusState.backgroundColor,
+ borderRadius: const BorderRadius.all(
+ Radius.circular(
+ CustomProperties.borderRadius,
+ ),
+ ),
+ ),
+ child: AnimatedSize(
+ curve: Curves.ease,
+ duration: const Duration(
+ milliseconds: CustomProperties.shortAnimationDurationMs,
+ ),
+ child: AnimatedSwitcher(
+ duration: const Duration(
+ milliseconds: CustomProperties.shortAnimationDurationMs,
+ ),
+ reverseDuration: const Duration(
+ milliseconds: 0,
+ ),
+ transitionBuilder: (child, animation) {
+ return FadeTransition(
+ opacity: animation,
+ child: child,
+ );
+ },
+ child: Text(
+ key: ValueKey(
+ statusState.statusWidgetDimension.toString(),
+ ),
+ statusState.mainMessageStatus,
+ textAlign: TextAlign.center,
+ style: Theme.of(context).textTheme.headlineLarge?.copyWith(
+ color: statusState.foregroundColor,
+ fontWeight: FontWeight.bold,
+ fontSize: DeviceHelper.isMobile(context)
+ ? 30
+ : DeviceHelper.isPortrait(context)
+ ? 30
+ : 55,
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/widgets/progress_indicator/custom_circular_progress_indicator.dart b/lib/widgets/progress_indicator/custom_circular_progress_indicator.dart
index 23cf3277..b8621cf9 100644
--- a/lib/widgets/progress_indicator/custom_circular_progress_indicator.dart
+++ b/lib/widgets/progress_indicator/custom_circular_progress_indicator.dart
@@ -24,9 +24,9 @@ class CustomCircularProgressIndicator extends StatelessWidget {
padding: const EdgeInsets.all(8.0),
child: Text(
message,
- style: const TextStyle(
- fontWeight: FontWeight.bold,
- ),
+ style: Theme.of(context).textTheme.bodyMedium!.copyWith(
+ fontWeight: FontWeight.bold,
+ ),
),
),
],
diff --git a/lib/widgets/progress_indicator/custom_progress_bar_indicator.dart b/lib/widgets/progress_indicator/custom_progress_bar_indicator.dart
index 4bd6ede0..67cc1b6c 100644
--- a/lib/widgets/progress_indicator/custom_progress_bar_indicator.dart
+++ b/lib/widgets/progress_indicator/custom_progress_bar_indicator.dart
@@ -1,3 +1,4 @@
+import 'package:chabo/custom_properties.dart';
import 'package:flutter/material.dart';
class CustomProgressBarIndicator extends StatelessWidget {
@@ -23,7 +24,9 @@ class CustomProgressBarIndicator extends StatelessWidget {
alignment: Alignment.centerLeft,
children: [
AnimatedContainer(
- duration: const Duration(milliseconds: 500),
+ duration: const Duration(
+ milliseconds: CustomProperties.animationDurationMs,
+ ),
width: x,
height: 15,
decoration: BoxDecoration(
@@ -35,7 +38,9 @@ class CustomProgressBarIndicator extends StatelessWidget {
),
),
AnimatedContainer(
- duration: const Duration(milliseconds: 500),
+ duration: const Duration(
+ milliseconds: CustomProperties.animationDurationMs,
+ ),
width: percent,
height: 10,
decoration: BoxDecoration(
diff --git a/lib/widgets/theme_switcher_widget.dart b/lib/widgets/theme_switcher_widget.dart
index c6aee3b1..ae97a19b 100644
--- a/lib/widgets/theme_switcher_widget.dart
+++ b/lib/widgets/theme_switcher_widget.dart
@@ -1,5 +1,6 @@
import 'package:animated_toggle_switch/animated_toggle_switch.dart';
import 'package:chabo/bloc/theme/theme_bloc.dart';
+import 'package:chabo/custom_properties.dart';
import 'package:chabo/models/enums/theme_state_status.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -55,10 +56,10 @@ class ThemeSwitcherWidget extends StatelessWidget {
),
AnimatedSwitcher(
duration: const Duration(
- milliseconds: 200,
+ milliseconds: CustomProperties.shortAnimationDurationMs,
),
reverseDuration: const Duration(
- milliseconds: 200,
+ milliseconds: CustomProperties.shortAnimationDurationMs,
),
transitionBuilder: (Widget child, Animation animation) {
return SlideTransition(
diff --git a/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus b/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus
index 2fb5e920..5ea7677c 120000
--- a/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus
+++ b/linux/flutter/ephemeral/.plugin_symlinks/package_info_plus
@@ -1 +1 @@
-C:/Users/Valentin/AppData/Local/Pub/Cache/hosted/pub.dev/package_info_plus-3.0.3/
\ No newline at end of file
+C:/Users/Valentin/AppData/Local/Pub/Cache/hosted/pub.dev/package_info_plus-4.0.0/
\ No newline at end of file
diff --git a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux
index 3d69ff4a..83625431 120000
--- a/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux
+++ b/linux/flutter/ephemeral/.plugin_symlinks/shared_preferences_linux
@@ -1 +1 @@
-C:/Users/Valentin/AppData/Local/Pub/Cache/hosted/pub.dev/shared_preferences_linux-2.1.5/
\ No newline at end of file
+C:/Users/Valentin/AppData/Local/Pub/Cache/hosted/pub.dev/shared_preferences_linux-2.2.0/
\ No newline at end of file
diff --git a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux
index a273bc61..c2842472 120000
--- a/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux
+++ b/linux/flutter/ephemeral/.plugin_symlinks/url_launcher_linux
@@ -1 +1 @@
-C:/Users/Valentin/AppData/Local/Pub/Cache/hosted/pub.dev/url_launcher_linux-3.0.4/
\ No newline at end of file
+C:/Users/Valentin/AppData/Local/Pub/Cache/hosted/pub.dev/url_launcher_linux-3.0.5/
\ No newline at end of file
diff --git a/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig
index 57995472..5dc813a2 100644
--- a/macos/Flutter/ephemeral/Flutter-Generated.xcconfig
+++ b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig
@@ -3,8 +3,8 @@ FLUTTER_ROOT=D:\src\Flutter
FLUTTER_APPLICATION_PATH=D:\Code\chabo
COCOAPODS_PARALLEL_CODE_SIGN=true
FLUTTER_BUILD_DIR=build
-FLUTTER_BUILD_NAME=1.6.0
-FLUTTER_BUILD_NUMBER=1.6.0
+FLUTTER_BUILD_NAME=1.6.1
+FLUTTER_BUILD_NUMBER=1.6.1
DART_OBFUSCATION=false
TRACK_WIDGET_CREATION=true
TREE_SHAKE_ICONS=false
diff --git a/macos/Flutter/ephemeral/flutter_export_environment.sh b/macos/Flutter/ephemeral/flutter_export_environment.sh
index eb328ef2..6c50bb77 100644
--- a/macos/Flutter/ephemeral/flutter_export_environment.sh
+++ b/macos/Flutter/ephemeral/flutter_export_environment.sh
@@ -4,8 +4,8 @@ export "FLUTTER_ROOT=D:\src\Flutter"
export "FLUTTER_APPLICATION_PATH=D:\Code\chabo"
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
export "FLUTTER_BUILD_DIR=build"
-export "FLUTTER_BUILD_NAME=1.6.0"
-export "FLUTTER_BUILD_NUMBER=1.6.0"
+export "FLUTTER_BUILD_NAME=1.6.1"
+export "FLUTTER_BUILD_NUMBER=1.6.1"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=true"
export "TREE_SHAKE_ICONS=false"
diff --git a/pubspec.lock b/pubspec.lock
index bca39eb5..20dae7db 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -53,26 +53,26 @@ packages:
dependency: transitive
description:
name: archive
- sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d
+ sha256: "0c8368c9b3f0abbc193b9d6133649a614204b528982bebc7026372d61677ce3a"
url: "https://pub.dev"
source: hosted
- version: "3.3.6"
+ version: "3.3.7"
args:
dependency: transitive
description:
name: args
- sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440"
+ sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a
url: "https://pub.dev"
source: hosted
- version: "2.4.0"
+ version: "2.4.1"
async:
dependency: transitive
description:
name: async
- sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0
+ sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
- version: "2.10.0"
+ version: "2.11.0"
bloc:
dependency: transitive
description:
@@ -89,6 +89,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.1"
+ bloc_test:
+ dependency: "direct dev"
+ description:
+ name: bloc_test
+ sha256: ffbb60c17ee3d8e3784cb78071088e353199057233665541e8ac6cd438dca8ad
+ url: "https://pub.dev"
+ source: hosted
+ version: "9.1.1"
boolean_selector:
dependency: transitive
description:
@@ -97,22 +105,46 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.1"
+ build:
+ dependency: transitive
+ description:
+ name: build
+ sha256: "43865b79fbb78532e4bff7c33087aa43b1d488c4fdef014eaef568af6d8016dc"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
+ built_collection:
+ dependency: transitive
+ description:
+ name: built_collection
+ sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
+ url: "https://pub.dev"
+ source: hosted
+ version: "5.1.1"
+ built_value:
+ dependency: transitive
+ description:
+ name: built_value
+ sha256: "2f17434bd5d52a26762043d6b43bb53b3acd029b4d9071a329f46d67ef297e6d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "8.5.0"
characters:
dependency: transitive
description:
name: characters
- sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c
+ sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
- version: "1.2.1"
+ version: "1.3.0"
checked_yaml:
dependency: transitive
description:
name: checked_yaml
- sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311"
+ sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
url: "https://pub.dev"
source: hosted
- version: "2.0.2"
+ version: "2.0.3"
cli_util:
dependency: transitive
description:
@@ -129,14 +161,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
+ code_builder:
+ dependency: transitive
+ description:
+ name: code_builder
+ sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.4.0"
collection:
dependency: transitive
description:
name: collection
- sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0
+ sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
url: "https://pub.dev"
source: hosted
- version: "1.17.0"
+ version: "1.17.1"
convert:
dependency: transitive
description:
@@ -145,14 +185,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.1"
+ coverage:
+ dependency: transitive
+ description:
+ name: coverage
+ sha256: "2fb815080e44a09b85e0f2ca8a820b15053982b2e714b59267719e8a9ff17097"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.6.3"
crypto:
dependency: transitive
description:
name: crypto
- sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
+ sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
- version: "3.0.2"
+ version: "3.0.3"
csslib:
dependency: transitive
description:
@@ -201,6 +249,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.8"
+ diff_match_patch:
+ dependency: transitive
+ description:
+ name: diff_match_patch
+ sha256: "2efc9e6e8f449d0abe15be240e2c2a3bcd977c8d126cfd70598aee60af35c0a4"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.4.1"
enum_to_string:
dependency: "direct main"
description:
@@ -229,10 +285,10 @@ packages:
dependency: transitive
description:
name: ffi
- sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978
+ sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99
url: "https://pub.dev"
source: hosted
- version: "2.0.1"
+ version: "2.0.2"
file:
dependency: "direct main"
description:
@@ -241,6 +297,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.1.4"
+ fixnum:
+ dependency: transitive
+ description:
+ name: fixnum
+ sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.0"
flutter:
dependency: "direct main"
description: flutter
@@ -258,10 +322,10 @@ packages:
dependency: "direct dev"
description:
name: flutter_launcher_icons
- sha256: "8546a9b9510e1a260b8d55fb2d07096e8a8552c6a2c2bf529100344894b2b41a"
+ sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
url: "https://pub.dev"
source: hosted
- version: "0.13.0"
+ version: "0.13.1"
flutter_lints:
dependency: "direct dev"
description:
@@ -274,26 +338,26 @@ packages:
dependency: "direct main"
description:
name: flutter_local_notifications
- sha256: "2876372952b65ca7f684e698eba22bda1cf581fa071dd30ba2f01900f507d0d1"
+ sha256: ee6ee56855aa920899b68586b538474d086c149932220b47b92502cbfb5ba5e5
url: "https://pub.dev"
source: hosted
- version: "14.0.0+1"
+ version: "14.0.0+2"
flutter_local_notifications_linux:
dependency: transitive
description:
name: flutter_local_notifications_linux
- sha256: "909bb95de05a2e793503a2437146285a2f600cd0b3f826e26b870a334d8586d7"
+ sha256: "33f741ef47b5f63cc7f78fe75eeeac7e19f171ff3c3df054d84c1e38bedb6a03"
url: "https://pub.dev"
source: hosted
- version: "4.0.0"
+ version: "4.0.0+1"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
- sha256: "63235c42de5b6c99846969a27ad0209c401e6b77b0498939813725b5791c107c"
+ sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef"
url: "https://pub.dev"
source: hosted
- version: "7.0.0"
+ version: "7.0.0+1"
flutter_localizations:
dependency: "direct main"
description: flutter
@@ -325,6 +389,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "10.4.0"
+ frontend_server_client:
+ dependency: transitive
+ description:
+ name: frontend_server_client
+ sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.2.0"
glob:
dependency: transitive
description:
@@ -337,10 +409,10 @@ packages:
dependency: "direct main"
description:
name: google_fonts
- sha256: "927573f2e8a8d65c17931e21918ad0ab0666b1b636537de7c4932bdb487b190f"
+ sha256: "6b6f10f0ce3c42f6552d1c70d2c28d764cf22bb487f50f66cca31dcd5194f4d6"
url: "https://pub.dev"
source: hosted
- version: "4.0.3"
+ version: "4.0.4"
google_mobile_ads:
dependency: "direct main"
description:
@@ -361,10 +433,18 @@ packages:
dependency: "direct main"
description:
name: http
- sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482"
+ sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.13.6"
+ http_multi_server:
+ dependency: transitive
+ description:
+ name: http_multi_server
+ sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
url: "https://pub.dev"
source: hosted
- version: "0.13.5"
+ version: "3.2.1"
http_parser:
dependency: transitive
description:
@@ -377,58 +457,74 @@ packages:
dependency: transitive
description:
name: image
- sha256: "483a389d6ccb292b570c31b3a193779b1b0178e7eb571986d9a49904b6861227"
+ sha256: a72242c9a0ffb65d03de1b7113bc4e189686fc07c7147b8b41811d0dd0e0d9bf
url: "https://pub.dev"
source: hosted
- version: "4.0.15"
+ version: "4.0.17"
intl:
dependency: "direct main"
description:
name: intl
- sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91"
+ sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6
url: "https://pub.dev"
source: hosted
- version: "0.17.0"
+ version: "0.18.0"
+ io:
+ dependency: transitive
+ description:
+ name: io
+ sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
js:
dependency: transitive
description:
name: js
- sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7"
+ sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
- version: "0.6.5"
+ version: "0.6.7"
json_annotation:
dependency: transitive
description:
name: json_annotation
- sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317
+ sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467
url: "https://pub.dev"
source: hosted
- version: "4.8.0"
+ version: "4.8.1"
lints:
dependency: transitive
description:
name: lints
- sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593"
+ sha256: "6b0206b0bf4f04961fc5438198ccb3a885685cd67d4d4a32cc20ad7f8adbe015"
url: "https://pub.dev"
source: hosted
- version: "2.0.1"
+ version: "2.1.0"
+ logging:
+ dependency: transitive
+ description:
+ name: logging
+ sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.1"
markdown:
dependency: transitive
description:
name: markdown
- sha256: b3c60dee8c2af50ad0e6e90cceba98e47718a6ee0a7a6772c77846a0cc21f78b
+ sha256: "8e332924094383133cee218b676871f42db2514f1f6ac617b6cf6152a7faab8e"
url: "https://pub.dev"
source: hosted
- version: "7.0.1"
+ version: "7.1.0"
matcher:
dependency: transitive
description:
name: matcher
- sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72"
+ sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
url: "https://pub.dev"
source: hosted
- version: "0.12.13"
+ version: "0.12.15"
material_color_utilities:
dependency: transitive
description:
@@ -441,10 +537,34 @@ packages:
dependency: transitive
description:
name: meta
- sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42"
+ sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.9.1"
+ mime:
+ dependency: transitive
+ description:
+ name: mime
+ sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
+ mockito:
+ dependency: "direct dev"
+ description:
+ name: mockito
+ sha256: dd61809f04da1838a680926de50a9e87385c1de91c6579629c3d1723946e8059
url: "https://pub.dev"
source: hosted
- version: "1.8.0"
+ version: "5.4.0"
+ mocktail:
+ dependency: transitive
+ description:
+ name: mocktail
+ sha256: "80a996cd9a69284b3dc521ce185ffe9150cde69767c2d3a0720147d93c0cef53"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.3.0"
nested:
dependency: transitive
description:
@@ -453,6 +573,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.0"
+ node_preamble:
+ dependency: transitive
+ description:
+ name: node_preamble
+ sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.2"
package_config:
dependency: transitive
description:
@@ -465,10 +593,10 @@ packages:
dependency: "direct main"
description:
name: package_info_plus
- sha256: "8df5ab0a481d7dc20c0e63809e90a588e496d276ba53358afc4c4443d0a00697"
+ sha256: d39e8fbff4c5aef4592737e25ad6ac500df006ce7a7a8e1f838ce1256e167542
url: "https://pub.dev"
source: hosted
- version: "3.0.3"
+ version: "4.0.0"
package_info_plus_platform_interface:
dependency: transitive
description:
@@ -481,34 +609,34 @@ packages:
dependency: transitive
description:
name: path
- sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b
+ sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev"
source: hosted
- version: "1.8.2"
+ version: "1.8.3"
path_provider:
dependency: transitive
description:
name: path_provider
- sha256: "04890b994ee89bfa80bf3080bfec40d5a92c5c7a785ebb02c13084a099d2b6f9"
+ sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2"
url: "https://pub.dev"
source: hosted
- version: "2.0.13"
+ version: "2.0.15"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
- sha256: "019f18c9c10ae370b08dce1f3e3b73bc9f58e7f087bb5e921f06529438ac0ae7"
+ sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86"
url: "https://pub.dev"
source: hosted
- version: "2.0.24"
+ version: "2.0.27"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
- sha256: "12eee51abdf4d34c590f043f45073adbb45514a108bd9db4491547a2fd891059"
+ sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3"
url: "https://pub.dev"
source: hosted
- version: "2.2.0"
+ version: "2.2.3"
path_provider_linux:
dependency: transitive
description:
@@ -529,18 +657,18 @@ packages:
dependency: transitive
description:
name: path_provider_windows
- sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130
+ sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6
url: "https://pub.dev"
source: hosted
- version: "2.1.5"
+ version: "2.1.6"
petitparser:
dependency: transitive
description:
name: petitparser
- sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4"
+ sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
url: "https://pub.dev"
source: hosted
- version: "5.1.0"
+ version: "5.4.0"
platform:
dependency: transitive
description:
@@ -561,10 +689,18 @@ packages:
dependency: transitive
description:
name: pointycastle
- sha256: "57b6b78df14175658f09c5dfcfc51a46ad9561a3504fe679913dab404d0cc0f2"
+ sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
url: "https://pub.dev"
source: hosted
- version: "3.7.0"
+ version: "3.7.3"
+ pool:
+ dependency: transitive
+ description:
+ name: pool
+ sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.5.1"
process:
dependency: transitive
description:
@@ -601,63 +737,119 @@ packages:
dependency: "direct main"
description:
name: shared_preferences
- sha256: ee6257848f822b8481691f20c3e6d2bfee2e9eccb2a3d249907fcfb198c55b41
+ sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022"
url: "https://pub.dev"
source: hosted
- version: "2.0.18"
+ version: "2.1.1"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
- sha256: ad423a80fe7b4e48b50d6111b3ea1027af0e959e49d485712e134863d9c1c521
+ sha256: "6478c6bbbecfe9aced34c483171e90d7c078f5883558b30ec3163cf18402c749"
url: "https://pub.dev"
source: hosted
- version: "2.0.17"
+ version: "2.1.4"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
- sha256: "1e755f8583229f185cfca61b1d80fb2344c9d660e1c69ede5450d8f478fa5310"
+ sha256: e014107bb79d6d3297196f4f2d0db54b5d1f85b8ea8ff63b8e8b391a02700feb
url: "https://pub.dev"
source: hosted
- version: "2.1.5"
+ version: "2.2.2"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
- sha256: "3a59ed10890a8409ad0faad7bb2957dab4b92b8fbe553257b05d30ed8af2c707"
+ sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa"
url: "https://pub.dev"
source: hosted
- version: "2.1.5"
+ version: "2.2.0"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
- sha256: "824bfd02713e37603b2bdade0842e47d56e7db32b1dcdd1cae533fb88e2913fc"
+ sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d
url: "https://pub.dev"
source: hosted
- version: "2.1.1"
+ version: "2.2.0"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
- sha256: "0dc2633f215a3d4aa3184c9b2c5766f4711e4e5a6b256e62aafee41f89f1bfb8"
+ sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5"
url: "https://pub.dev"
source: hosted
- version: "2.0.6"
+ version: "2.1.0"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
- sha256: "71bcd669bb9cdb6b39f22c4a7728b6d49e934f6cba73157ffa5a54f1eed67436"
+ sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173"
url: "https://pub.dev"
source: hosted
- version: "2.1.5"
+ version: "2.2.0"
+ shelf:
+ dependency: transitive
+ description:
+ name: shelf
+ sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.1"
+ shelf_packages_handler:
+ dependency: transitive
+ description:
+ name: shelf_packages_handler
+ sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.0.2"
+ shelf_static:
+ dependency: transitive
+ description:
+ name: shelf_static
+ sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.2"
+ shelf_web_socket:
+ dependency: transitive
+ description:
+ name: shelf_web_socket
+ sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
+ source_gen:
+ dependency: transitive
+ description:
+ name: source_gen
+ sha256: "373f96cf5a8744bc9816c1ff41cf5391bbdbe3d7a96fe98c622b6738a8a7bd33"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.2"
+ source_map_stack_trace:
+ dependency: transitive
+ description:
+ name: source_map_stack_trace
+ sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.1"
+ source_maps:
+ dependency: transitive
+ description:
+ name: source_maps
+ sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.10.12"
source_span:
dependency: transitive
description:
@@ -706,70 +898,86 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.2.1"
+ test:
+ dependency: transitive
+ description:
+ name: test
+ sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.24.1"
test_api:
dependency: transitive
description:
name: test_api
- sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206
+ sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
url: "https://pub.dev"
source: hosted
- version: "0.4.16"
+ version: "0.5.1"
+ test_core:
+ dependency: transitive
+ description:
+ name: test_core
+ sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.5.1"
timezone:
dependency: "direct main"
description:
name: timezone
- sha256: "24c8fcdd49a805d95777a39064862133ff816ebfffe0ceff110fb5960e557964"
+ sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0"
url: "https://pub.dev"
source: hosted
- version: "0.9.1"
+ version: "0.9.2"
typed_data:
dependency: transitive
description:
name: typed_data
- sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
+ sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
- version: "1.3.1"
+ version: "1.3.2"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
- sha256: "75f2846facd11168d007529d6cd8fcb2b750186bea046af9711f10b907e1587e"
+ sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3
url: "https://pub.dev"
source: hosted
- version: "6.1.10"
+ version: "6.1.11"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
- sha256: "845530e5e05db5500c1a4c1446785d60cbd8f9bd45e21e7dd643a3273bb4bbd1"
+ sha256: "7aac14be5f4731b923cc697ae2d42043945076cd0dbb8806baecc92c1dc88891"
url: "https://pub.dev"
source: hosted
- version: "6.0.25"
+ version: "6.0.33"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
- sha256: "3dedc66ca3c0bef9e6a93c0999aee102556a450afcc1b7bcfeace7a424927d92"
+ sha256: "9af7ea73259886b92199f9e42c116072f05ff9bea2dcb339ab935dfc957392c2"
url: "https://pub.dev"
source: hosted
- version: "6.1.3"
+ version: "6.1.4"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
- sha256: "206fb8334a700ef7754d6a9ed119e7349bc830448098f21a69bf1b4ed038cabc"
+ sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5"
url: "https://pub.dev"
source: hosted
- version: "3.0.4"
+ version: "3.0.5"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
- sha256: "0ef2b4f97942a16523e51256b799e9aa1843da6c60c55eefbfa9dbc2dcb8331a"
+ sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e"
url: "https://pub.dev"
source: hosted
- version: "3.0.4"
+ version: "3.0.5"
url_launcher_platform_interface:
dependency: transitive
description:
@@ -790,10 +998,10 @@ packages:
dependency: transitive
description:
name: url_launcher_windows
- sha256: a83ba3607a507758669cfafb03f9de09bf6e6280c14d9b9cb18f013e406dcacd
+ sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771"
url: "https://pub.dev"
source: hosted
- version: "3.0.5"
+ version: "3.0.6"
uuid:
dependency: transitive
description:
@@ -818,14 +1026,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.3.3"
+ vm_service:
+ dependency: transitive
+ description:
+ name: vm_service
+ sha256: f3743ca475e0c9ef71df4ba15eb2d7684eecd5c8ba20a462462e4e8b561b2e11
+ url: "https://pub.dev"
+ source: hosted
+ version: "11.6.0"
watcher:
dependency: transitive
description:
name: watcher
- sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
+ sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.0"
+ web_socket_channel:
+ dependency: transitive
+ description:
+ name: web_socket_channel
+ sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
url: "https://pub.dev"
source: hosted
- version: "1.0.2"
+ version: "2.4.0"
+ webkit_inspection_protocol:
+ dependency: transitive
+ description:
+ name: webkit_inspection_protocol
+ sha256: "67d3a8b6c79e1987d19d848b0892e582dbb0c66c57cc1fef58a177dd2aa2823d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.0"
webview_flutter:
dependency: transitive
description:
@@ -838,10 +1070,10 @@ packages:
dependency: transitive
description:
name: webview_flutter_android
- sha256: d6cf18cd6c809c5a9294cd99707a21986aac4e08c87e1916ce2590315fb55d3a
+ sha256: "1acea8def62592123e2fbbca164ed8681a98a890bdcbb88f916d5b4a22687759"
url: "https://pub.dev"
source: hosted
- version: "3.6.2"
+ version: "3.7.0"
webview_flutter_platform_interface:
dependency: transitive
description:
@@ -854,42 +1086,42 @@ packages:
dependency: transitive
description:
name: webview_flutter_wkwebview
- sha256: c94d242d8cbe1012c06ba7ac790c46d6e6b68723b7d34f8c74ed19f68d166f49
+ sha256: "4646bb68297803bdbb96d46853e8fcb560d6cb5e04153fa64581535767875dfe"
url: "https://pub.dev"
source: hosted
- version: "3.4.0"
+ version: "3.4.3"
win32:
dependency: transitive
description:
name: win32
- sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
+ sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c"
url: "https://pub.dev"
source: hosted
- version: "3.1.3"
+ version: "4.1.4"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
- sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
+ sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1
url: "https://pub.dev"
source: hosted
- version: "0.2.0+3"
+ version: "1.0.0"
xml:
dependency: transitive
description:
name: xml
- sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5"
+ sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
url: "https://pub.dev"
source: hosted
- version: "6.2.2"
+ version: "6.3.0"
yaml:
dependency: transitive
description:
name: yaml
- sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370"
+ sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
url: "https://pub.dev"
source: hosted
- version: "3.1.1"
+ version: "3.1.2"
sdks:
- dart: ">=2.19.0 <3.0.0"
- flutter: ">=3.7.7"
+ dart: ">=3.0.0 <4.0.0"
+ flutter: ">=3.10.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 6dc9baa8..829c346e 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,11 +3,11 @@ description: Mobile app to get the closing and opening schedules of the Chaban D
publish_to: 'none'
-version: 1.6.1
+version: 1.8.1
environment:
- sdk: '>=2.17.6 <3.0.0'
- flutter: '3.7.7'
+ sdk: '>=2.19.0 <3.0.0'
+ flutter: '3.10.0'
dependencies:
animated_toggle_switch: ^0.6.2
@@ -27,8 +27,8 @@ dependencies:
google_fonts: ^4.0.0
google_mobile_ads: ^3.0.0
http: ^0.13.0
- intl: ^0.17.0
- package_info_plus: ^3.0.3
+ intl: ^0.18.0
+ package_info_plus: ^4.0.0
shared_preferences: ^2.0.17
stream_transform: ^2.0.0
timezone: ^0.9.1
@@ -42,6 +42,8 @@ dev_dependencies:
flutter_lints: ^2.0.0
flutter_launcher_icons: ^0.13.0
dart_code_metrics: ^5.7.3
+ bloc_test: ^9.1.1
+ mockito: ^5.4.0
flutter:
generate: true
diff --git a/test/services/storage_service_test.dart b/test/services/storage_service_test.dart
new file mode 100644
index 00000000..8b5f22ea
--- /dev/null
+++ b/test/services/storage_service_test.dart
@@ -0,0 +1,101 @@
+import 'package:chabo/models/enums/day.dart';
+import 'package:chabo/models/enums/theme_state_status.dart';
+import 'package:chabo/models/time_slot.dart';
+import 'package:chabo/service/storage_service.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+void main() {
+ late final StorageService storageService;
+
+ setUpAll(() async {
+ SharedPreferences.setMockInitialValues({});
+ final sharedPreferences = await SharedPreferences.getInstance();
+ storageService = StorageService(sharedPreferences: sharedPreferences);
+ });
+
+ group('StorageService TESTS', () {
+ test('Save & Read String', () async {
+ final saveResult =
+ await storageService.saveString('KEY_STRING', 'STRING');
+ final readResult = storageService.readString('KEY_STRING');
+ expect(saveResult, true);
+ expect(readResult, 'STRING');
+ });
+
+ test('Save & Read Bool', () async {
+ final saveResult = await storageService.saveBool('KEY_BOOL', false);
+ final readResult = storageService.readBool('KEY_BOOL');
+ expect(saveResult, true);
+ expect(readResult, false);
+ });
+
+ test('Save & Read Duration', () async {
+ final saveResult = await storageService.saveDuration(
+ 'KEY_DURATION',
+ const Duration(
+ hours: 1,
+ ),
+ );
+ final readResult = storageService.readDuration('KEY_DURATION');
+ expect(saveResult, true);
+ expect(readResult, const Duration(hours: 1));
+ });
+
+ test('Save & Read TimeOfDay', () async {
+ final saveResult = await storageService.saveTimeOfDay(
+ 'KEY_TIMEOFDAY',
+ const TimeOfDay(
+ hour: 13,
+ minute: 20,
+ ),
+ );
+ final readResult = storageService.readTimeOfDay('KEY_TIMEOFDAY');
+ expect(saveResult, true);
+ expect(readResult, const TimeOfDay(hour: 13, minute: 20));
+ });
+
+ test('Save & Read Day', () async {
+ final saveResult = await storageService.saveDay(
+ 'KEY_DAY',
+ Day.monday,
+ );
+ final readResult = storageService.readDay('KEY_DAY');
+ expect(saveResult, true);
+ expect(readResult, Day.monday);
+ });
+
+ test('Save & Read Theme', () async {
+ final saveResult = await storageService.saveTheme(
+ 'KEY_THEME',
+ ThemeStateStatus.light,
+ );
+ final readResult = storageService.readTheme('KEY_THEME');
+ expect(saveResult, true);
+ expect(readResult, ThemeStateStatus.light);
+ });
+
+ test('Save & Read TimeSlots', () async {
+ final timeSlots = [
+ const TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 8, minute: 0),
+ to: TimeOfDay(hour: 10, minute: 0),
+ ),
+ const TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 18, minute: 0),
+ to: TimeOfDay(hour: 20, minute: 0),
+ ),
+ ];
+ final saveResult = await storageService.saveTimeSlots(
+ 'KEY_TIMESLOTS',
+ timeSlots,
+ );
+ final readResult = storageService.readTimeSlots('KEY_TIMESLOTS');
+ expect(saveResult, true);
+ expect(readResult, timeSlots);
+ });
+ });
+}
diff --git a/test/units/boat_forecast_test.dart b/test/units/boat_forecast_test.dart
new file mode 100644
index 00000000..ee452a45
--- /dev/null
+++ b/test/units/boat_forecast_test.dart
@@ -0,0 +1,228 @@
+import 'package:chabo/models/boat.dart';
+import 'package:chabo/models/boat_forecast.dart';
+import 'package:chabo/models/enums/forecast_closing_type.dart';
+import 'package:chabo/models/time_slot.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ final forecast = BoatForecast(
+ totalClosing: true,
+ circulationClosingDate: DateTime(2023, 5, 14, 15, 0),
+ circulationReOpeningDate: DateTime(2023, 5, 14, 16, 0),
+ boats: [Boat(name: 'TEST_BOAT', isLeaving: false)],
+ closingType: ForecastClosingType.complete,
+ );
+
+ final forecast2 = BoatForecast(
+ totalClosing: true,
+ circulationClosingDate: DateTime(2023, 5, 14, 23, 0),
+ circulationReOpeningDate: DateTime(2023, 5, 14, 05, 0),
+ boats: [Boat(name: 'TEST_BOAT', isLeaving: false)],
+ closingType: ForecastClosingType.complete,
+ );
+
+ final forecast3 = BoatForecast(
+ totalClosing: true,
+ circulationClosingDate: DateTime(2023, 5, 14, 23, 0),
+ circulationReOpeningDate: DateTime(2023, 5, 15, 05, 0),
+ boats: [Boat(name: 'TEST_BOAT', isLeaving: false)],
+ closingType: ForecastClosingType.complete,
+ );
+
+ group('BoatForecast TESTS', () {
+ test('Is during 2 days', () {
+ expect(forecast2.isDuringTwoDays, true);
+ });
+
+ test('Is NOT during 2 days', () {
+ expect(forecast.isDuringTwoDays, false);
+ });
+
+ test('Get the correct closing duration', () {
+ expect(forecast.closedDuration, const Duration(hours: 1));
+ });
+
+ test('Is overlaping with', () {
+ final isOverlaping =
+ forecast.isOverlappingWith(DateTime(2023, 5, 14, 15, 30));
+ expect(isOverlaping, true);
+ });
+
+ test('Is NOT overlaping with', () {
+ final isOverlaping =
+ forecast.isOverlappingWith(DateTime(2023, 5, 14, 17, 30));
+ expect(isOverlaping, false);
+ });
+
+ test('(1) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 14, minute: 00),
+ to: TimeOfDay(
+ hour: 15,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(2) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 15, minute: 30),
+ to: TimeOfDay(
+ hour: 15,
+ minute: 45,
+ ),
+ );
+
+ final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(3) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 12, minute: 30),
+ to: TimeOfDay(
+ hour: 18,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(4) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 15, minute: 30),
+ to: TimeOfDay(
+ hour: 18,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(5) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 15, minute: 30),
+ to: TimeOfDay(
+ hour: 18,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(6) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 23, minute: 00),
+ to: TimeOfDay(
+ hour: 23,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast3.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(7) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 00, minute: 00),
+ to: TimeOfDay(
+ hour: 1,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast3.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(1) Is NOT overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 19, minute: 00),
+ to: TimeOfDay(
+ hour: 20,
+ minute: 00,
+ ),
+ );
+
+ final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, false);
+ });
+
+ test('(2) Is NOT overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 7, minute: 00),
+ to: TimeOfDay(
+ hour: 8,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast3.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, false);
+ });
+
+ test('Is NOT currently closed', () {
+ final isOverlaping = forecast.isCurrentlyClosed();
+ expect(isOverlaping, false);
+ });
+
+ test('Has passed', () {
+ final isOverlaping = forecast.hasPassed();
+ expect(isOverlaping, true);
+ });
+
+ test('Build from JSON - Boat arrival', () {
+ var jsonValue1 = {
+ 'datasetid': 'previsions_pont_chaban',
+ 'recordid': '82c316d304b1adef7eeef9edc9ab7b257f766086',
+ 'fields': {
+ 'fermeture_totale': 'oui',
+ 'bateau': 'MARITE',
+ 'date_passage': '2023-03-02',
+ 're_ouverture_a_la_circulation': '16:49',
+ 'fermeture_a_la_circulation': '15:49',
+ 'type_de_fermeture': 'Totale',
+ },
+ 'record_timestamp': '2023-04-25T13:32:05.809+02:00',
+ };
+ var jsonValue2 = {
+ 'datasetid': 'previsions_pont_chaban',
+ 'recordid': '82c316d304b1adef7eeef9edc9ab7b257f766086',
+ 'fields': {
+ 'fermeture_totale': 'oui',
+ 'bateau': 'MARITE',
+ 'date_passage': '2023-03-15',
+ 're_ouverture_a_la_circulation': '16:49',
+ 'fermeture_a_la_circulation': '15:49',
+ 'type_de_fermeture': 'Totale',
+ },
+ 'record_timestamp': '2023-04-25T13:32:05.809+02:00',
+ };
+ final forecast1 = BoatForecast.fromJSON(jsonValue1);
+ final forecast2 = BoatForecast.fromJSON(jsonValue2);
+
+ expect(forecast1.boats[0].isLeaving, false);
+ expect(forecast2.boats[0].isLeaving, true);
+ });
+ });
+}
diff --git a/test/units/custom_extensions_tests.dart b/test/units/custom_extensions_tests.dart
new file mode 100644
index 00000000..88bd21d3
--- /dev/null
+++ b/test/units/custom_extensions_tests.dart
@@ -0,0 +1,43 @@
+import 'package:chabo/extensions/date_time_extension.dart';
+import 'package:chabo/extensions/string_extension.dart';
+import 'package:chabo/models/enums/day.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ group('StringExtensions TEST', () {
+ test('Capitalize', () {
+ const string = 'test';
+ expect(string.capitalize(), 'Test');
+ });
+ });
+
+ group('DateTimeExtensions TEST', () {
+ test('Previous 1', () {
+ const day = Day.monday;
+ final dateTime = DateTime(2023, 5, 14, 15, 0);
+ final previousMonday = dateTime.previous(day.weekPosition);
+ expect(previousMonday, DateTime(2023, 5, 8, 0, 0));
+ });
+
+ test('Previous 2', () {
+ const day = Day.sunday;
+ final dateTime = DateTime(2023, 5, 14, 15, 0);
+ final previousMonday = dateTime.previous(day.weekPosition);
+ expect(previousMonday, DateTime(2023, 5, 7, 0, 0));
+ });
+
+ test('Previous 3', () {
+ const day = Day.saturday;
+ final dateTime = DateTime(2023, 5, 14, 15, 0);
+ final previousMonday = dateTime.previous(day.weekPosition);
+ expect(previousMonday, DateTime(2023, 5, 13, 0, 0));
+ });
+
+ test('Previous 4', () {
+ const day = Day.saturday;
+ final dateTime = DateTime(2023, 5, 11, 15, 0);
+ final previousMonday = dateTime.previous(day.weekPosition);
+ expect(previousMonday, DateTime(2023, 5, 6, 0, 0));
+ });
+ });
+}
diff --git a/test/units/maintenance_forecast_test.dart b/test/units/maintenance_forecast_test.dart
new file mode 100644
index 00000000..88f44ea5
--- /dev/null
+++ b/test/units/maintenance_forecast_test.dart
@@ -0,0 +1,190 @@
+import 'package:chabo/models/enums/forecast_closing_type.dart';
+import 'package:chabo/models/maintenance_forecast.dart';
+import 'package:chabo/models/time_slot.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+ final forecast = MaintenanceForecast(
+ totalClosing: true,
+ circulationClosingDate: DateTime(2023, 5, 14, 15, 0),
+ circulationReOpeningDate: DateTime(2023, 5, 14, 16, 0),
+ closingType: ForecastClosingType.complete,
+ );
+
+ final forecast2 = MaintenanceForecast(
+ totalClosing: true,
+ circulationClosingDate: DateTime(2023, 5, 14, 23, 0),
+ circulationReOpeningDate: DateTime(2023, 5, 14, 05, 0),
+ closingType: ForecastClosingType.complete,
+ );
+
+ final forecast3 = MaintenanceForecast(
+ totalClosing: true,
+ circulationClosingDate: DateTime(2023, 5, 14, 23, 0),
+ circulationReOpeningDate: DateTime(2023, 5, 15, 05, 0),
+ closingType: ForecastClosingType.complete,
+ );
+
+ group('MaintenanceForecast TESTS', () {
+ test('Is during 2 days', () {
+ expect(forecast2.isDuringTwoDays, true);
+ });
+
+ test('Is NOT during 2 days', () {
+ expect(forecast.isDuringTwoDays, false);
+ });
+
+ test('Get the correct closing duration', () {
+ expect(forecast.closedDuration, const Duration(hours: 1));
+ });
+
+ test('Is overlaping with', () {
+ final isOverlaping =
+ forecast.isOverlappingWith(DateTime(2023, 5, 14, 15, 30));
+ expect(isOverlaping, true);
+ });
+
+ test('Is NOT overlaping with', () {
+ final isOverlaping =
+ forecast.isOverlappingWith(DateTime(2023, 5, 14, 17, 30));
+ expect(isOverlaping, false);
+ });
+
+ test('(1) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 14, minute: 00),
+ to: TimeOfDay(
+ hour: 15,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(2) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 15, minute: 30),
+ to: TimeOfDay(
+ hour: 15,
+ minute: 45,
+ ),
+ );
+
+ final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(3) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 12, minute: 30),
+ to: TimeOfDay(
+ hour: 18,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(4) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 15, minute: 30),
+ to: TimeOfDay(
+ hour: 18,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(5) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 15, minute: 30),
+ to: TimeOfDay(
+ hour: 18,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(6) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 23, minute: 00),
+ to: TimeOfDay(
+ hour: 23,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast3.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(7) Is overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 00, minute: 00),
+ to: TimeOfDay(
+ hour: 1,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast3.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, true);
+ });
+
+ test('(1) Is NOT overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 19, minute: 00),
+ to: TimeOfDay(
+ hour: 20,
+ minute: 00,
+ ),
+ );
+
+ final isOverlaping = forecast.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, false);
+ });
+
+ test('(2) Is NOT overlaping with [TimeSlots]', () {
+ const timeSlot1 = TimeSlot(
+ name: '',
+ from: TimeOfDay(hour: 7, minute: 00),
+ to: TimeOfDay(
+ hour: 8,
+ minute: 30,
+ ),
+ );
+
+ final isOverlaping = forecast3.isOverlappingWithTimeSlot(timeSlot1);
+ expect(isOverlaping, false);
+ });
+
+ test('Is NOT currently closed', () {
+ final isOverlaping = forecast.isCurrentlyClosed();
+ expect(isOverlaping, false);
+ });
+
+ test('Has passed', () {
+ final isOverlaping = forecast.hasPassed();
+ expect(isOverlaping, true);
+ });
+ });
+}
diff --git a/test/widget_test.dart b/test/widget_test.dart
deleted file mode 100644
index c3402014..00000000
--- a/test/widget_test.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-import 'package:flutter_test/flutter_test.dart';
-
-void main() {
- testWidgets('Counter increments smoke test', (WidgetTester tester) async {
- expect(true, true);
- });
-}