Compare commits
34 commits
Author | SHA1 | Date | |
---|---|---|---|
f0ccf59db9 | |||
cc7caffffa | |||
17d8fac893 | |||
1f48e868b0 | |||
9d2871405d | |||
9637551d7a | |||
2456f7cbda | |||
0f39a30921 | |||
1e4ca0c61b | |||
1269a93624 | |||
a5615fe3cb | |||
342b870e93 | |||
0647f260db | |||
0e484bdc16 | |||
da983871e2 | |||
8ddac141d7 | |||
aea7647c89 | |||
e19d761f4d | |||
240812e261 | |||
cb380e802c | |||
2ac04cba02 | |||
6b33fcb01c | |||
50dd6c19c9 | |||
3c68cf7164 | |||
7fcbdc18bd | |||
bf654ea837 | |||
966c02b0e6 | |||
2ba3db5be3 | |||
5f56ef3068 | |||
bf0078f2e9 | |||
9436b7964a | |||
e715a9634d | |||
b6c224e8c4 | |||
3a44c5d748 |
157 changed files with 13489 additions and 2347 deletions
24
.metadata
24
.metadata
|
@ -1,10 +1,30 @@
|
||||||
# This file tracks properties of this Flutter project.
|
# This file tracks properties of this Flutter project.
|
||||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
#
|
#
|
||||||
# This file should be version controlled and should not be manually edited.
|
# This file should be version controlled.
|
||||||
|
|
||||||
version:
|
version:
|
||||||
revision: b712a172f9694745f50505c93340883493b505e5
|
revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||||
channel: stable
|
channel: stable
|
||||||
|
|
||||||
project_type: app
|
project_type: app
|
||||||
|
|
||||||
|
# Tracks metadata for the flutter migrate command
|
||||||
|
migration:
|
||||||
|
platforms:
|
||||||
|
- platform: root
|
||||||
|
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||||
|
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||||
|
- platform: windows
|
||||||
|
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||||
|
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||||
|
|
||||||
|
# User provided section
|
||||||
|
|
||||||
|
# List of Local paths (relative to this file) that should be
|
||||||
|
# ignored by the migrate tool.
|
||||||
|
#
|
||||||
|
# Files that are not part of the templates will be ignored by default.
|
||||||
|
unmanaged_files:
|
||||||
|
- 'lib/main.dart'
|
||||||
|
- 'ios/Runner.xcodeproj/project.pbxproj'
|
||||||
|
|
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
|
@ -7,7 +7,11 @@
|
||||||
{
|
{
|
||||||
"name": "Current Device",
|
"name": "Current Device",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "dart"
|
"type": "dart",
|
||||||
|
"args": [
|
||||||
|
"--dart-define",
|
||||||
|
"DOWNLOAD=apk"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "info_tren (profile mode)",
|
"name": "info_tren (profile mode)",
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
v2.6.0
|
|
||||||
Added ability to view yesterday data for trains that didn't depart yet today.
|
|
||||||
Fixed iOS status bar color.
|
|
||||||
|
|
||||||
v2.5.0
|
|
||||||
Initial arrivals/departures support
|
|
||||||
|
|
||||||
v2.4.1
|
|
||||||
Fixed DateTime (UTC -> local)
|
|
||||||
|
|
||||||
v2.4.0
|
|
||||||
Moved to api v2
|
|
||||||
Added support for any train number, including train numbers starting with 0
|
|
||||||
|
|
||||||
v2.3.1
|
|
||||||
Fixed badge background when arrival is known but not departure
|
|
||||||
|
|
||||||
v2.3.0
|
|
||||||
Added pull to refresh
|
|
||||||
|
|
||||||
v2.2.0
|
|
||||||
Added refresh button on error
|
|
||||||
|
|
||||||
v2.1.1
|
|
||||||
Fixed Android build
|
|
||||||
Switched versioning format
|
|
||||||
|
|
||||||
v2.0.7
|
|
||||||
Switched from WebView to API
|
|
||||||
Updated app to latest Flutter
|
|
||||||
Tweaks
|
|
||||||
|
|
||||||
v2.0.6
|
|
||||||
Brought feature parity with iOS _(except for v2.0.2, which is iOS specific)_.
|
|
||||||
|
|
||||||
|
|
||||||
v2.0.5
|
|
||||||
- increased font weight on iOS
|
|
||||||
- added support for system bolt font request on iOS
|
|
||||||
|
|
||||||
v2.0.4
|
|
||||||
- added original time in case of delay for iOS
|
|
||||||
+ will be for Android soon
|
|
||||||
+ in case there is a delay, the original time will be shown with
|
|
||||||
a stroke through it and the new time will be shown below
|
|
||||||
|
|
||||||
v2.0.3
|
|
||||||
- added km badge colour for iOS
|
|
||||||
+ will be added for Android soon
|
|
||||||
+ green for being on time
|
|
||||||
+ yellow for a non planned stop
|
|
||||||
+ red for a delay
|
|
||||||
|
|
||||||
v2.0.2
|
|
||||||
- added translucency to the navigation bar on iOS
|
|
||||||
|
|
||||||
v2.0.1
|
|
||||||
- added a little separation between the arrows and the text in the stations list
|
|
||||||
- fine tuned the positioning, centering items when they are supposed to be centered
|
|
||||||
- changed text from "sosește" to "sosire", in order to match "plecare"
|
|
||||||
|
|
||||||
v2.0.0
|
|
||||||
Rewritten!
|
|
||||||
- separate UI for Android and iOS
|
|
||||||
- uses WebView to get data on device instead of relying on server
|
|
122
CHANGELOG.txt
Normal file
122
CHANGELOG.txt
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
v2.7.11
|
||||||
|
Add support for IC trains.
|
||||||
|
Allow choosing displayed timezone.
|
||||||
|
Show notes about wagon detachment, receival, or train number changes.
|
||||||
|
Use system accent color if available.
|
||||||
|
Use API v3.
|
||||||
|
|
||||||
|
v2.7.10
|
||||||
|
Add about page to Fluent UI.
|
||||||
|
Add settings page, allowing changing between UIs.
|
||||||
|
Add touch scrolling on Linux.
|
||||||
|
|
||||||
|
v2.7.9
|
||||||
|
Add Fluent UI for Windows and Linux.
|
||||||
|
Add split view in landscape when viewing a train.
|
||||||
|
Add error handling and auto refresh when viewing a station's arrivals/departures.
|
||||||
|
General code fixes and migration (freezed, riverpod).
|
||||||
|
|
||||||
|
v2.7.8
|
||||||
|
Added cancelled trains in departures/arrivals board.
|
||||||
|
Selecting train in departures/arrivels board chooses appropriate departure date.
|
||||||
|
Temporarily switched all platforms to Material.
|
||||||
|
|
||||||
|
v2.7.7
|
||||||
|
Improved departures/arrivals page:
|
||||||
|
- badge for platform (due to limitations in data, platform in only known when a train arrives/departs)
|
||||||
|
- time deviations shown (delays or arriving early)
|
||||||
|
Moved to API v3 for station data.
|
||||||
|
|
||||||
|
v2.7.6
|
||||||
|
Transitioned to Material 3.
|
||||||
|
Redesigned main page on Material.
|
||||||
|
On Android (Material), tapping station card in train information screen opens departures/arrivals board.
|
||||||
|
Added past tense to trains already arrived/departed.
|
||||||
|
Fixed download button on Android.
|
||||||
|
|
||||||
|
v2.7.5
|
||||||
|
Added about page and in-app changelog.
|
||||||
|
On Android, added download buttons.
|
||||||
|
|
||||||
|
v2.7.4
|
||||||
|
Addressed Android 12 component exporting rule.
|
||||||
|
See: https://developer.android.com/about/versions/12/behavior-changes-12#exported
|
||||||
|
|
||||||
|
v2.7.3
|
||||||
|
Added Android APK signing.
|
||||||
|
|
||||||
|
v2.7.2
|
||||||
|
Fixed alignment of station names in train screen.
|
||||||
|
|
||||||
|
v2.7.1
|
||||||
|
Switched train suggestions list from hardcoded data to server data.
|
||||||
|
Added Linux build files.
|
||||||
|
|
||||||
|
v2.7.0
|
||||||
|
Changed domain name for server providing the data.
|
||||||
|
Changed bundle name accordingly.
|
||||||
|
|
||||||
|
v2.6.0
|
||||||
|
Added ability to view yesterday data for trains that didn't depart yet today.
|
||||||
|
Fixed iOS status bar color.
|
||||||
|
|
||||||
|
v2.5.0
|
||||||
|
Initial arrivals/departures support
|
||||||
|
|
||||||
|
v2.4.1
|
||||||
|
Fixed DateTime (UTC -> local)
|
||||||
|
|
||||||
|
v2.4.0
|
||||||
|
Moved to api v2
|
||||||
|
Added support for any train number, including train numbers starting with 0
|
||||||
|
|
||||||
|
v2.3.1
|
||||||
|
Fixed badge background when arrival is known but not departure
|
||||||
|
|
||||||
|
v2.3.0
|
||||||
|
Added pull to refresh
|
||||||
|
|
||||||
|
v2.2.0
|
||||||
|
Added refresh button on error
|
||||||
|
|
||||||
|
v2.1.1
|
||||||
|
Fixed Android build
|
||||||
|
Switched versioning format
|
||||||
|
|
||||||
|
v2.0.7
|
||||||
|
Switched from WebView to API
|
||||||
|
Updated app to latest Flutter
|
||||||
|
Tweaks
|
||||||
|
|
||||||
|
v2.0.6
|
||||||
|
Brought feature parity with iOS _(except for v2.0.2, which is iOS specific)_.
|
||||||
|
|
||||||
|
v2.0.5
|
||||||
|
- increased font weight on iOS
|
||||||
|
- added support for system bolt font request on iOS
|
||||||
|
|
||||||
|
v2.0.4
|
||||||
|
- added original time in case of delay for iOS
|
||||||
|
+ will be for Android soon
|
||||||
|
+ in case there is a delay, the original time will be shown with
|
||||||
|
a stroke through it and the new time will be shown below
|
||||||
|
|
||||||
|
v2.0.3
|
||||||
|
- added km badge colour for iOS
|
||||||
|
+ will be added for Android soon
|
||||||
|
+ green for being on time
|
||||||
|
+ yellow for a non planned stop
|
||||||
|
+ red for a delay
|
||||||
|
|
||||||
|
v2.0.2
|
||||||
|
- added translucency to the navigation bar on iOS
|
||||||
|
|
||||||
|
v2.0.1
|
||||||
|
- added a little separation between the arrows and the text in the stations list
|
||||||
|
- fine tuned the positioning, centering items when they are supposed to be centered
|
||||||
|
- changed text from "sosește" to "sosire", in order to match "plecare"
|
||||||
|
|
||||||
|
v2.0.0
|
||||||
|
Rewritten!
|
||||||
|
- separate UI for Android and iOS
|
||||||
|
- uses WebView to get data on device instead of relying on server
|
|
@ -25,8 +25,14 @@ apply plugin: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||||
|
|
||||||
|
def keystoreProperties = new Properties()
|
||||||
|
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||||
|
if (keystorePropertiesFile.exists()) {
|
||||||
|
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 30
|
compileSdkVersion 33
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
@ -43,18 +49,24 @@ android {
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId "xyz.dcdevelop.infotren"
|
applicationId "ro.dcdev.infotren"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 30
|
targetSdkVersion 33
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signingConfigs {
|
||||||
|
release {
|
||||||
|
keyAlias keystoreProperties['keyAlias']
|
||||||
|
keyPassword keystoreProperties['keyPassword']
|
||||||
|
storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
|
||||||
|
storePassword keystoreProperties['storePassword']
|
||||||
|
}
|
||||||
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
// TODO: Add your own signing config for the release build.
|
signingConfig signingConfigs.release
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
|
||||||
signingConfig signingConfigs.debug
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="xyz.dcdevelop.infotren">
|
package="ro.dcdev.infotren">
|
||||||
<!-- Flutter needs it to communicate with the running application
|
<!-- Flutter needs it to communicate with the running application
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
-->
|
-->
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="xyz.dcdevelop.infotren">
|
package="ro.dcdev.infotren">
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<application
|
<application
|
||||||
android:label="Info Tren"
|
android:label="Info Tren"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package xyz.dcdevelop.infotren
|
package ro.dcdev.infotren
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="xyz.dcdevelop.info_tren">
|
package="ro.dcdev.info_tren">
|
||||||
<!-- Flutter needs it to communicate with the running application
|
<!-- Flutter needs it to communicate with the running application
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
-->
|
-->
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.3.50'
|
ext.kotlin_version = '1.7.10'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,6 @@ subprojects {
|
||||||
project.evaluationDependsOn(':app')
|
project.evaluationDependsOn(':app')
|
||||||
}
|
}
|
||||||
|
|
||||||
task clean(type: Delete) {
|
tasks.register("clean", Delete) {
|
||||||
delete rootProject.buildDir
|
delete rootProject.buildDir
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-all.zip
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
{"short_name":"ATC","operator":"Astra Trans Carpatic","data_export":"20171212","valabil":{"de_la":"20171210","pana_la":"20181208"},"versiune":"1","trenuri":[{"rang":"IR","numar":"15510","numar_intern":15510},{"rang":"IR","numar":"15511","numar_intern":15511},{"rang":"IR","numar":"15512","numar_intern":15512},{"rang":"IR","numar":"15513*","numar_intern":15513},{"rang":"IR","numar":"15513","numar_intern":15513},{"rang":"IR","numar":"15514","numar_intern":15514},{"rang":"IR","numar":"15514","numar_intern":15514},{"rang":"IR","numar":"15516","numar_intern":15516},{"rang":"IR","numar":"15520","numar_intern":15520},{"rang":"IR","numar":"15521*","numar_intern":15521},{"rang":"IR","numar":"15521","numar_intern":15521},{"rang":"IR","numar":"15522","numar_intern":15522},{"rang":"IR","numar":"15522","numar_intern":15522},{"rang":"IR","numar":"15523","numar_intern":15523},{"rang":"IR","numar":"15523","numar_intern":15523},{"rang":"IR","numar":"15527","numar_intern":15527},{"rang":"IR","numar":"15528","numar_intern":15528},{"rang":"IR","numar":"15529","numar_intern":15529},{"rang":"IR","numar":"15531","numar_intern":15531},{"rang":"IR","numar":"15532","numar_intern":15532},{"rang":"IR","numar":"15533","numar_intern":15533},{"rang":"IR","numar":"15533e","numar_intern":15533},{"rang":"IR","numar":"15534","numar_intern":15534},{"rang":"IR","numar":"15535","numar_intern":15535},{"rang":"IR","numar":"15536","numar_intern":15536},{"rang":"IR","numar":"15537-2","numar_intern":15537},{"rang":"IR","numar":"15538","numar_intern":15538},{"rang":"IR","numar":"15540","numar_intern":15540},{"rang":"IR","numar":"15541","numar_intern":15541},{"rang":"IR","numar":"15541","numar_intern":15541},{"rang":"IR","numar":"15542","numar_intern":15542},{"rang":"IR","numar":"15542","numar_intern":15542},{"rang":"IR","numar":"15543","numar_intern":15543},{"rang":"IR","numar":"15544","numar_intern":15544},{"rang":"IR","numar":"15545","numar_intern":15545},{"rang":"IR","numar":"15546*","numar_intern":15546},{"rang":"IR","numar":"15546","numar_intern":15546},{"rang":"IR","numar":"15547","numar_intern":15547},{"rang":"IR","numar":"15548","numar_intern":15548},{"rang":"IR","numar":"15549*","numar_intern":15549},{"rang":"IR","numar":"15549b","numar_intern":15549},{"rang":"IR","numar":"15551","numar_intern":15551},{"rang":"IR","numar":"15552","numar_intern":15552},{"rang":"IR","numar":"15553","numar_intern":15553},{"rang":"IR","numar":"15581","numar_intern":15581},{"rang":"IR","numar":"15582","numar_intern":15582},{"rang":"IR","numar":"15582***","numar_intern":15582},{"rang":"IR","numar":"15583","numar_intern":15583},{"rang":"IR","numar":"15590","numar_intern":15590},{"rang":"IR","numar":"15591","numar_intern":15591},{"rang":"IR","numar":"15592","numar_intern":15592},{"rang":"IR","numar":"15593","numar_intern":15593},{"rang":"R","numar":"*P18801","numar_intern":null},{"rang":"IR","numar":"*15546","numar_intern":null},{"rang":"R","numar":"**P18801","numar_intern":null},{"rang":"IR","numar":"*15591","numar_intern":null},{"rang":"R","numar":"**P18800","numar_intern":null},{"rang":"IR","numar":"15593","numar_intern":15593},{"rang":"IR","numar":"15594","numar_intern":15594},{"rang":"IR","numar":"15595-2","numar_intern":15595},{"rang":"R","numar":"18800","numar_intern":18800},{"rang":"R","numar":"18801","numar_intern":18801},{"rang":"IR","numar":"18826","numar_intern":18826},{"rang":"IR","numar":"18851","numar_intern":18851},{"rang":"IR","numar":"18852","numar_intern":18852}]}
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +0,0 @@
|
||||||
atc.json
|
|
||||||
cfr.json
|
|
||||||
interregional.json
|
|
||||||
rc.json
|
|
||||||
st.json
|
|
||||||
tfc.json
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
||||||
{"short_name":"Softrans","operator":"Softrans S.R.L.","data_export":"20181212","valabil":{"de_la":"20181209","pana_la":"20191214"},"versiune":"1","trenuri":[{"rang":"IR","numar":"15931-2","numar_intern":15931},{"rang":"IR","numar":"15932","numar_intern":15932},{"rang":"IR","numar":"15933-2","numar_intern":15933},{"rang":"IR","numar":"15934","numar_intern":15934},{"rang":"IR","numar":"15935-2","numar_intern":15935},{"rang":"IR","numar":"15936","numar_intern":15936},{"rang":"IR","numar":"15982","numar_intern":15982},{"rang":"IR","numar":"15984","numar_intern":15984}]}
|
|
File diff suppressed because one or more lines are too long
216
codemagic.yaml
Normal file
216
codemagic.yaml
Normal file
File diff suppressed because one or more lines are too long
|
@ -21,6 +21,6 @@
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>MinimumOSVersion</key>
|
<key>MinimumOSVersion</key>
|
||||||
<string>9.0</string>
|
<string>11.0</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# Uncomment this line to define a global platform for your project
|
# Uncomment this line to define a global platform for your project
|
||||||
# platform :ios, '9.0'
|
# platform :ios, '11.0'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|
34
ios/Podfile.lock
Normal file
34
ios/Podfile.lock
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
PODS:
|
||||||
|
- Flutter (1.0.0)
|
||||||
|
- package_info_plus (0.4.5):
|
||||||
|
- Flutter
|
||||||
|
- shared_preferences_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- url_launcher_ios (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
|
||||||
|
DEPENDENCIES:
|
||||||
|
- Flutter (from `Flutter`)
|
||||||
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
|
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
|
||||||
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
|
|
||||||
|
EXTERNAL SOURCES:
|
||||||
|
Flutter:
|
||||||
|
:path: Flutter
|
||||||
|
package_info_plus:
|
||||||
|
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||||
|
shared_preferences_ios:
|
||||||
|
:path: ".symlinks/plugins/shared_preferences_ios/ios"
|
||||||
|
url_launcher_ios:
|
||||||
|
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||||
|
|
||||||
|
SPEC CHECKSUMS:
|
||||||
|
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||||
|
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
|
||||||
|
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
|
||||||
|
url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
|
||||||
|
|
||||||
|
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
|
||||||
|
|
||||||
|
COCOAPODS: 1.11.3
|
|
@ -13,6 +13,7 @@
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
|
AF5528149967EA996B5AA109 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6E6EB5FA5AA2228D5622CD62 /* Pods_Runner.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
@ -31,7 +32,11 @@
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
|
2088AE25E07C211FFB9CE536 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
2F80AD107B0E1CC9E1C01A5A /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
|
5DA42B3CD8940DB121C028E8 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
6E6EB5FA5AA2228D5622CD62 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||||
|
@ -49,6 +54,7 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
AF5528149967EA996B5AA109 /* Pods_Runner.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -72,6 +78,8 @@
|
||||||
9740EEB11CF90186004384FC /* Flutter */,
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
|
B55F9B76DFEAB456725329A0 /* Pods */,
|
||||||
|
E56598AA51C5533E6B51BD5A /* Frameworks */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
@ -98,6 +106,25 @@
|
||||||
path = Runner;
|
path = Runner;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
B55F9B76DFEAB456725329A0 /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
2F80AD107B0E1CC9E1C01A5A /* Pods-Runner.debug.xcconfig */,
|
||||||
|
2088AE25E07C211FFB9CE536 /* Pods-Runner.release.xcconfig */,
|
||||||
|
5DA42B3CD8940DB121C028E8 /* Pods-Runner.profile.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Pods;
|
||||||
|
path = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
E56598AA51C5533E6B51BD5A /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
6E6EB5FA5AA2228D5622CD62 /* Pods_Runner.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
|
@ -105,12 +132,14 @@
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
2B2F3198BD0D2214C77EC99E /* [CP] Check Pods Manifest.lock */,
|
||||||
9740EEB61CF901F6004384FC /* Run Script */,
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
97C146EA1CF9000F007C117D /* Sources */,
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
|
D71FC49A789443CEBF7C5C70 /* [CP] Embed Pods Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
|
@ -127,7 +156,7 @@
|
||||||
97C146E61CF9000F007C117D /* Project object */ = {
|
97C146E61CF9000F007C117D /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 1020;
|
LastUpgradeCheck = 1300;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
97C146ED1CF9000F007C117D = {
|
97C146ED1CF9000F007C117D = {
|
||||||
|
@ -169,6 +198,28 @@
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
2B2F3198BD0D2214C77EC99E /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -197,6 +248,23 @@
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
};
|
};
|
||||||
|
D71FC49A789443CEBF7C5C70 /* [CP] Embed Pods Frameworks */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Embed Pods Frameworks";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
@ -272,7 +340,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
@ -296,7 +364,7 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 2.0.7;
|
MARKETING_VERSION = 2.0.7;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = xyz.dcdevelop.infotren;
|
PRODUCT_BUNDLE_IDENTIFIER = ro.dcdev.infotren;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
@ -351,7 +419,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
@ -400,7 +468,7 @@
|
||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
@ -426,7 +494,7 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 2.0.7;
|
MARKETING_VERSION = 2.0.7;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = xyz.dcdevelop.infotren;
|
PRODUCT_BUNDLE_IDENTIFIER = ro.dcdev.infotren;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
@ -450,7 +518,7 @@
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 2.0.7;
|
MARKETING_VERSION = 2.0.7;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = xyz.dcdevelop.infotren;
|
PRODUCT_BUNDLE_IDENTIFIER = ro.dcdev.infotren;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1020"
|
LastUpgradeVersion = "1300"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
|
@ -4,4 +4,7 @@
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "group:Runner.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|
|
@ -43,5 +43,7 @@
|
||||||
</array>
|
</array>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
const authority = 'scraper.infotren.dcdevelop.xyz';
|
const authority = 'scraper.infotren.dcdev.ro';
|
18
lib/api/releases.dart
Normal file
18
lib/api/releases.dart
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/utils/iterable_extensions.dart';
|
||||||
|
|
||||||
|
Future<List<ChangelogEntry>> getRemoteReleases() async {
|
||||||
|
final Uri uri = Uri.parse('https://gitea.dcdev.ro/api/v1/repos/kbruen/info_tren/releases');
|
||||||
|
final response = await http.get(uri);
|
||||||
|
final json = jsonDecode(response.body) as List<dynamic>;
|
||||||
|
return json.map((e) => ChangelogEntry(
|
||||||
|
version: ChangelogVersion.parse(e['tag_name']),
|
||||||
|
description: e['body'],
|
||||||
|
apkLink: (e['assets'] as List<dynamic>).where((e) => (e['name'] as String).contains('.apk')).map((e) => Uri.parse(e['browser_download_url'] as String)).firstOrNull,
|
||||||
|
linuxLink: (e['assets'] as List<dynamic>).where((e) => (e['name'] as String).contains('infotren-linux')).map((e) => Uri.parse(e['browser_download_url'] as String)).firstOrNull,
|
||||||
|
windowsLink: (e['assets'] as List<dynamic>).where((e) => (e['name'] as String).contains('-win.zip')).map((e) => Uri.parse(e['browser_download_url'] as String)).firstOrNull,
|
||||||
|
)).toList();
|
||||||
|
}
|
|
@ -2,9 +2,13 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:info_tren/api/common.dart';
|
import 'package:info_tren/api/common.dart';
|
||||||
import 'package:info_tren/models/station_data.dart';
|
import 'package:info_tren/models.dart';
|
||||||
|
|
||||||
Future<StationData> getStationData(String stationName) async {
|
Future<StationData> getStationData(String stationName, [DateTime? date]) async {
|
||||||
final response = await http.get(Uri.https(authority, 'v2/station/$stationName'));
|
final uri = Uri.https(authority, 'v3/stations/$stationName');
|
||||||
|
if (date != null) {
|
||||||
|
uri.queryParameters['date'] = date.toIso8601String();
|
||||||
|
}
|
||||||
|
final response = await http.get(uri);
|
||||||
return StationData.fromJson(jsonDecode(response.body));
|
return StationData.fromJson(jsonDecode(response.body));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:info_tren/api/common.dart';
|
import 'package:info_tren/api/common.dart';
|
||||||
import 'package:info_tren/models/stations_result.dart';
|
import 'package:info_tren/models.dart';
|
||||||
|
|
||||||
Future<List<StationsResult>> get stations async {
|
Future<List<StationsResult>> get stations async {
|
||||||
final result = await http.get(Uri.https(authority, 'v2/stations'));
|
final result = await http.get(Uri.https(authority, 'v2/stations'));
|
||||||
final data = jsonDecode(result.body) as List<dynamic>;
|
final data = jsonDecode(result.body) as List<dynamic>;
|
||||||
return data.map((e) => StationsResult.fromJson(e)).toList(growable: false,);
|
return data.map((e) => StationsResult.fromJson(e)).toList(growable: false,);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:info_tren/api/common.dart';
|
import 'package:info_tren/api/common.dart';
|
||||||
import 'package:info_tren/models/train_data.dart';
|
import 'package:info_tren/models.dart';
|
||||||
|
|
||||||
Future<TrainData> getTrain(String trainNumber, {DateTime? date}) async {
|
Future<TrainData> getTrain(String trainNumber, {DateTime? date}) async {
|
||||||
date ??= DateTime.now();
|
date ??= DateTime.now();
|
||||||
final response = await http.get(Uri.https(authority, 'v2/train/$trainNumber', {
|
final response = await http.get(Uri.https(authority, 'v3/trains/$trainNumber', {
|
||||||
'date': date.toIso8601String(),
|
'date': date.toUtc().toIso8601String(),
|
||||||
}),);
|
}),);
|
||||||
return trainDataFromJson(response.body);
|
return trainDataFromJson(response.body);
|
||||||
}
|
}
|
11
lib/api/trains.dart
Normal file
11
lib/api/trains.dart
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:info_tren/api/common.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
|
||||||
|
Future<List<TrainsResult>> get trains async {
|
||||||
|
final result = await http.get(Uri.https(authority, 'v2/trains'));
|
||||||
|
final data = jsonDecode(result.body) as List<dynamic>;
|
||||||
|
return data.map((e) => TrainsResult.fromJson(e)).toList(growable: false,);
|
||||||
|
}
|
59
lib/components/badge/badge.dart
Normal file
59
lib/components/badge/badge.dart
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/components/badge/badge_cupertino.dart';
|
||||||
|
import 'package:info_tren/components/badge/badge_fluent.dart';
|
||||||
|
import 'package:info_tren/components/badge/badge_material.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
|
class Badge extends ConsumerWidget {
|
||||||
|
final String text;
|
||||||
|
final String caption;
|
||||||
|
final bool isNotScheduled;
|
||||||
|
final bool isOnTime;
|
||||||
|
final bool isDelayed;
|
||||||
|
|
||||||
|
const Badge({
|
||||||
|
super.key,
|
||||||
|
required this.text,
|
||||||
|
required this.caption,
|
||||||
|
this.isNotScheduled = false,
|
||||||
|
this.isOnTime = false,
|
||||||
|
this.isDelayed = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
|
|
||||||
|
switch (uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
return MaterialBadge(
|
||||||
|
text: text,
|
||||||
|
caption: caption,
|
||||||
|
isNotScheduled: isNotScheduled,
|
||||||
|
isOnTime: isOnTime,
|
||||||
|
isDelayed: isDelayed,
|
||||||
|
);
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
return CupertinoBadge(
|
||||||
|
text: text,
|
||||||
|
caption: caption,
|
||||||
|
isNotScheduled: isNotScheduled,
|
||||||
|
isOnTime: isOnTime,
|
||||||
|
isDelayed: isDelayed,
|
||||||
|
);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return FluentBadge(
|
||||||
|
text: text,
|
||||||
|
caption: caption,
|
||||||
|
isNotScheduled: isNotScheduled,
|
||||||
|
isOnTime: isOnTime,
|
||||||
|
isDelayed: isDelayed,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
80
lib/components/badge/badge_cupertino.dart
Normal file
80
lib/components/badge/badge_cupertino.dart
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/train_info_constants.dart';
|
||||||
|
|
||||||
|
class CupertinoBadge extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
final String caption;
|
||||||
|
final bool isNotScheduled;
|
||||||
|
final bool isOnTime;
|
||||||
|
final bool isDelayed;
|
||||||
|
|
||||||
|
const CupertinoBadge({
|
||||||
|
required this.text,
|
||||||
|
required this.caption,
|
||||||
|
this.isNotScheduled = false,
|
||||||
|
this.isOnTime = false,
|
||||||
|
this.isDelayed = false,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Color foregroundColor = foregroundWhite;
|
||||||
|
Color? backgroundColor;
|
||||||
|
|
||||||
|
if (isNotScheduled) {
|
||||||
|
foregroundColor = const Color.fromRGBO(225, 175, 30, 1);
|
||||||
|
backgroundColor = const Color.fromRGBO(80, 40, 10, 1);
|
||||||
|
}
|
||||||
|
else if (isOnTime) {
|
||||||
|
foregroundColor = const Color.fromRGBO(130, 175, 65, 1);
|
||||||
|
backgroundColor = const Color.fromRGBO(40, 80, 10, 1);
|
||||||
|
}
|
||||||
|
else if (isDelayed) {
|
||||||
|
foregroundColor = const Color.fromRGBO(225, 75, 30, 1);
|
||||||
|
backgroundColor = const Color.fromRGBO(80, 20, 10, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(
|
||||||
|
width: 2,
|
||||||
|
color: foregroundColor,
|
||||||
|
),
|
||||||
|
color: backgroundColor,
|
||||||
|
// color: CupertinoColors.activeOrange,
|
||||||
|
),
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w400 : FontWeight.w200,
|
||||||
|
color: MediaQuery.of(context).boldText ? foregroundWhite : foregroundColor,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
caption,
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 12,
|
||||||
|
color: MediaQuery.of(context).boldText ? foregroundWhite : foregroundColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
80
lib/components/badge/badge_fluent.dart
Normal file
80
lib/components/badge/badge_fluent.dart
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class FluentBadge extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
final String caption;
|
||||||
|
final bool isNotScheduled;
|
||||||
|
final bool isOnTime;
|
||||||
|
final bool isDelayed;
|
||||||
|
|
||||||
|
const FluentBadge({
|
||||||
|
required this.text,
|
||||||
|
required this.caption,
|
||||||
|
this.isNotScheduled = false,
|
||||||
|
this.isOnTime = false,
|
||||||
|
this.isDelayed = false,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Color foregroundColor = FluentTheme.of(context).activeColor;
|
||||||
|
Color? backgroundColor;
|
||||||
|
|
||||||
|
if (isNotScheduled) {
|
||||||
|
foregroundColor = const Color.fromRGBO(225, 175, 30, 1);
|
||||||
|
backgroundColor = const Color.fromRGBO(80, 40, 10, 1);
|
||||||
|
}
|
||||||
|
else if (isOnTime) {
|
||||||
|
foregroundColor = const Color.fromRGBO(130, 175, 65, 1);
|
||||||
|
backgroundColor = const Color.fromRGBO(40, 80, 10, 1);
|
||||||
|
}
|
||||||
|
else if (isDelayed) {
|
||||||
|
foregroundColor = const Color.fromRGBO(225, 75, 30, 1);
|
||||||
|
backgroundColor = const Color.fromRGBO(80, 20, 10, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(
|
||||||
|
width: 2,
|
||||||
|
color: foregroundColor,
|
||||||
|
),
|
||||||
|
color: backgroundColor,
|
||||||
|
// color: CupertinoColors.activeOrange,
|
||||||
|
),
|
||||||
|
width: 48,
|
||||||
|
height: 48,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: FluentTheme.of(context).typography.bodyLarge?.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w400 : FontWeight.w200,
|
||||||
|
color: MediaQuery.of(context).boldText ? Colors.white : foregroundColor,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
caption,
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(
|
||||||
|
fontSize: 12,
|
||||||
|
color: MediaQuery.of(context).boldText ? Colors.white : foregroundColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
79
lib/components/badge/badge_material.dart
Normal file
79
lib/components/badge/badge_material.dart
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/view_train/train_info_material.dart';
|
||||||
|
|
||||||
|
class MaterialBadge extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
final String caption;
|
||||||
|
final bool isNotScheduled;
|
||||||
|
final bool isOnTime;
|
||||||
|
final bool isDelayed;
|
||||||
|
|
||||||
|
const MaterialBadge({
|
||||||
|
required this.text,
|
||||||
|
required this.caption,
|
||||||
|
this.isNotScheduled = false,
|
||||||
|
this.isOnTime = false,
|
||||||
|
this.isDelayed = false,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Color foregroundColor = Colors.white70;
|
||||||
|
Color? backgroundColor;
|
||||||
|
|
||||||
|
if (isNotScheduled) {
|
||||||
|
foregroundColor = Colors.orange.shade300;
|
||||||
|
backgroundColor = Colors.orange.shade900.withOpacity(0.3);
|
||||||
|
}
|
||||||
|
else if (isOnTime) {
|
||||||
|
foregroundColor = Colors.green.shade300;
|
||||||
|
backgroundColor = Colors.green.shade900.withOpacity(0.3);
|
||||||
|
}
|
||||||
|
else if (isDelayed) {
|
||||||
|
foregroundColor = Colors.red.shade300;
|
||||||
|
backgroundColor = Colors.red.shade900.withOpacity(0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(
|
||||||
|
width: 2,
|
||||||
|
color: foregroundColor,
|
||||||
|
),
|
||||||
|
color: backgroundColor,
|
||||||
|
),
|
||||||
|
width: isSmallScreen(context) ? 42 : 48,
|
||||||
|
height: isSmallScreen(context) ? 42 : 48,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 16 : 20,
|
||||||
|
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w400 : FontWeight.w200,
|
||||||
|
color: MediaQuery.of(context).boldText ? Colors.white70 : foregroundColor,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
caption,
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
|
fontSize: 10,
|
||||||
|
color: MediaQuery.of(context).boldText ? Colors.white70 : foregroundColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,8 +4,8 @@ import 'package:info_tren/pages/train_info_page/train_info_constants.dart';
|
||||||
class CupertinoDivider extends StatelessWidget {
|
class CupertinoDivider extends StatelessWidget {
|
||||||
final Color color;
|
final Color color;
|
||||||
|
|
||||||
CupertinoDivider({Key? key, Color? color}):
|
const CupertinoDivider({Key? key, Color? color}):
|
||||||
color = color ?? FOREGROUND_DARK_GREY,
|
color = color ?? foregroundDarkGrey,
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -33,8 +33,8 @@ class CupertinoDivider extends StatelessWidget {
|
||||||
class CupertinoVerticalDivider extends StatelessWidget {
|
class CupertinoVerticalDivider extends StatelessWidget {
|
||||||
final Color color;
|
final Color color;
|
||||||
|
|
||||||
CupertinoVerticalDivider({Key? key, Color? color}):
|
const CupertinoVerticalDivider({Key? key, Color? color}):
|
||||||
color = color ?? FOREGROUND_DARK_GREY,
|
color = color ?? foregroundDarkGrey,
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -5,39 +5,54 @@ class CupertinoListTile extends StatelessWidget {
|
||||||
final Widget? title;
|
final Widget? title;
|
||||||
final Widget? subtitle;
|
final Widget? subtitle;
|
||||||
final Widget? trailing;
|
final Widget? trailing;
|
||||||
|
final void Function()? onTap;
|
||||||
|
|
||||||
const CupertinoListTile({ Key? key, this.leading, this.title, this.subtitle, this.trailing, }) : super(key: key);
|
const CupertinoListTile({ super.key, this.leading, this.title, this.subtitle, this.trailing, this.onTap, });
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return GestureDetector(
|
||||||
mainAxisSize: MainAxisSize.max,
|
onTap: onTap,
|
||||||
children: [
|
behavior: HitTestBehavior.opaque,
|
||||||
if (leading != null)
|
child: Row(
|
||||||
leading!,
|
mainAxisSize: MainAxisSize.max,
|
||||||
Expanded(
|
children: [
|
||||||
child: Column(
|
if (leading != null)
|
||||||
mainAxisSize: MainAxisSize.min,
|
Padding(
|
||||||
children: [
|
padding: const EdgeInsets.all(8.0),
|
||||||
if (title != null)
|
child: leading!,
|
||||||
title!,
|
),
|
||||||
if (subtitle != null)
|
Expanded(
|
||||||
CupertinoTheme(
|
child: Padding(
|
||||||
child: subtitle!,
|
padding: const EdgeInsets.all(8.0),
|
||||||
data: CupertinoTheme.of(context).copyWith(
|
child: Column(
|
||||||
textTheme: CupertinoTextThemeData(
|
mainAxisSize: MainAxisSize.min,
|
||||||
textStyle: TextStyle(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
fontSize: CupertinoTheme.of(context).textTheme.textStyle.fontSize! - 2,
|
children: [
|
||||||
)
|
if (title != null)
|
||||||
)
|
title!,
|
||||||
),
|
if (subtitle != null)
|
||||||
),
|
CupertinoTheme(
|
||||||
],
|
data: CupertinoTheme.of(context).copyWith(
|
||||||
|
textTheme: CupertinoTextThemeData(
|
||||||
|
textStyle: TextStyle(
|
||||||
|
fontSize: CupertinoTheme.of(context).textTheme.textStyle.fontSize! - 2,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
child: subtitle!,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
if (trailing != null)
|
||||||
if (trailing != null)
|
Padding(
|
||||||
trailing!,
|
padding: const EdgeInsets.all(8.0),
|
||||||
],
|
child: trailing!,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:info_tren/models/ui_design.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/utils/default_ui_design.dart';
|
import 'package:info_tren/utils/default_ui_design.dart';
|
||||||
|
|
||||||
class FutureDisplay<T> extends StatelessWidget {
|
class FutureDisplay<T> extends StatelessWidget {
|
||||||
|
@ -9,7 +9,7 @@ class FutureDisplay<T> extends StatelessWidget {
|
||||||
final Widget Function<T>(BuildContext context, T data) builder;
|
final Widget Function<T>(BuildContext context, T data) builder;
|
||||||
final Widget Function(BuildContext context, Object error, StackTrace? st)? errorBuilder;
|
final Widget Function(BuildContext context, Object error, StackTrace? st)? errorBuilder;
|
||||||
|
|
||||||
FutureDisplay({Key? key, required this.future, required this.builder, this.errorBuilder, this.uiDesign}): super(key: key);
|
const FutureDisplay({Key? key, required this.future, required this.builder, this.errorBuilder, this.uiDesign}): super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -24,10 +24,10 @@ class FutureDisplay<T> extends StatelessWidget {
|
||||||
Widget loadingWidget;
|
Widget loadingWidget;
|
||||||
switch (uiDesign) {
|
switch (uiDesign) {
|
||||||
case UiDesign.MATERIAL:
|
case UiDesign.MATERIAL:
|
||||||
loadingWidget = CircularProgressIndicator();
|
loadingWidget = const CircularProgressIndicator();
|
||||||
break;
|
break;
|
||||||
case UiDesign.CUPERTINO:
|
case UiDesign.CUPERTINO:
|
||||||
loadingWidget = CupertinoActivityIndicator();
|
loadingWidget = const CupertinoActivityIndicator();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
|
|
@ -1,24 +1,27 @@
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/components/loading/loading_cupertino.dart';
|
import 'package:info_tren/components/loading/loading_cupertino.dart';
|
||||||
|
import 'package:info_tren/components/loading/loading_fluent.dart';
|
||||||
import 'package:info_tren/components/loading/loading_material.dart';
|
import 'package:info_tren/components/loading/loading_material.dart';
|
||||||
import 'package:info_tren/models/ui_design.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/utils/default_ui_design.dart';
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
class Loading extends StatelessWidget {
|
class Loading extends ConsumerWidget {
|
||||||
static const DEFAULT_TEXT = 'Loading...';
|
static const defaultText = 'Loading...';
|
||||||
|
|
||||||
final UiDesign? uiDesign;
|
|
||||||
final String? text;
|
final String? text;
|
||||||
const Loading({ Key? key, this.text, this.uiDesign }) : super(key: key);
|
const Loading({ super.key, this.text, });
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
switch (uiDesign) {
|
switch (uiDesign) {
|
||||||
case UiDesign.MATERIAL:
|
case UiDesign.MATERIAL:
|
||||||
return LoadingMaterial(text: text ?? DEFAULT_TEXT,);
|
return LoadingMaterial(text: text ?? defaultText,);
|
||||||
case UiDesign.CUPERTINO:
|
case UiDesign.CUPERTINO:
|
||||||
return LoadingCupertino(text: text ?? DEFAULT_TEXT,);
|
return LoadingCupertino(text: text ?? defaultText,);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return LoadingFluent(text: text ?? defaultText,);
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
|
@ -27,5 +30,5 @@ class Loading extends StatelessWidget {
|
||||||
|
|
||||||
abstract class LoadingCommon extends StatelessWidget {
|
abstract class LoadingCommon extends StatelessWidget {
|
||||||
final String text;
|
final String text;
|
||||||
LoadingCommon({required this.text});
|
const LoadingCommon({required this.text, super.key,});
|
||||||
}
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:info_tren/components/loading/loading.dart';
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
|
|
||||||
class LoadingCupertino extends LoadingCommon {
|
class LoadingCupertino extends LoadingCommon {
|
||||||
LoadingCupertino({required String text}) : super(text: text,);
|
const LoadingCupertino({required super.text, super.key,});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -12,8 +11,8 @@ class LoadingCupertino extends LoadingCommon {
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
const Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: EdgeInsets.all(8.0),
|
||||||
child: CupertinoActivityIndicator(),
|
child: CupertinoActivityIndicator(),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
|
|
26
lib/components/loading/loading_fluent.dart
Normal file
26
lib/components/loading/loading_fluent.dart
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
|
|
||||||
|
class LoadingFluent extends LoadingCommon {
|
||||||
|
const LoadingFluent({required super.text, super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.all(8.0),
|
||||||
|
child: ProgressRing(),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(text),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:info_tren/components/loading/loading.dart';
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
|
|
||||||
class LoadingMaterial extends LoadingCommon {
|
class LoadingMaterial extends LoadingCommon {
|
||||||
LoadingMaterial({required String text}) : super(text: text,);
|
const LoadingMaterial({required super.text, super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -11,8 +11,8 @@ class LoadingMaterial extends LoadingCommon {
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
const Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: EdgeInsets.all(8.0),
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
class RefreshFutureBuilder<T> extends StatefulWidget {
|
class RefreshFutureBuilder<T> extends StatefulWidget {
|
||||||
final Future<T> Function()? futureCreator;
|
final Future<T> Function()? futureCreator;
|
||||||
|
@ -19,7 +20,7 @@ class _RefreshFutureBuilderState<T> extends State<RefreshFutureBuilder<T>> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
snapshot = widget.initialData != null ? RefreshFutureBuilderSnapshot.initial(widget.initialData!) : RefreshFutureBuilderSnapshot.nothing();
|
snapshot = widget.initialData != null ? RefreshFutureBuilderSnapshot.initial(widget.initialData as T) : const RefreshFutureBuilderSnapshot.nothing();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -39,7 +40,7 @@ class _RefreshFutureBuilderState<T> extends State<RefreshFutureBuilder<T>> {
|
||||||
setState(() {
|
setState(() {
|
||||||
switch (snapshot.state) {
|
switch (snapshot.state) {
|
||||||
case RefreshFutureBuilderState.none:
|
case RefreshFutureBuilderState.none:
|
||||||
snapshot = RefreshFutureBuilderSnapshot.waiting();
|
snapshot = const RefreshFutureBuilderSnapshot.waiting();
|
||||||
break;
|
break;
|
||||||
case RefreshFutureBuilderState.initial:
|
case RefreshFutureBuilderState.initial:
|
||||||
snapshot = RefreshFutureBuilderSnapshot.refresh(snapshot.data);
|
snapshot = RefreshFutureBuilderSnapshot.refresh(snapshot.data);
|
||||||
|
@ -47,7 +48,7 @@ class _RefreshFutureBuilderState<T> extends State<RefreshFutureBuilder<T>> {
|
||||||
case RefreshFutureBuilderState.waiting:
|
case RefreshFutureBuilderState.waiting:
|
||||||
return;
|
return;
|
||||||
case RefreshFutureBuilderState.error:
|
case RefreshFutureBuilderState.error:
|
||||||
snapshot = RefreshFutureBuilderSnapshot.waiting();
|
snapshot = const RefreshFutureBuilderSnapshot.waiting();
|
||||||
break;
|
break;
|
||||||
case RefreshFutureBuilderState.done:
|
case RefreshFutureBuilderState.done:
|
||||||
snapshot = RefreshFutureBuilderSnapshot.refresh(snapshot.data);
|
snapshot = RefreshFutureBuilderSnapshot.refresh(snapshot.data);
|
||||||
|
@ -134,3 +135,41 @@ enum RefreshFutureBuilderState {
|
||||||
refreshing,
|
refreshing,
|
||||||
refreshError,
|
refreshError,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RefreshFutureBuilderProviderAdapter<T> extends ConsumerWidget {
|
||||||
|
final Provider<AsyncValue<T>> futureProvider;
|
||||||
|
final Future Function()? refresh;
|
||||||
|
final Widget Function(BuildContext context, Future Function() refresh, Future Function(Future<T> Function()) replaceFuture, RefreshFutureBuilderSnapshot<T> snapshot) builder;
|
||||||
|
|
||||||
|
const RefreshFutureBuilderProviderAdapter({required this.futureProvider, required this.builder, this.refresh, super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final value = ref.watch(futureProvider);
|
||||||
|
|
||||||
|
return builder(
|
||||||
|
context,
|
||||||
|
refresh ?? () async {
|
||||||
|
ref.invalidate(futureProvider);
|
||||||
|
},
|
||||||
|
(_) => throw UnimplementedError('Cannot replace the future when adapting a FutureProvider'),
|
||||||
|
value.when(
|
||||||
|
data: (data) => value.isLoading || value.isRefreshing
|
||||||
|
? RefreshFutureBuilderSnapshot.refresh(data)
|
||||||
|
: RefreshFutureBuilderSnapshot.withData(data),
|
||||||
|
error: (error, st) => value.isLoading || value.isRefreshing
|
||||||
|
? RefreshFutureBuilderSnapshot.refreshError(value.hasValue ? value.value : null, value.error, value.stackTrace)
|
||||||
|
: RefreshFutureBuilderSnapshot.withError(error, st),
|
||||||
|
loading: () {
|
||||||
|
if (value.hasValue) {
|
||||||
|
return RefreshFutureBuilderSnapshot.refresh(value.value, value.error, value.stackTrace);
|
||||||
|
}
|
||||||
|
else if (value.hasError) {
|
||||||
|
return RefreshFutureBuilderSnapshot.refreshError(value.value, value.error, value.stackTrace);
|
||||||
|
}
|
||||||
|
return const RefreshFutureBuilderSnapshot.waiting();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,113 +1,75 @@
|
||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_cupertino.dart';
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_cupertino.dart';
|
||||||
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_fluent.dart';
|
||||||
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_material.dart';
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions_material.dart';
|
||||||
import 'package:info_tren/models/train_operator_lines.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/models/ui_design.dart';
|
import 'package:info_tren/providers.dart';
|
||||||
import 'package:info_tren/utils/default_ui_design.dart';
|
|
||||||
import 'package:tuple/tuple.dart';
|
|
||||||
|
|
||||||
class SelectTrainSuggestions extends StatefulWidget {
|
class SelectTrainSuggestions extends ConsumerWidget {
|
||||||
final UiDesign? uiDesign;
|
final List<TrainsResult> choices;
|
||||||
final String userInput;
|
final String? currentInput;
|
||||||
final void Function(String trainNumber) onTrainSelected;
|
final void Function(String trainNumber) onTrainSelected;
|
||||||
|
|
||||||
const SelectTrainSuggestions({ Key? key, required this.uiDesign, required this.userInput, required this.onTrainSelected }) : super(key: key);
|
const SelectTrainSuggestions({required this.choices, this.currentInput, required this.onTrainSelected, super.key, });
|
||||||
|
|
||||||
@override
|
@override
|
||||||
SelectTrainSuggestionsState createState() {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
|
|
||||||
switch(uiDesign) {
|
switch(uiDesign) {
|
||||||
case UiDesign.MATERIAL:
|
case UiDesign.MATERIAL:
|
||||||
return SelectTrainSuggestionsStateMaterial();
|
return SelectTrainSuggestionsMaterial(
|
||||||
|
choices: choices,
|
||||||
|
onTrainSelected: onTrainSelected,
|
||||||
|
currentInput: currentInput,
|
||||||
|
);
|
||||||
case UiDesign.CUPERTINO:
|
case UiDesign.CUPERTINO:
|
||||||
return SelectTrainSuggestionsStateCupertino();
|
return SelectTrainSuggestionsCupertino(
|
||||||
|
choices: choices,
|
||||||
|
onTrainSelected: onTrainSelected,
|
||||||
|
currentInput: currentInput,
|
||||||
|
);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return SelectTrainSuggestionsFluent(
|
||||||
|
choices: choices,
|
||||||
|
onTrainSelected: onTrainSelected,
|
||||||
|
currentInput: currentInput,
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class SelectTrainSuggestionsState extends State<SelectTrainSuggestions> {
|
abstract class SelectTrainSuggestionsShared extends StatelessWidget {
|
||||||
late String userInput;
|
|
||||||
|
|
||||||
List<TrainOperatorLines> operators = [];
|
|
||||||
|
|
||||||
Future loadOperators(BuildContext context) async {
|
|
||||||
operators = [];
|
|
||||||
|
|
||||||
final operatorsString = await DefaultAssetBundle.of(context).loadString("assets/lines/files.txt");
|
|
||||||
final operatorsFilesList = operatorsString.split("\n");
|
|
||||||
|
|
||||||
final decoder = JsonDecoder();
|
|
||||||
|
|
||||||
for (final operatorFile in operatorsFilesList) {
|
|
||||||
final operatorString = await DefaultAssetBundle.of(context).loadString("assets/lines/$operatorFile");
|
|
||||||
final operatorData = decoder.convert(operatorString);
|
|
||||||
final _operator = TrainOperatorLines.fromJson(operatorData);
|
|
||||||
operators.add(_operator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
userInput = widget.userInput;
|
|
||||||
|
|
||||||
loadOperators(context).then((_) {
|
|
||||||
setState(() {});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeDependencies() {
|
|
||||||
super.didChangeDependencies();
|
|
||||||
if (userInput != widget.userInput) {
|
|
||||||
setState(() {
|
|
||||||
userInput = widget.userInput;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String getUseCurrentInputWidgetText(String currentInput) => 'Caută trenul cu numărul $currentInput';
|
String getUseCurrentInputWidgetText(String currentInput) => 'Caută trenul cu numărul $currentInput';
|
||||||
Widget getUseCurrentInputWidget(String currentInput, void Function(String) onTrainSelected);
|
Widget getUseCurrentInputWidget(String currentInput, void Function(String) onTrainSelected);
|
||||||
|
|
||||||
|
final List<TrainsResult> choices;
|
||||||
|
final String? currentInput;
|
||||||
|
final void Function(String trainNumber) onTrainSelected;
|
||||||
|
|
||||||
|
const SelectTrainSuggestionsShared({
|
||||||
|
required this.choices,
|
||||||
|
this.currentInput,
|
||||||
|
required this.onTrainSelected,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var sliversTuple = operators.map(
|
var slivers = choices.map((c) => c.company).toSet().map((operator) => OperatorAutocompleteSliver(
|
||||||
(op) => Tuple2(
|
operatorName: operator,
|
||||||
getFilteredLines(op, userInput),
|
trains: choices.where((c) => c.company == operator).toList(),
|
||||||
op.operator,
|
onTrainSelected: onTrainSelected,
|
||||||
)
|
|
||||||
).where((tuple) => tuple.item1.isNotEmpty).toList();
|
|
||||||
if (userInput.isNotEmpty) sliversTuple.sort((a, b) {
|
|
||||||
final aTrain = a.item1.first;
|
|
||||||
final bTrain = b.item1.first;
|
|
||||||
|
|
||||||
final inputAsRegExp = RegExp(userInput);
|
|
||||||
|
|
||||||
final matchOnA = inputAsRegExp.firstMatch(aTrain.number)!;
|
|
||||||
final matchOnB = inputAsRegExp.firstMatch(bTrain.number)!;
|
|
||||||
|
|
||||||
if (matchOnA.start != matchOnB.start) return matchOnA.start - matchOnB.start;
|
|
||||||
|
|
||||||
if (aTrain.number.length != bTrain.number.length) return aTrain.number.length - bTrain.number.length;
|
|
||||||
|
|
||||||
return aTrain.number.compareTo(bTrain.number);
|
|
||||||
});
|
|
||||||
var slivers = sliversTuple.map((tuple) => OperatorAutocompleteSliver(
|
|
||||||
uiDesign: widget.uiDesign,
|
|
||||||
operatorName: tuple.item2,
|
|
||||||
trains: tuple.item1,
|
|
||||||
onTrainSelected: widget.onTrainSelected,
|
|
||||||
)).toList();
|
)).toList();
|
||||||
|
|
||||||
return CustomScrollView(
|
return CustomScrollView(
|
||||||
slivers: <Widget>[
|
slivers: <Widget>[
|
||||||
...slivers,
|
...slivers,
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: int.tryParse(userInput) != null ? getUseCurrentInputWidget(userInput, widget.onTrainSelected) : Container(),
|
child: currentInput != null && int.tryParse(currentInput!) != null ? getUseCurrentInputWidget(currentInput!, onTrainSelected) : Container(),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Container(
|
child: Container(
|
||||||
|
@ -117,44 +79,21 @@ abstract class SelectTrainSuggestionsState extends State<SelectTrainSuggestions>
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TrainOperatorTrainDescription> getFilteredLines(TrainOperatorLines _operator, String currentInput) {
|
|
||||||
if (currentInput.isNotEmpty) {
|
|
||||||
final filteredLines = _operator.trains
|
|
||||||
.where((elem) => elem.number.contains(currentInput))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
filteredLines.sort((a, b) {
|
|
||||||
final inputAsRegExp = RegExp(currentInput);
|
|
||||||
|
|
||||||
final matchOnA = inputAsRegExp.firstMatch(a.number)!;
|
|
||||||
final matchOnB = inputAsRegExp.firstMatch(b.number)!;
|
|
||||||
|
|
||||||
if (matchOnA.start != matchOnB.start) return matchOnA.start - matchOnB.start;
|
|
||||||
|
|
||||||
if (a.number.length != b.number.length) return a.number.length - b.number.length;
|
|
||||||
|
|
||||||
return a.number.compareTo(b.number);
|
|
||||||
});
|
|
||||||
|
|
||||||
return filteredLines;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return _operator.trains;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class OperatorAutocompleteSliver extends StatelessWidget {
|
class OperatorAutocompleteSliver extends ConsumerWidget {
|
||||||
final UiDesign? uiDesign;
|
|
||||||
final String operatorName;
|
final String operatorName;
|
||||||
final List<TrainOperatorTrainDescription> trains;
|
final List<TrainsResult> trains;
|
||||||
final void Function(String) onTrainSelected;
|
final void Function(String) onTrainSelected;
|
||||||
|
|
||||||
const OperatorAutocompleteSliver({ Key? key, required this.uiDesign, required this.operatorName, required this.trains, required this.onTrainSelected }) : super(key: key);
|
const OperatorAutocompleteSliver({
|
||||||
|
super.key,
|
||||||
|
required this.operatorName,
|
||||||
|
required this.trains,
|
||||||
|
required this.onTrainSelected,
|
||||||
|
});
|
||||||
|
|
||||||
Widget mapTrainToItem(TrainOperatorTrainDescription train) {
|
Widget mapTrainToItem(TrainsResult train, UiDesign uiDesign) {
|
||||||
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
|
||||||
switch (uiDesign) {
|
switch (uiDesign) {
|
||||||
case UiDesign.MATERIAL:
|
case UiDesign.MATERIAL:
|
||||||
return OperatorAutocompleteTileMaterial(
|
return OperatorAutocompleteTileMaterial(
|
||||||
|
@ -168,13 +107,20 @@ class OperatorAutocompleteSliver extends StatelessWidget {
|
||||||
operatorName: operatorName,
|
operatorName: operatorName,
|
||||||
train: train,
|
train: train,
|
||||||
);
|
);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return OperatorAutocompleteTileFluent(
|
||||||
|
onTrainSelected: onTrainSelected,
|
||||||
|
operatorName: operatorName,
|
||||||
|
train: train,
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
if (trains.isEmpty) {
|
if (trains.isEmpty) {
|
||||||
return SliverToBoxAdapter(child: Container(),);
|
return SliverToBoxAdapter(child: Container(),);
|
||||||
}
|
}
|
||||||
|
@ -182,14 +128,14 @@ class OperatorAutocompleteSliver extends StatelessWidget {
|
||||||
return SliverPrototypeExtentList(
|
return SliverPrototypeExtentList(
|
||||||
prototypeItem: Column(
|
prototypeItem: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
mapTrainToItem(TrainOperatorTrainDescription()),
|
mapTrainToItem(const TrainsResult(company: 'Company', number: '123', rank: 'R'), uiDesign),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
return Column(
|
return Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
mapTrainToItem(trains[index]),
|
mapTrainToItem(trains[index], uiDesign),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -202,7 +148,7 @@ class OperatorAutocompleteSliver extends StatelessWidget {
|
||||||
|
|
||||||
abstract class OperatorAutocompleteTile extends StatelessWidget {
|
abstract class OperatorAutocompleteTile extends StatelessWidget {
|
||||||
final String operatorName;
|
final String operatorName;
|
||||||
final TrainOperatorTrainDescription train;
|
final TrainsResult train;
|
||||||
final void Function(String) onTrainSelected;
|
final void Function(String) onTrainSelected;
|
||||||
|
|
||||||
const OperatorAutocompleteTile({ Key? key, required this.onTrainSelected, required this.operatorName, required this.train }) : super(key: key);
|
const OperatorAutocompleteTile({ Key? key, required this.onTrainSelected, required this.operatorName, required this.train }) : super(key: key);
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:info_tren/components/cupertino_divider.dart';
|
import 'package:info_tren/components/cupertino_divider.dart';
|
||||||
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions.dart';
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions.dart';
|
||||||
import 'package:info_tren/models/train_operator_lines.dart';
|
import 'package:info_tren/components/train_id_text_span.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
|
||||||
|
class SelectTrainSuggestionsCupertino extends SelectTrainSuggestionsShared {
|
||||||
|
const SelectTrainSuggestionsCupertino({
|
||||||
|
super.key,
|
||||||
|
required super.choices,
|
||||||
|
required super.onTrainSelected,
|
||||||
|
super.currentInput,
|
||||||
|
});
|
||||||
|
|
||||||
class SelectTrainSuggestionsStateCupertino extends SelectTrainSuggestionsState {
|
|
||||||
@override
|
@override
|
||||||
Widget getUseCurrentInputWidget(String currentInput, void Function(String) onTrainSelected) {
|
Widget getUseCurrentInputWidget(String currentInput, void Function(String) onTrainSelected) {
|
||||||
return Column(
|
return Column(
|
||||||
|
@ -21,18 +29,18 @@ class SelectTrainSuggestionsStateCupertino extends SelectTrainSuggestionsState {
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
CupertinoDivider(),
|
const CupertinoDivider(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class OperatorAutocompleteTileCupertino extends OperatorAutocompleteTile {
|
class OperatorAutocompleteTileCupertino extends OperatorAutocompleteTile {
|
||||||
OperatorAutocompleteTileCupertino({
|
const OperatorAutocompleteTileCupertino({
|
||||||
Key? key,
|
Key? key,
|
||||||
required String operatorName,
|
required String operatorName,
|
||||||
required void Function(String) onTrainSelected,
|
required void Function(String) onTrainSelected,
|
||||||
required TrainOperatorTrainDescription train
|
required TrainsResult train
|
||||||
}): super(
|
}): super(
|
||||||
onTrainSelected: onTrainSelected,
|
onTrainSelected: onTrainSelected,
|
||||||
operatorName: operatorName,
|
operatorName: operatorName,
|
||||||
|
@ -62,8 +70,8 @@ class OperatorAutocompleteTileCupertino extends OperatorAutocompleteTile {
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(fontSize: 10, fontWeight: FontWeight.w200),
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(fontSize: 10, fontWeight: FontWeight.w200),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
Text(
|
Text.rich(
|
||||||
"${train.rang} ${train.number}",
|
trainIdSpan(rank: train.rank, number: train.number),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -71,7 +79,7 @@ class OperatorAutocompleteTileCupertino extends OperatorAutocompleteTile {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
CupertinoDivider(),
|
const CupertinoDivider(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions.dart';
|
||||||
|
import 'package:info_tren/components/train_id_text_span.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
|
||||||
|
class SelectTrainSuggestionsFluent extends SelectTrainSuggestionsShared {
|
||||||
|
const SelectTrainSuggestionsFluent({
|
||||||
|
super.key,
|
||||||
|
required super.choices,
|
||||||
|
required super.onTrainSelected,
|
||||||
|
super.currentInput,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget getUseCurrentInputWidget(String currentInput, void Function(String) onTrainSelected) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Button(
|
||||||
|
child: Text(getUseCurrentInputWidgetText(currentInput)),
|
||||||
|
onPressed: () => onTrainSelected(currentInput),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OperatorAutocompleteTileFluent extends OperatorAutocompleteTile {
|
||||||
|
const OperatorAutocompleteTileFluent({
|
||||||
|
Key? key,
|
||||||
|
required String operatorName,
|
||||||
|
required void Function(String) onTrainSelected,
|
||||||
|
required TrainsResult train
|
||||||
|
}): super(
|
||||||
|
onTrainSelected: onTrainSelected,
|
||||||
|
operatorName: operatorName,
|
||||||
|
train: train,
|
||||||
|
key: key,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
onTrainSelected(train.number);
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 4, 16, 4),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
operatorName,
|
||||||
|
style: FluentTheme.of(context).typography.body?.copyWith(fontSize: 10, fontWeight: FontWeight.w200),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
Text.rich(
|
||||||
|
trainIdSpan(rank: train.rank, number: train.number),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,16 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions.dart';
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions.dart';
|
||||||
import 'package:info_tren/models/train_operator_lines.dart';
|
import 'package:info_tren/components/train_id_text_span.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
|
||||||
|
class SelectTrainSuggestionsMaterial extends SelectTrainSuggestionsShared {
|
||||||
|
const SelectTrainSuggestionsMaterial({
|
||||||
|
super.key,
|
||||||
|
required super.choices,
|
||||||
|
required super.onTrainSelected,
|
||||||
|
super.currentInput,
|
||||||
|
});
|
||||||
|
|
||||||
class SelectTrainSuggestionsStateMaterial extends SelectTrainSuggestionsState {
|
|
||||||
@override
|
@override
|
||||||
Widget getUseCurrentInputWidget(String currentInput, void Function(String) onTrainSelected) {
|
Widget getUseCurrentInputWidget(String currentInput, void Function(String) onTrainSelected) {
|
||||||
return Column(
|
return Column(
|
||||||
|
@ -14,18 +22,18 @@ class SelectTrainSuggestionsStateMaterial extends SelectTrainSuggestionsState {
|
||||||
onTrainSelected(currentInput);
|
onTrainSelected(currentInput);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Divider(),
|
const Divider(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class OperatorAutocompleteTileMaterial extends OperatorAutocompleteTile {
|
class OperatorAutocompleteTileMaterial extends OperatorAutocompleteTile {
|
||||||
OperatorAutocompleteTileMaterial({
|
const OperatorAutocompleteTileMaterial({
|
||||||
Key? key,
|
Key? key,
|
||||||
required String operatorName,
|
required String operatorName,
|
||||||
required void Function(String) onTrainSelected,
|
required void Function(String) onTrainSelected,
|
||||||
required TrainOperatorTrainDescription train
|
required TrainsResult train
|
||||||
}): super(
|
}): super(
|
||||||
onTrainSelected: onTrainSelected,
|
onTrainSelected: onTrainSelected,
|
||||||
operatorName: operatorName,
|
operatorName: operatorName,
|
||||||
|
@ -37,7 +45,7 @@ class OperatorAutocompleteTileMaterial extends OperatorAutocompleteTile {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
dense: true,
|
dense: true,
|
||||||
title: Text("${train.rang} ${train.number}"),
|
title: Text.rich(trainIdSpan(rank: train.rank, number: train.number)),
|
||||||
subtitle: Text(operatorName),
|
subtitle: Text(operatorName),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
onTrainSelected(train.number);
|
onTrainSelected(train.number);
|
||||||
|
|
|
@ -5,10 +5,11 @@ class SlimAppBar extends StatelessWidget {
|
||||||
final double size;
|
final double size;
|
||||||
// final Function onBackTap;
|
// final Function onBackTap;
|
||||||
|
|
||||||
SlimAppBar({
|
const SlimAppBar({
|
||||||
required this.title,
|
required this.title,
|
||||||
this.size = 24,
|
this.size = 24,
|
||||||
// this.onBackTap,
|
// this.onBackTap,
|
||||||
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -28,11 +29,11 @@ class SlimAppBar extends StatelessWidget {
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Container(
|
SizedBox(
|
||||||
height: size,
|
height: size,
|
||||||
width: size,
|
width: size,
|
||||||
child: (ModalRoute.of(context)?.canPop ?? false)
|
child: (ModalRoute.of(context)?.canPop ?? false)
|
||||||
? BackButtonIcon()
|
? const BackButtonIcon()
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
|
@ -43,13 +44,13 @@ class SlimAppBar extends StatelessWidget {
|
||||||
title,
|
title,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style:
|
style:
|
||||||
Theme.of(context).appBarTheme.textTheme?.caption?.copyWith(color: Theme.of(context).appBarTheme.textTheme?.bodyText2?.color) ??
|
Theme.of(context).textTheme.titleSmall?.copyWith(color: Theme.of(context).textTheme.titleLarge?.color) ??
|
||||||
Theme.of(context).textTheme.caption?.copyWith(color: Theme.of(context).textTheme.bodyText2?.color),
|
Theme.of(context).textTheme.bodySmall?.copyWith(color: Theme.of(context).textTheme.bodyMedium?.color),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
SizedBox(
|
||||||
height: size,
|
height: size,
|
||||||
width: size,
|
width: size,
|
||||||
),
|
),
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
||||||
class SliverPersistentHeaderPadding extends StatelessWidget {
|
class SliverPersistentHeaderPadding extends StatelessWidget {
|
||||||
final double maxHeight;
|
final double maxHeight;
|
||||||
|
|
||||||
const SliverPersistentHeaderPadding({required this.maxHeight});
|
const SliverPersistentHeaderPadding({required this.maxHeight, super.key,});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
39
lib/components/train_id_text_span.dart
Normal file
39
lib/components/train_id_text_span.dart
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
|
||||||
|
TextSpan trainIdSpan({
|
||||||
|
required String rank,
|
||||||
|
required String number,
|
||||||
|
Locale? locale,
|
||||||
|
MouseCursor? mouseCursor,
|
||||||
|
void Function(PointerEnterEvent)? onEnter,
|
||||||
|
void Function(PointerExitEvent)? onExit,
|
||||||
|
GestureRecognizer? recognizer,
|
||||||
|
String? semanticsLabel,
|
||||||
|
bool? spellOut,
|
||||||
|
TextStyle? style,
|
||||||
|
}) => TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: rank,
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: rank.startsWith('IC')
|
||||||
|
? const Color.fromARGB(255, 0, 255, 0)
|
||||||
|
: rank.startsWith('IR')
|
||||||
|
? const Color.fromARGB(255, 255, 0, 0)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
TextSpan(text: number),
|
||||||
|
],
|
||||||
|
locale: locale,
|
||||||
|
mouseCursor: mouseCursor,
|
||||||
|
onEnter: onEnter,
|
||||||
|
onExit: onExit,
|
||||||
|
recognizer: recognizer,
|
||||||
|
semanticsLabel: semanticsLabel,
|
||||||
|
spellOut: spellOut,
|
||||||
|
style: style,
|
||||||
|
);
|
213
lib/main.dart
213
lib/main.dart
|
@ -1,91 +1,190 @@
|
||||||
import 'dart:io' show Platform;
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:dynamic_color/dynamic_color.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:fluent_ui/fluent_ui.dart' as f;
|
||||||
|
import 'package:flutter/cupertino.dart' as c;
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
|
import 'package:flutter/material.dart' as m;
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
// import 'package:flutter_redux/flutter_redux.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:info_tren/models/ui_design.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/pages/about/about_page.dart';
|
||||||
import 'package:info_tren/pages/main/main_page.dart';
|
import 'package:info_tren/pages/main/main_page.dart';
|
||||||
|
import 'package:info_tren/pages/settings/setings_page.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/select_train/select_train.dart';
|
import 'package:info_tren/pages/train_info_page/select_train/select_train.dart';
|
||||||
|
import 'package:info_tren/providers.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:timezone/data/latest.dart';
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
void main() {
|
initializeTimeZones();
|
||||||
// final store = createStore();
|
final sharedPreferences = await SharedPreferences.getInstance();
|
||||||
// runApp(
|
|
||||||
// StoreProvider(
|
|
||||||
// store: store,
|
|
||||||
// child: StartPoint(),
|
|
||||||
// )
|
|
||||||
// );
|
|
||||||
runApp(
|
runApp(
|
||||||
StartPoint(),
|
ProviderScope(
|
||||||
|
overrides: [
|
||||||
|
sharedPreferencesProvider.overrideWithValue(sharedPreferences),
|
||||||
|
],
|
||||||
|
child: const StartPoint(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, WidgetBuilder> routesByUiDesign(UiDesign uiDesign) => {
|
Map<String, WidgetBuilder> get routes => {
|
||||||
Navigator.defaultRouteName: (context) {
|
Navigator.defaultRouteName: (context) {
|
||||||
return MainPage(uiDesign: uiDesign,);
|
return const MainPage();
|
||||||
|
},
|
||||||
|
AboutPage.routeName: (context) {
|
||||||
|
return const AboutPage();
|
||||||
|
},
|
||||||
|
SettingsPage.routeName: (context) {
|
||||||
|
return const SettingsPage();
|
||||||
},
|
},
|
||||||
SelectTrainPage.routeName: (context) {
|
SelectTrainPage.routeName: (context) {
|
||||||
return SelectTrainPage(uiDesign: uiDesign);
|
return const SelectTrainPage();
|
||||||
},
|
},
|
||||||
TrainInfo.routeName: (context) {
|
TrainInfo.routeName: (context) {
|
||||||
return TrainInfo(
|
final args = ModalRoute.of(context)!.settings.arguments as TrainInfoArguments;
|
||||||
trainNumber: ModalRoute.of(context)!.settings.arguments as String,
|
return ProviderScope(
|
||||||
uiDesign: uiDesign,
|
overrides: [
|
||||||
|
trainInfoArgumentsProvider.overrideWithValue(args),
|
||||||
|
],
|
||||||
|
child: const TrainInfo(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
SelectStationPage.routeName: (context) {
|
SelectStationPage.routeName: (context) {
|
||||||
return SelectStationPage(uiDesign: uiDesign,);
|
return const SelectStationPage();
|
||||||
},
|
},
|
||||||
ViewStationPage.routeName: (context) {
|
ViewStationPage.routeName: (context) {
|
||||||
return ViewStationPage(
|
final args = ModalRoute.of(context)!.settings.arguments as ViewStationArguments;
|
||||||
stationName: ModalRoute.of(context)!.settings.arguments as String,
|
return ProviderScope(
|
||||||
uiDesign: uiDesign,
|
overrides: [
|
||||||
|
viewStationArgumentsProvider.overrideWithValue(args),
|
||||||
|
],
|
||||||
|
child: const ViewStationPage(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
class StartPoint extends StatelessWidget {
|
class DragFluentScrollBevahior extends f.FluentScrollBehavior {
|
||||||
final String appTitle = 'Info Tren';
|
const DragFluentScrollBevahior();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Set<PointerDeviceKind> get dragDevices => {
|
||||||
if (Platform.isIOS || Platform.isMacOS) {
|
PointerDeviceKind.mouse,
|
||||||
return AnnotatedRegion(
|
PointerDeviceKind.touch,
|
||||||
value: const SystemUiOverlayStyle(
|
};
|
||||||
statusBarBrightness: Brightness.dark,
|
}
|
||||||
),
|
|
||||||
child: CupertinoApp(
|
class DragCupertinoScrollBevahior extends c.CupertinoScrollBehavior {
|
||||||
title: appTitle,
|
const DragCupertinoScrollBevahior();
|
||||||
theme: CupertinoThemeData(
|
|
||||||
primaryColor: Colors.blue.shade600,
|
@override
|
||||||
brightness: Brightness.dark,
|
Set<PointerDeviceKind> get dragDevices => {
|
||||||
// textTheme: CupertinoTextThemeData(
|
PointerDeviceKind.mouse,
|
||||||
// textStyle: TextStyle(
|
PointerDeviceKind.touch,
|
||||||
// fontFamily: 'Atkinson Hyperlegible',
|
};
|
||||||
// ),
|
}
|
||||||
// ),
|
|
||||||
),
|
class DragMaterialScrollBevahior extends m.MaterialScrollBehavior {
|
||||||
routes: routesByUiDesign(UiDesign.CUPERTINO),
|
const DragMaterialScrollBevahior();
|
||||||
),
|
|
||||||
|
@override
|
||||||
|
Set<PointerDeviceKind> get dragDevices => {
|
||||||
|
PointerDeviceKind.mouse,
|
||||||
|
PointerDeviceKind.touch,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class StartPoint extends ConsumerWidget {
|
||||||
|
final String appTitle = 'Info Tren';
|
||||||
|
|
||||||
|
const StartPoint({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
|
if (uiDesign == UiDesign.CUPERTINO) {
|
||||||
|
return DynamicColorBuilder(
|
||||||
|
builder: (lightScheme, darkScheme) {
|
||||||
|
return AnnotatedRegion(
|
||||||
|
value: const SystemUiOverlayStyle(
|
||||||
|
statusBarBrightness: c.Brightness.dark,
|
||||||
|
),
|
||||||
|
child: c.CupertinoApp(
|
||||||
|
title: appTitle,
|
||||||
|
theme: c.CupertinoThemeData(
|
||||||
|
primaryColor: darkScheme?.primary ?? m.Colors.blue.shade600,
|
||||||
|
brightness: c.Brightness.dark,
|
||||||
|
// textTheme: CupertinoTextThemeData(
|
||||||
|
// textStyle: TextStyle(
|
||||||
|
// fontFamily: 'Atkinson Hyperlegible',
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
),
|
||||||
|
scrollBehavior: Platform.isLinux ? const DragCupertinoScrollBevahior() : null,
|
||||||
|
routes: routes,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (uiDesign == UiDesign.FLUENT) {
|
||||||
|
return DynamicColorBuilder(
|
||||||
|
builder: (lightScheme, darkScheme) {
|
||||||
|
return f.FluentApp(
|
||||||
|
title: appTitle,
|
||||||
|
theme: f.FluentThemeData(
|
||||||
|
brightness: f.Brightness.light,
|
||||||
|
accentColor: lightScheme != null ? f.AccentColor.swatch({
|
||||||
|
'normal': lightScheme.primary,
|
||||||
|
}) : f.Colors.blue,
|
||||||
|
),
|
||||||
|
darkTheme: f.FluentThemeData(
|
||||||
|
brightness: f.Brightness.dark,
|
||||||
|
accentColor: darkScheme != null ? f.AccentColor.swatch({
|
||||||
|
'normal': darkScheme.primary,
|
||||||
|
}) : f.Colors.blue,
|
||||||
|
),
|
||||||
|
routes: routes,
|
||||||
|
scrollBehavior: Platform.isLinux ? const DragFluentScrollBevahior() : const f.FluentScrollBehavior(),
|
||||||
|
);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return MaterialApp(
|
return DynamicColorBuilder(
|
||||||
title: appTitle,
|
builder: (lightScheme, darkScheme) {
|
||||||
theme: ThemeData(
|
lightScheme ??= m.ColorScheme.fromSwatch(
|
||||||
primarySwatch: Colors.blue,
|
brightness: m.Brightness.light,
|
||||||
brightness: Brightness.dark,
|
primarySwatch: m.Colors.blue,
|
||||||
primaryColor: Colors.blue.shade600,
|
);
|
||||||
accentColor: Colors.blue.shade700,
|
darkScheme ??= m.ColorScheme.fromSwatch(
|
||||||
// fontFamily: 'Atkinson Hyperlegible',
|
brightness: m.Brightness.dark,
|
||||||
),
|
primarySwatch: m.Colors.blue,
|
||||||
routes: routesByUiDesign(UiDesign.MATERIAL),
|
);
|
||||||
|
|
||||||
|
|
||||||
|
return m.MaterialApp(
|
||||||
|
title: appTitle,
|
||||||
|
theme: m.ThemeData(
|
||||||
|
colorScheme: lightScheme,
|
||||||
|
useMaterial3: true,
|
||||||
|
// fontFamily: 'Atkinson Hyperlegible',
|
||||||
|
),
|
||||||
|
darkTheme: m.ThemeData(
|
||||||
|
colorScheme: darkScheme,
|
||||||
|
useMaterial3: true,
|
||||||
|
// fontFamily: 'Atkinson Hyperlegible',
|
||||||
|
),
|
||||||
|
scrollBehavior: Platform.isLinux ? const DragMaterialScrollBevahior() : null,
|
||||||
|
routes: routes,
|
||||||
|
);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
lib/models.dart
Normal file
14
lib/models.dart
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
export 'package:info_tren/models/changelog_entry.dart';
|
||||||
|
export 'package:info_tren/models/station_arrdep.dart';
|
||||||
|
export 'package:info_tren/models/station_data.dart';
|
||||||
|
export 'package:info_tren/models/station_status.dart';
|
||||||
|
export 'package:info_tren/models/station_train.dart';
|
||||||
|
export 'package:info_tren/models/stations_result.dart';
|
||||||
|
export 'package:info_tren/models/train_data.dart';
|
||||||
|
export 'package:info_tren/models/trains_result.dart';
|
||||||
|
export 'package:info_tren/models/ui_design.dart';
|
||||||
|
export 'package:info_tren/models/ui_timezone.dart';
|
||||||
|
|
||||||
|
import 'package:info_tren/models/train_data.dart' show TrainDataStatusState;
|
||||||
|
|
||||||
|
typedef TrainDataState = TrainDataStatusState;
|
83
lib/models/changelog_entry.dart
Normal file
83
lib/models/changelog_entry.dart
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
import 'package:quiver/core.dart';
|
||||||
|
|
||||||
|
class ChangelogEntry {
|
||||||
|
final ChangelogVersion version;
|
||||||
|
final String description;
|
||||||
|
final Uri? apkLink;
|
||||||
|
final Uri? linuxLink;
|
||||||
|
final Uri? windowsLink;
|
||||||
|
|
||||||
|
ChangelogEntry({
|
||||||
|
required this.version,
|
||||||
|
required this.description,
|
||||||
|
this.apkLink,
|
||||||
|
this.linuxLink,
|
||||||
|
this.windowsLink,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory ChangelogEntry.fromTextBlock(String text) {
|
||||||
|
final lines = text.split(RegExp(r'(\r?\n)+'));
|
||||||
|
return ChangelogEntry(
|
||||||
|
version: ChangelogVersion.parse(lines.first),
|
||||||
|
description: lines.skip(1).join('\n'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<ChangelogEntry> fromTextFile(String text) {
|
||||||
|
final blocks = text.split(RegExp(r'(\r?\n){2}'));
|
||||||
|
return blocks.map(ChangelogEntry.fromTextBlock).toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChangelogVersion implements Comparable<ChangelogVersion> {
|
||||||
|
final int major;
|
||||||
|
final int minor;
|
||||||
|
final int patch;
|
||||||
|
final String? prerelease;
|
||||||
|
|
||||||
|
ChangelogVersion(this.major, this.minor, this.patch, [this.prerelease]);
|
||||||
|
|
||||||
|
factory ChangelogVersion.parse(String version) {
|
||||||
|
if (version.startsWith('v')) {
|
||||||
|
version = version.substring(1);
|
||||||
|
}
|
||||||
|
String? prerelease;
|
||||||
|
if (version.contains('-')) {
|
||||||
|
final index = version.indexOf('-');
|
||||||
|
prerelease = version.substring(index + 1);
|
||||||
|
version = version.substring(0, index);
|
||||||
|
}
|
||||||
|
final splitted = version.split('.').map(int.parse).toList();
|
||||||
|
return ChangelogVersion(splitted[0], splitted[1], splitted[2], prerelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
final vString = 'v$major.$minor.$patch';
|
||||||
|
return prerelease == null ? vString : '$vString-$prerelease';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator==(dynamic other) {
|
||||||
|
if (other is! ChangelogVersion) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return major == other.major && minor == other.minor && patch == other.patch && prerelease == other.prerelease;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return hash3(major.hashCode, minor.hashCode, patch.hashCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int compareTo(ChangelogVersion other) {
|
||||||
|
if (major != other.major) {
|
||||||
|
return major.compareTo(other.major);
|
||||||
|
}
|
||||||
|
if (minor != other.minor) {
|
||||||
|
return minor.compareTo(other.minor);
|
||||||
|
}
|
||||||
|
return patch.compareTo(other.patch);
|
||||||
|
}
|
||||||
|
}
|
18
lib/models/station_arrdep.dart
Normal file
18
lib/models/station_arrdep.dart
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
|
||||||
|
part 'station_arrdep.g.dart';
|
||||||
|
part 'station_arrdep.freezed.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class StationArrDep with _$StationArrDep {
|
||||||
|
const factory StationArrDep({
|
||||||
|
required int? stoppingTime,
|
||||||
|
required DateTime time,
|
||||||
|
required StationTrain train,
|
||||||
|
required StationStatus status,
|
||||||
|
}) = _StationArrDep;
|
||||||
|
|
||||||
|
factory StationArrDep.fromJson(Map<String, dynamic> json) => _$StationArrDepFromJson(json);
|
||||||
|
}
|
||||||
|
|
241
lib/models/station_arrdep.freezed.dart
Normal file
241
lib/models/station_arrdep.freezed.dart
Normal file
|
@ -0,0 +1,241 @@
|
||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'station_arrdep.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||||
|
|
||||||
|
StationArrDep _$StationArrDepFromJson(Map<String, dynamic> json) {
|
||||||
|
return _StationArrDep.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$StationArrDep {
|
||||||
|
int? get stoppingTime => throw _privateConstructorUsedError;
|
||||||
|
DateTime get time => throw _privateConstructorUsedError;
|
||||||
|
StationTrain get train => throw _privateConstructorUsedError;
|
||||||
|
StationStatus get status => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
$StationArrDepCopyWith<StationArrDep> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $StationArrDepCopyWith<$Res> {
|
||||||
|
factory $StationArrDepCopyWith(
|
||||||
|
StationArrDep value, $Res Function(StationArrDep) then) =
|
||||||
|
_$StationArrDepCopyWithImpl<$Res, StationArrDep>;
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{int? stoppingTime,
|
||||||
|
DateTime time,
|
||||||
|
StationTrain train,
|
||||||
|
StationStatus status});
|
||||||
|
|
||||||
|
$StationTrainCopyWith<$Res> get train;
|
||||||
|
$StationStatusCopyWith<$Res> get status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$StationArrDepCopyWithImpl<$Res, $Val extends StationArrDep>
|
||||||
|
implements $StationArrDepCopyWith<$Res> {
|
||||||
|
_$StationArrDepCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? stoppingTime = freezed,
|
||||||
|
Object? time = null,
|
||||||
|
Object? train = null,
|
||||||
|
Object? status = null,
|
||||||
|
}) {
|
||||||
|
return _then(_value.copyWith(
|
||||||
|
stoppingTime: freezed == stoppingTime
|
||||||
|
? _value.stoppingTime
|
||||||
|
: stoppingTime // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,
|
||||||
|
time: null == time
|
||||||
|
? _value.time
|
||||||
|
: time // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,
|
||||||
|
train: null == train
|
||||||
|
? _value.train
|
||||||
|
: train // ignore: cast_nullable_to_non_nullable
|
||||||
|
as StationTrain,
|
||||||
|
status: null == status
|
||||||
|
? _value.status
|
||||||
|
: status // ignore: cast_nullable_to_non_nullable
|
||||||
|
as StationStatus,
|
||||||
|
) as $Val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$StationTrainCopyWith<$Res> get train {
|
||||||
|
return $StationTrainCopyWith<$Res>(_value.train, (value) {
|
||||||
|
return _then(_value.copyWith(train: value) as $Val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$StationStatusCopyWith<$Res> get status {
|
||||||
|
return $StationStatusCopyWith<$Res>(_value.status, (value) {
|
||||||
|
return _then(_value.copyWith(status: value) as $Val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$_StationArrDepCopyWith<$Res>
|
||||||
|
implements $StationArrDepCopyWith<$Res> {
|
||||||
|
factory _$$_StationArrDepCopyWith(
|
||||||
|
_$_StationArrDep value, $Res Function(_$_StationArrDep) then) =
|
||||||
|
__$$_StationArrDepCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{int? stoppingTime,
|
||||||
|
DateTime time,
|
||||||
|
StationTrain train,
|
||||||
|
StationStatus status});
|
||||||
|
|
||||||
|
@override
|
||||||
|
$StationTrainCopyWith<$Res> get train;
|
||||||
|
@override
|
||||||
|
$StationStatusCopyWith<$Res> get status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$_StationArrDepCopyWithImpl<$Res>
|
||||||
|
extends _$StationArrDepCopyWithImpl<$Res, _$_StationArrDep>
|
||||||
|
implements _$$_StationArrDepCopyWith<$Res> {
|
||||||
|
__$$_StationArrDepCopyWithImpl(
|
||||||
|
_$_StationArrDep _value, $Res Function(_$_StationArrDep) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? stoppingTime = freezed,
|
||||||
|
Object? time = null,
|
||||||
|
Object? train = null,
|
||||||
|
Object? status = null,
|
||||||
|
}) {
|
||||||
|
return _then(_$_StationArrDep(
|
||||||
|
stoppingTime: freezed == stoppingTime
|
||||||
|
? _value.stoppingTime
|
||||||
|
: stoppingTime // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int?,
|
||||||
|
time: null == time
|
||||||
|
? _value.time
|
||||||
|
: time // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,
|
||||||
|
train: null == train
|
||||||
|
? _value.train
|
||||||
|
: train // ignore: cast_nullable_to_non_nullable
|
||||||
|
as StationTrain,
|
||||||
|
status: null == status
|
||||||
|
? _value.status
|
||||||
|
: status // ignore: cast_nullable_to_non_nullable
|
||||||
|
as StationStatus,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$_StationArrDep implements _StationArrDep {
|
||||||
|
const _$_StationArrDep(
|
||||||
|
{required this.stoppingTime,
|
||||||
|
required this.time,
|
||||||
|
required this.train,
|
||||||
|
required this.status});
|
||||||
|
|
||||||
|
factory _$_StationArrDep.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$_StationArrDepFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final int? stoppingTime;
|
||||||
|
@override
|
||||||
|
final DateTime time;
|
||||||
|
@override
|
||||||
|
final StationTrain train;
|
||||||
|
@override
|
||||||
|
final StationStatus status;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'StationArrDep(stoppingTime: $stoppingTime, time: $time, train: $train, status: $status)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(dynamic other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$_StationArrDep &&
|
||||||
|
(identical(other.stoppingTime, stoppingTime) ||
|
||||||
|
other.stoppingTime == stoppingTime) &&
|
||||||
|
(identical(other.time, time) || other.time == time) &&
|
||||||
|
(identical(other.train, train) || other.train == train) &&
|
||||||
|
(identical(other.status, status) || other.status == status));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
Object.hash(runtimeType, stoppingTime, time, train, status);
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$_StationArrDepCopyWith<_$_StationArrDep> get copyWith =>
|
||||||
|
__$$_StationArrDepCopyWithImpl<_$_StationArrDep>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$_StationArrDepToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _StationArrDep implements StationArrDep {
|
||||||
|
const factory _StationArrDep(
|
||||||
|
{required final int? stoppingTime,
|
||||||
|
required final DateTime time,
|
||||||
|
required final StationTrain train,
|
||||||
|
required final StationStatus status}) = _$_StationArrDep;
|
||||||
|
|
||||||
|
factory _StationArrDep.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$_StationArrDep.fromJson;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int? get stoppingTime;
|
||||||
|
@override
|
||||||
|
DateTime get time;
|
||||||
|
@override
|
||||||
|
StationTrain get train;
|
||||||
|
@override
|
||||||
|
StationStatus get status;
|
||||||
|
@override
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
_$$_StationArrDepCopyWith<_$_StationArrDep> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
23
lib/models/station_arrdep.g.dart
Normal file
23
lib/models/station_arrdep.g.dart
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'station_arrdep.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$_StationArrDep _$$_StationArrDepFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$_StationArrDep(
|
||||||
|
stoppingTime: json['stoppingTime'] as int?,
|
||||||
|
time: DateTime.parse(json['time'] as String),
|
||||||
|
train: StationTrain.fromJson(json['train'] as Map<String, dynamic>),
|
||||||
|
status: StationStatus.fromJson(json['status'] as Map<String, dynamic>),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_StationArrDepToJson(_$_StationArrDep instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'stoppingTime': instance.stoppingTime,
|
||||||
|
'time': instance.time.toIso8601String(),
|
||||||
|
'train': instance.train,
|
||||||
|
'status': instance.status,
|
||||||
|
};
|
|
@ -1,68 +1,17 @@
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
|
||||||
part 'station_data.g.dart';
|
part 'station_data.g.dart';
|
||||||
|
part 'station_data.freezed.dart';
|
||||||
|
|
||||||
@JsonSerializable()
|
@freezed
|
||||||
class StationData {
|
class StationData with _$StationData {
|
||||||
final String date;
|
const factory StationData({
|
||||||
final String stationName;
|
required String date,
|
||||||
final List<StationArrival>? arrivals;
|
required String stationName,
|
||||||
final List<StationDeparture>? departures;
|
required List<StationArrDep>? arrivals,
|
||||||
|
required List<StationArrDep>? departures,
|
||||||
const StationData({required this.date, required this.stationName, required this.arrivals, required this.departures});
|
}) = _StationData;
|
||||||
|
|
||||||
factory StationData.fromJson(Map<String, dynamic> json) => _$StationDataFromJson(json);
|
factory StationData.fromJson(Map<String, dynamic> json) => _$StationDataFromJson(json);
|
||||||
Map<String, dynamic> toJson() => _$StationDataToJson(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class StationArrival {
|
|
||||||
final int? stoppingTime;
|
|
||||||
final DateTime time;
|
|
||||||
final StationTrainArr train;
|
|
||||||
|
|
||||||
const StationArrival({required this.stoppingTime, required this.time, required this.train,});
|
|
||||||
|
|
||||||
factory StationArrival.fromJson(Map<String, dynamic> json) => _$StationArrivalFromJson(json);
|
|
||||||
Map<String, dynamic> toJson() => _$StationArrivalToJson(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class StationDeparture {
|
|
||||||
final int? stoppingTime;
|
|
||||||
final DateTime time;
|
|
||||||
final StationTrainDep train;
|
|
||||||
|
|
||||||
const StationDeparture({required this.stoppingTime, required this.time, required this.train,});
|
|
||||||
|
|
||||||
factory StationDeparture.fromJson(Map<String, dynamic> json) => _$StationDepartureFromJson(json);
|
|
||||||
Map<String, dynamic> toJson() => _$StationDepartureToJson(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class StationTrainArr {
|
|
||||||
final String rank;
|
|
||||||
final String number;
|
|
||||||
final String operator;
|
|
||||||
final String origin;
|
|
||||||
final List<String>? route;
|
|
||||||
|
|
||||||
StationTrainArr({required this.rank, required this.number, required this.operator, required this.origin, this.route,});
|
|
||||||
|
|
||||||
factory StationTrainArr.fromJson(Map<String, dynamic> json) => _$StationTrainArrFromJson(json);
|
|
||||||
Map<String, dynamic> toJson() => _$StationTrainArrToJson(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class StationTrainDep {
|
|
||||||
final String rank;
|
|
||||||
final String number;
|
|
||||||
final String operator;
|
|
||||||
final String destination;
|
|
||||||
final List<String>? route;
|
|
||||||
|
|
||||||
StationTrainDep({required this.rank, required this.number, required this.operator, required this.destination, this.route,});
|
|
||||||
|
|
||||||
factory StationTrainDep.fromJson(Map<String, dynamic> json) => _$StationTrainDepFromJson(json);
|
|
||||||
Map<String, dynamic> toJson() => _$StationTrainDepToJson(this);
|
|
||||||
}
|
}
|
||||||
|
|
239
lib/models/station_data.freezed.dart
Normal file
239
lib/models/station_data.freezed.dart
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'station_data.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||||
|
|
||||||
|
StationData _$StationDataFromJson(Map<String, dynamic> json) {
|
||||||
|
return _StationData.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$StationData {
|
||||||
|
String get date => throw _privateConstructorUsedError;
|
||||||
|
String get stationName => throw _privateConstructorUsedError;
|
||||||
|
List<StationArrDep>? get arrivals => throw _privateConstructorUsedError;
|
||||||
|
List<StationArrDep>? get departures => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
$StationDataCopyWith<StationData> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $StationDataCopyWith<$Res> {
|
||||||
|
factory $StationDataCopyWith(
|
||||||
|
StationData value, $Res Function(StationData) then) =
|
||||||
|
_$StationDataCopyWithImpl<$Res, StationData>;
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{String date,
|
||||||
|
String stationName,
|
||||||
|
List<StationArrDep>? arrivals,
|
||||||
|
List<StationArrDep>? departures});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$StationDataCopyWithImpl<$Res, $Val extends StationData>
|
||||||
|
implements $StationDataCopyWith<$Res> {
|
||||||
|
_$StationDataCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? date = null,
|
||||||
|
Object? stationName = null,
|
||||||
|
Object? arrivals = freezed,
|
||||||
|
Object? departures = freezed,
|
||||||
|
}) {
|
||||||
|
return _then(_value.copyWith(
|
||||||
|
date: null == date
|
||||||
|
? _value.date
|
||||||
|
: date // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
stationName: null == stationName
|
||||||
|
? _value.stationName
|
||||||
|
: stationName // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
arrivals: freezed == arrivals
|
||||||
|
? _value.arrivals
|
||||||
|
: arrivals // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<StationArrDep>?,
|
||||||
|
departures: freezed == departures
|
||||||
|
? _value.departures
|
||||||
|
: departures // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<StationArrDep>?,
|
||||||
|
) as $Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$_StationDataCopyWith<$Res>
|
||||||
|
implements $StationDataCopyWith<$Res> {
|
||||||
|
factory _$$_StationDataCopyWith(
|
||||||
|
_$_StationData value, $Res Function(_$_StationData) then) =
|
||||||
|
__$$_StationDataCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{String date,
|
||||||
|
String stationName,
|
||||||
|
List<StationArrDep>? arrivals,
|
||||||
|
List<StationArrDep>? departures});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$_StationDataCopyWithImpl<$Res>
|
||||||
|
extends _$StationDataCopyWithImpl<$Res, _$_StationData>
|
||||||
|
implements _$$_StationDataCopyWith<$Res> {
|
||||||
|
__$$_StationDataCopyWithImpl(
|
||||||
|
_$_StationData _value, $Res Function(_$_StationData) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? date = null,
|
||||||
|
Object? stationName = null,
|
||||||
|
Object? arrivals = freezed,
|
||||||
|
Object? departures = freezed,
|
||||||
|
}) {
|
||||||
|
return _then(_$_StationData(
|
||||||
|
date: null == date
|
||||||
|
? _value.date
|
||||||
|
: date // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
stationName: null == stationName
|
||||||
|
? _value.stationName
|
||||||
|
: stationName // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
arrivals: freezed == arrivals
|
||||||
|
? _value._arrivals
|
||||||
|
: arrivals // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<StationArrDep>?,
|
||||||
|
departures: freezed == departures
|
||||||
|
? _value._departures
|
||||||
|
: departures // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<StationArrDep>?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$_StationData implements _StationData {
|
||||||
|
const _$_StationData(
|
||||||
|
{required this.date,
|
||||||
|
required this.stationName,
|
||||||
|
required final List<StationArrDep>? arrivals,
|
||||||
|
required final List<StationArrDep>? departures})
|
||||||
|
: _arrivals = arrivals,
|
||||||
|
_departures = departures;
|
||||||
|
|
||||||
|
factory _$_StationData.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$_StationDataFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String date;
|
||||||
|
@override
|
||||||
|
final String stationName;
|
||||||
|
final List<StationArrDep>? _arrivals;
|
||||||
|
@override
|
||||||
|
List<StationArrDep>? get arrivals {
|
||||||
|
final value = _arrivals;
|
||||||
|
if (value == null) return null;
|
||||||
|
if (_arrivals is EqualUnmodifiableListView) return _arrivals;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<StationArrDep>? _departures;
|
||||||
|
@override
|
||||||
|
List<StationArrDep>? get departures {
|
||||||
|
final value = _departures;
|
||||||
|
if (value == null) return null;
|
||||||
|
if (_departures is EqualUnmodifiableListView) return _departures;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'StationData(date: $date, stationName: $stationName, arrivals: $arrivals, departures: $departures)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(dynamic other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$_StationData &&
|
||||||
|
(identical(other.date, date) || other.date == date) &&
|
||||||
|
(identical(other.stationName, stationName) ||
|
||||||
|
other.stationName == stationName) &&
|
||||||
|
const DeepCollectionEquality().equals(other._arrivals, _arrivals) &&
|
||||||
|
const DeepCollectionEquality()
|
||||||
|
.equals(other._departures, _departures));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType,
|
||||||
|
date,
|
||||||
|
stationName,
|
||||||
|
const DeepCollectionEquality().hash(_arrivals),
|
||||||
|
const DeepCollectionEquality().hash(_departures));
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$_StationDataCopyWith<_$_StationData> get copyWith =>
|
||||||
|
__$$_StationDataCopyWithImpl<_$_StationData>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$_StationDataToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _StationData implements StationData {
|
||||||
|
const factory _StationData(
|
||||||
|
{required final String date,
|
||||||
|
required final String stationName,
|
||||||
|
required final List<StationArrDep>? arrivals,
|
||||||
|
required final List<StationArrDep>? departures}) = _$_StationData;
|
||||||
|
|
||||||
|
factory _StationData.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$_StationData.fromJson;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get date;
|
||||||
|
@override
|
||||||
|
String get stationName;
|
||||||
|
@override
|
||||||
|
List<StationArrDep>? get arrivals;
|
||||||
|
@override
|
||||||
|
List<StationArrDep>? get departures;
|
||||||
|
@override
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
_$$_StationDataCopyWith<_$_StationData> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
|
@ -6,87 +6,22 @@ part of 'station_data.dart';
|
||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
StationData _$StationDataFromJson(Map<String, dynamic> json) => StationData(
|
_$_StationData _$$_StationDataFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$_StationData(
|
||||||
date: json['date'] as String,
|
date: json['date'] as String,
|
||||||
stationName: json['stationName'] as String,
|
stationName: json['stationName'] as String,
|
||||||
arrivals: (json['arrivals'] as List<dynamic>?)
|
arrivals: (json['arrivals'] as List<dynamic>?)
|
||||||
?.map((e) => StationArrival.fromJson(e as Map<String, dynamic>))
|
?.map((e) => StationArrDep.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
departures: (json['departures'] as List<dynamic>?)
|
departures: (json['departures'] as List<dynamic>?)
|
||||||
?.map((e) => StationDeparture.fromJson(e as Map<String, dynamic>))
|
?.map((e) => StationArrDep.fromJson(e as Map<String, dynamic>))
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$StationDataToJson(StationData instance) =>
|
Map<String, dynamic> _$$_StationDataToJson(_$_StationData instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'date': instance.date,
|
'date': instance.date,
|
||||||
'stationName': instance.stationName,
|
'stationName': instance.stationName,
|
||||||
'arrivals': instance.arrivals,
|
'arrivals': instance.arrivals,
|
||||||
'departures': instance.departures,
|
'departures': instance.departures,
|
||||||
};
|
};
|
||||||
|
|
||||||
StationArrival _$StationArrivalFromJson(Map<String, dynamic> json) =>
|
|
||||||
StationArrival(
|
|
||||||
stoppingTime: json['stoppingTime'] as int?,
|
|
||||||
time: DateTime.parse(json['time'] as String),
|
|
||||||
train: StationTrainArr.fromJson(json['train'] as Map<String, dynamic>),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$StationArrivalToJson(StationArrival instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'stoppingTime': instance.stoppingTime,
|
|
||||||
'time': instance.time.toIso8601String(),
|
|
||||||
'train': instance.train,
|
|
||||||
};
|
|
||||||
|
|
||||||
StationDeparture _$StationDepartureFromJson(Map<String, dynamic> json) =>
|
|
||||||
StationDeparture(
|
|
||||||
stoppingTime: json['stoppingTime'] as int?,
|
|
||||||
time: DateTime.parse(json['time'] as String),
|
|
||||||
train: StationTrainDep.fromJson(json['train'] as Map<String, dynamic>),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$StationDepartureToJson(StationDeparture instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'stoppingTime': instance.stoppingTime,
|
|
||||||
'time': instance.time.toIso8601String(),
|
|
||||||
'train': instance.train,
|
|
||||||
};
|
|
||||||
|
|
||||||
StationTrainArr _$StationTrainArrFromJson(Map<String, dynamic> json) =>
|
|
||||||
StationTrainArr(
|
|
||||||
rank: json['rank'] as String,
|
|
||||||
number: json['number'] as String,
|
|
||||||
operator: json['operator'] as String,
|
|
||||||
origin: json['origin'] as String,
|
|
||||||
route:
|
|
||||||
(json['route'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$StationTrainArrToJson(StationTrainArr instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'rank': instance.rank,
|
|
||||||
'number': instance.number,
|
|
||||||
'operator': instance.operator,
|
|
||||||
'origin': instance.origin,
|
|
||||||
'route': instance.route,
|
|
||||||
};
|
|
||||||
|
|
||||||
StationTrainDep _$StationTrainDepFromJson(Map<String, dynamic> json) =>
|
|
||||||
StationTrainDep(
|
|
||||||
rank: json['rank'] as String,
|
|
||||||
number: json['number'] as String,
|
|
||||||
operator: json['operator'] as String,
|
|
||||||
destination: json['destination'] as String,
|
|
||||||
route:
|
|
||||||
(json['route'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$StationTrainDepToJson(StationTrainDep instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'rank': instance.rank,
|
|
||||||
'number': instance.number,
|
|
||||||
'operator': instance.operator,
|
|
||||||
'destination': instance.destination,
|
|
||||||
'route': instance.route,
|
|
||||||
};
|
|
||||||
|
|
17
lib/models/station_status.dart
Normal file
17
lib/models/station_status.dart
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'station_status.g.dart';
|
||||||
|
part 'station_status.freezed.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class StationStatus with _$StationStatus {
|
||||||
|
const factory StationStatus({
|
||||||
|
required int delay,
|
||||||
|
required bool real,
|
||||||
|
required bool cancelled,
|
||||||
|
required String? platform,
|
||||||
|
}) = _StationStatus;
|
||||||
|
|
||||||
|
factory StationStatus.fromJson(Map<String, dynamic> json) => _$StationStatusFromJson(json);
|
||||||
|
}
|
||||||
|
|
210
lib/models/station_status.freezed.dart
Normal file
210
lib/models/station_status.freezed.dart
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'station_status.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||||
|
|
||||||
|
StationStatus _$StationStatusFromJson(Map<String, dynamic> json) {
|
||||||
|
return _StationStatus.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$StationStatus {
|
||||||
|
int get delay => throw _privateConstructorUsedError;
|
||||||
|
bool get real => throw _privateConstructorUsedError;
|
||||||
|
bool get cancelled => throw _privateConstructorUsedError;
|
||||||
|
String? get platform => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
$StationStatusCopyWith<StationStatus> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $StationStatusCopyWith<$Res> {
|
||||||
|
factory $StationStatusCopyWith(
|
||||||
|
StationStatus value, $Res Function(StationStatus) then) =
|
||||||
|
_$StationStatusCopyWithImpl<$Res, StationStatus>;
|
||||||
|
@useResult
|
||||||
|
$Res call({int delay, bool real, bool cancelled, String? platform});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$StationStatusCopyWithImpl<$Res, $Val extends StationStatus>
|
||||||
|
implements $StationStatusCopyWith<$Res> {
|
||||||
|
_$StationStatusCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? delay = null,
|
||||||
|
Object? real = null,
|
||||||
|
Object? cancelled = null,
|
||||||
|
Object? platform = freezed,
|
||||||
|
}) {
|
||||||
|
return _then(_value.copyWith(
|
||||||
|
delay: null == delay
|
||||||
|
? _value.delay
|
||||||
|
: delay // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
|
real: null == real
|
||||||
|
? _value.real
|
||||||
|
: real // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
cancelled: null == cancelled
|
||||||
|
? _value.cancelled
|
||||||
|
: cancelled // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
platform: freezed == platform
|
||||||
|
? _value.platform
|
||||||
|
: platform // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
) as $Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$_StationStatusCopyWith<$Res>
|
||||||
|
implements $StationStatusCopyWith<$Res> {
|
||||||
|
factory _$$_StationStatusCopyWith(
|
||||||
|
_$_StationStatus value, $Res Function(_$_StationStatus) then) =
|
||||||
|
__$$_StationStatusCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({int delay, bool real, bool cancelled, String? platform});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$_StationStatusCopyWithImpl<$Res>
|
||||||
|
extends _$StationStatusCopyWithImpl<$Res, _$_StationStatus>
|
||||||
|
implements _$$_StationStatusCopyWith<$Res> {
|
||||||
|
__$$_StationStatusCopyWithImpl(
|
||||||
|
_$_StationStatus _value, $Res Function(_$_StationStatus) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? delay = null,
|
||||||
|
Object? real = null,
|
||||||
|
Object? cancelled = null,
|
||||||
|
Object? platform = freezed,
|
||||||
|
}) {
|
||||||
|
return _then(_$_StationStatus(
|
||||||
|
delay: null == delay
|
||||||
|
? _value.delay
|
||||||
|
: delay // ignore: cast_nullable_to_non_nullable
|
||||||
|
as int,
|
||||||
|
real: null == real
|
||||||
|
? _value.real
|
||||||
|
: real // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
cancelled: null == cancelled
|
||||||
|
? _value.cancelled
|
||||||
|
: cancelled // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,
|
||||||
|
platform: freezed == platform
|
||||||
|
? _value.platform
|
||||||
|
: platform // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$_StationStatus implements _StationStatus {
|
||||||
|
const _$_StationStatus(
|
||||||
|
{required this.delay,
|
||||||
|
required this.real,
|
||||||
|
required this.cancelled,
|
||||||
|
required this.platform});
|
||||||
|
|
||||||
|
factory _$_StationStatus.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$_StationStatusFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final int delay;
|
||||||
|
@override
|
||||||
|
final bool real;
|
||||||
|
@override
|
||||||
|
final bool cancelled;
|
||||||
|
@override
|
||||||
|
final String? platform;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'StationStatus(delay: $delay, real: $real, cancelled: $cancelled, platform: $platform)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(dynamic other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$_StationStatus &&
|
||||||
|
(identical(other.delay, delay) || other.delay == delay) &&
|
||||||
|
(identical(other.real, real) || other.real == real) &&
|
||||||
|
(identical(other.cancelled, cancelled) ||
|
||||||
|
other.cancelled == cancelled) &&
|
||||||
|
(identical(other.platform, platform) ||
|
||||||
|
other.platform == platform));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
int get hashCode =>
|
||||||
|
Object.hash(runtimeType, delay, real, cancelled, platform);
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$_StationStatusCopyWith<_$_StationStatus> get copyWith =>
|
||||||
|
__$$_StationStatusCopyWithImpl<_$_StationStatus>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$_StationStatusToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _StationStatus implements StationStatus {
|
||||||
|
const factory _StationStatus(
|
||||||
|
{required final int delay,
|
||||||
|
required final bool real,
|
||||||
|
required final bool cancelled,
|
||||||
|
required final String? platform}) = _$_StationStatus;
|
||||||
|
|
||||||
|
factory _StationStatus.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$_StationStatus.fromJson;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get delay;
|
||||||
|
@override
|
||||||
|
bool get real;
|
||||||
|
@override
|
||||||
|
bool get cancelled;
|
||||||
|
@override
|
||||||
|
String? get platform;
|
||||||
|
@override
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
_$$_StationStatusCopyWith<_$_StationStatus> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
23
lib/models/station_status.g.dart
Normal file
23
lib/models/station_status.g.dart
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'station_status.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$_StationStatus _$$_StationStatusFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$_StationStatus(
|
||||||
|
delay: json['delay'] as int,
|
||||||
|
real: json['real'] as bool,
|
||||||
|
cancelled: json['cancelled'] as bool,
|
||||||
|
platform: json['platform'] as String?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_StationStatusToJson(_$_StationStatus instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'delay': instance.delay,
|
||||||
|
'real': instance.real,
|
||||||
|
'cancelled': instance.cancelled,
|
||||||
|
'platform': instance.platform,
|
||||||
|
};
|
19
lib/models/station_train.dart
Normal file
19
lib/models/station_train.dart
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'station_train.g.dart';
|
||||||
|
part 'station_train.freezed.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class StationTrain with _$StationTrain {
|
||||||
|
const factory StationTrain({
|
||||||
|
required String rank,
|
||||||
|
required String number,
|
||||||
|
required String operator,
|
||||||
|
required String terminus,
|
||||||
|
List<String>? route,
|
||||||
|
required DateTime departureDate,
|
||||||
|
}) = _StationTrain;
|
||||||
|
|
||||||
|
factory StationTrain.fromJson(Map<String, dynamic> json) => _$StationTrainFromJson(json);
|
||||||
|
}
|
||||||
|
|
268
lib/models/station_train.freezed.dart
Normal file
268
lib/models/station_train.freezed.dart
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'station_train.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||||
|
|
||||||
|
StationTrain _$StationTrainFromJson(Map<String, dynamic> json) {
|
||||||
|
return _StationTrain.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$StationTrain {
|
||||||
|
String get rank => throw _privateConstructorUsedError;
|
||||||
|
String get number => throw _privateConstructorUsedError;
|
||||||
|
String get operator => throw _privateConstructorUsedError;
|
||||||
|
String get terminus => throw _privateConstructorUsedError;
|
||||||
|
List<String>? get route => throw _privateConstructorUsedError;
|
||||||
|
DateTime get departureDate => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
$StationTrainCopyWith<StationTrain> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $StationTrainCopyWith<$Res> {
|
||||||
|
factory $StationTrainCopyWith(
|
||||||
|
StationTrain value, $Res Function(StationTrain) then) =
|
||||||
|
_$StationTrainCopyWithImpl<$Res, StationTrain>;
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{String rank,
|
||||||
|
String number,
|
||||||
|
String operator,
|
||||||
|
String terminus,
|
||||||
|
List<String>? route,
|
||||||
|
DateTime departureDate});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$StationTrainCopyWithImpl<$Res, $Val extends StationTrain>
|
||||||
|
implements $StationTrainCopyWith<$Res> {
|
||||||
|
_$StationTrainCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? rank = null,
|
||||||
|
Object? number = null,
|
||||||
|
Object? operator = null,
|
||||||
|
Object? terminus = null,
|
||||||
|
Object? route = freezed,
|
||||||
|
Object? departureDate = null,
|
||||||
|
}) {
|
||||||
|
return _then(_value.copyWith(
|
||||||
|
rank: null == rank
|
||||||
|
? _value.rank
|
||||||
|
: rank // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
number: null == number
|
||||||
|
? _value.number
|
||||||
|
: number // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
operator: null == operator
|
||||||
|
? _value.operator
|
||||||
|
: operator // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
terminus: null == terminus
|
||||||
|
? _value.terminus
|
||||||
|
: terminus // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
route: freezed == route
|
||||||
|
? _value.route
|
||||||
|
: route // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<String>?,
|
||||||
|
departureDate: null == departureDate
|
||||||
|
? _value.departureDate
|
||||||
|
: departureDate // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,
|
||||||
|
) as $Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$_StationTrainCopyWith<$Res>
|
||||||
|
implements $StationTrainCopyWith<$Res> {
|
||||||
|
factory _$$_StationTrainCopyWith(
|
||||||
|
_$_StationTrain value, $Res Function(_$_StationTrain) then) =
|
||||||
|
__$$_StationTrainCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call(
|
||||||
|
{String rank,
|
||||||
|
String number,
|
||||||
|
String operator,
|
||||||
|
String terminus,
|
||||||
|
List<String>? route,
|
||||||
|
DateTime departureDate});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$_StationTrainCopyWithImpl<$Res>
|
||||||
|
extends _$StationTrainCopyWithImpl<$Res, _$_StationTrain>
|
||||||
|
implements _$$_StationTrainCopyWith<$Res> {
|
||||||
|
__$$_StationTrainCopyWithImpl(
|
||||||
|
_$_StationTrain _value, $Res Function(_$_StationTrain) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? rank = null,
|
||||||
|
Object? number = null,
|
||||||
|
Object? operator = null,
|
||||||
|
Object? terminus = null,
|
||||||
|
Object? route = freezed,
|
||||||
|
Object? departureDate = null,
|
||||||
|
}) {
|
||||||
|
return _then(_$_StationTrain(
|
||||||
|
rank: null == rank
|
||||||
|
? _value.rank
|
||||||
|
: rank // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
number: null == number
|
||||||
|
? _value.number
|
||||||
|
: number // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
operator: null == operator
|
||||||
|
? _value.operator
|
||||||
|
: operator // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
terminus: null == terminus
|
||||||
|
? _value.terminus
|
||||||
|
: terminus // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
route: freezed == route
|
||||||
|
? _value._route
|
||||||
|
: route // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<String>?,
|
||||||
|
departureDate: null == departureDate
|
||||||
|
? _value.departureDate
|
||||||
|
: departureDate // ignore: cast_nullable_to_non_nullable
|
||||||
|
as DateTime,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$_StationTrain implements _StationTrain {
|
||||||
|
const _$_StationTrain(
|
||||||
|
{required this.rank,
|
||||||
|
required this.number,
|
||||||
|
required this.operator,
|
||||||
|
required this.terminus,
|
||||||
|
final List<String>? route,
|
||||||
|
required this.departureDate})
|
||||||
|
: _route = route;
|
||||||
|
|
||||||
|
factory _$_StationTrain.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$_StationTrainFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String rank;
|
||||||
|
@override
|
||||||
|
final String number;
|
||||||
|
@override
|
||||||
|
final String operator;
|
||||||
|
@override
|
||||||
|
final String terminus;
|
||||||
|
final List<String>? _route;
|
||||||
|
@override
|
||||||
|
List<String>? get route {
|
||||||
|
final value = _route;
|
||||||
|
if (value == null) return null;
|
||||||
|
if (_route is EqualUnmodifiableListView) return _route;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
final DateTime departureDate;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'StationTrain(rank: $rank, number: $number, operator: $operator, terminus: $terminus, route: $route, departureDate: $departureDate)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(dynamic other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$_StationTrain &&
|
||||||
|
(identical(other.rank, rank) || other.rank == rank) &&
|
||||||
|
(identical(other.number, number) || other.number == number) &&
|
||||||
|
(identical(other.operator, operator) ||
|
||||||
|
other.operator == operator) &&
|
||||||
|
(identical(other.terminus, terminus) ||
|
||||||
|
other.terminus == terminus) &&
|
||||||
|
const DeepCollectionEquality().equals(other._route, _route) &&
|
||||||
|
(identical(other.departureDate, departureDate) ||
|
||||||
|
other.departureDate == departureDate));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, rank, number, operator, terminus,
|
||||||
|
const DeepCollectionEquality().hash(_route), departureDate);
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$_StationTrainCopyWith<_$_StationTrain> get copyWith =>
|
||||||
|
__$$_StationTrainCopyWithImpl<_$_StationTrain>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$_StationTrainToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _StationTrain implements StationTrain {
|
||||||
|
const factory _StationTrain(
|
||||||
|
{required final String rank,
|
||||||
|
required final String number,
|
||||||
|
required final String operator,
|
||||||
|
required final String terminus,
|
||||||
|
final List<String>? route,
|
||||||
|
required final DateTime departureDate}) = _$_StationTrain;
|
||||||
|
|
||||||
|
factory _StationTrain.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$_StationTrain.fromJson;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get rank;
|
||||||
|
@override
|
||||||
|
String get number;
|
||||||
|
@override
|
||||||
|
String get operator;
|
||||||
|
@override
|
||||||
|
String get terminus;
|
||||||
|
@override
|
||||||
|
List<String>? get route;
|
||||||
|
@override
|
||||||
|
DateTime get departureDate;
|
||||||
|
@override
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
_$$_StationTrainCopyWith<_$_StationTrain> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
28
lib/models/station_train.g.dart
Normal file
28
lib/models/station_train.g.dart
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'station_train.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$_StationTrain _$$_StationTrainFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$_StationTrain(
|
||||||
|
rank: json['rank'] as String,
|
||||||
|
number: json['number'] as String,
|
||||||
|
operator: json['operator'] as String,
|
||||||
|
terminus: json['terminus'] as String,
|
||||||
|
route:
|
||||||
|
(json['route'] as List<dynamic>?)?.map((e) => e as String).toList(),
|
||||||
|
departureDate: DateTime.parse(json['departureDate'] as String),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_StationTrainToJson(_$_StationTrain instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'rank': instance.rank,
|
||||||
|
'number': instance.number,
|
||||||
|
'operator': instance.operator,
|
||||||
|
'terminus': instance.terminus,
|
||||||
|
'route': instance.route,
|
||||||
|
'departureDate': instance.departureDate.toIso8601String(),
|
||||||
|
};
|
|
@ -1,14 +1,14 @@
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
part 'stations_result.g.dart';
|
part 'stations_result.g.dart';
|
||||||
|
part 'stations_result.freezed.dart';
|
||||||
|
|
||||||
@JsonSerializable()
|
@freezed
|
||||||
class StationsResult {
|
class StationsResult with _$StationsResult {
|
||||||
final String name;
|
const factory StationsResult({
|
||||||
final List<String>? stoppedAtBy;
|
required String name,
|
||||||
|
List<String>? stoppedAtBy,
|
||||||
const StationsResult({required this.name, this.stoppedAtBy});
|
}) = _StationsResult;
|
||||||
|
|
||||||
factory StationsResult.fromJson(Map<String, dynamic> json) => _$StationsResultFromJson(json);
|
factory StationsResult.fromJson(Map<String, dynamic> json) => _$StationsResultFromJson(json);
|
||||||
Map<String, dynamic> toJson() => _$StationsResultToJson(this);
|
}
|
||||||
}
|
|
||||||
|
|
179
lib/models/stations_result.freezed.dart
Normal file
179
lib/models/stations_result.freezed.dart
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'stations_result.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||||
|
|
||||||
|
StationsResult _$StationsResultFromJson(Map<String, dynamic> json) {
|
||||||
|
return _StationsResult.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$StationsResult {
|
||||||
|
String get name => throw _privateConstructorUsedError;
|
||||||
|
List<String>? get stoppedAtBy => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
$StationsResultCopyWith<StationsResult> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $StationsResultCopyWith<$Res> {
|
||||||
|
factory $StationsResultCopyWith(
|
||||||
|
StationsResult value, $Res Function(StationsResult) then) =
|
||||||
|
_$StationsResultCopyWithImpl<$Res, StationsResult>;
|
||||||
|
@useResult
|
||||||
|
$Res call({String name, List<String>? stoppedAtBy});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$StationsResultCopyWithImpl<$Res, $Val extends StationsResult>
|
||||||
|
implements $StationsResultCopyWith<$Res> {
|
||||||
|
_$StationsResultCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? name = null,
|
||||||
|
Object? stoppedAtBy = freezed,
|
||||||
|
}) {
|
||||||
|
return _then(_value.copyWith(
|
||||||
|
name: null == name
|
||||||
|
? _value.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
stoppedAtBy: freezed == stoppedAtBy
|
||||||
|
? _value.stoppedAtBy
|
||||||
|
: stoppedAtBy // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<String>?,
|
||||||
|
) as $Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$_StationsResultCopyWith<$Res>
|
||||||
|
implements $StationsResultCopyWith<$Res> {
|
||||||
|
factory _$$_StationsResultCopyWith(
|
||||||
|
_$_StationsResult value, $Res Function(_$_StationsResult) then) =
|
||||||
|
__$$_StationsResultCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({String name, List<String>? stoppedAtBy});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$_StationsResultCopyWithImpl<$Res>
|
||||||
|
extends _$StationsResultCopyWithImpl<$Res, _$_StationsResult>
|
||||||
|
implements _$$_StationsResultCopyWith<$Res> {
|
||||||
|
__$$_StationsResultCopyWithImpl(
|
||||||
|
_$_StationsResult _value, $Res Function(_$_StationsResult) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? name = null,
|
||||||
|
Object? stoppedAtBy = freezed,
|
||||||
|
}) {
|
||||||
|
return _then(_$_StationsResult(
|
||||||
|
name: null == name
|
||||||
|
? _value.name
|
||||||
|
: name // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
stoppedAtBy: freezed == stoppedAtBy
|
||||||
|
? _value._stoppedAtBy
|
||||||
|
: stoppedAtBy // ignore: cast_nullable_to_non_nullable
|
||||||
|
as List<String>?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$_StationsResult implements _StationsResult {
|
||||||
|
const _$_StationsResult({required this.name, final List<String>? stoppedAtBy})
|
||||||
|
: _stoppedAtBy = stoppedAtBy;
|
||||||
|
|
||||||
|
factory _$_StationsResult.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$_StationsResultFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String name;
|
||||||
|
final List<String>? _stoppedAtBy;
|
||||||
|
@override
|
||||||
|
List<String>? get stoppedAtBy {
|
||||||
|
final value = _stoppedAtBy;
|
||||||
|
if (value == null) return null;
|
||||||
|
if (_stoppedAtBy is EqualUnmodifiableListView) return _stoppedAtBy;
|
||||||
|
// ignore: implicit_dynamic_type
|
||||||
|
return EqualUnmodifiableListView(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'StationsResult(name: $name, stoppedAtBy: $stoppedAtBy)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(dynamic other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$_StationsResult &&
|
||||||
|
(identical(other.name, name) || other.name == name) &&
|
||||||
|
const DeepCollectionEquality()
|
||||||
|
.equals(other._stoppedAtBy, _stoppedAtBy));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType, name, const DeepCollectionEquality().hash(_stoppedAtBy));
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$_StationsResultCopyWith<_$_StationsResult> get copyWith =>
|
||||||
|
__$$_StationsResultCopyWithImpl<_$_StationsResult>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$_StationsResultToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _StationsResult implements StationsResult {
|
||||||
|
const factory _StationsResult(
|
||||||
|
{required final String name,
|
||||||
|
final List<String>? stoppedAtBy}) = _$_StationsResult;
|
||||||
|
|
||||||
|
factory _StationsResult.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$_StationsResult.fromJson;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name;
|
||||||
|
@override
|
||||||
|
List<String>? get stoppedAtBy;
|
||||||
|
@override
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
_$$_StationsResultCopyWith<_$_StationsResult> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
|
@ -6,15 +6,15 @@ part of 'stations_result.dart';
|
||||||
// JsonSerializableGenerator
|
// JsonSerializableGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
StationsResult _$StationsResultFromJson(Map<String, dynamic> json) =>
|
_$_StationsResult _$$_StationsResultFromJson(Map<String, dynamic> json) =>
|
||||||
StationsResult(
|
_$_StationsResult(
|
||||||
name: json['name'] as String,
|
name: json['name'] as String,
|
||||||
stoppedAtBy: (json['stoppedAtBy'] as List<dynamic>?)
|
stoppedAtBy: (json['stoppedAtBy'] as List<dynamic>?)
|
||||||
?.map((e) => e as String)
|
?.map((e) => e as String)
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$StationsResultToJson(StationsResult instance) =>
|
Map<String, dynamic> _$$_StationsResultToJson(_$_StationsResult instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'name': instance.name,
|
'name': instance.name,
|
||||||
'stoppedAtBy': instance.stoppedAtBy,
|
'stoppedAtBy': instance.stoppedAtBy,
|
||||||
|
|
|
@ -4,181 +4,118 @@
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'train_data.freezed.dart';
|
||||||
|
part 'train_data.g.dart';
|
||||||
|
|
||||||
TrainData trainDataFromJson(String str) => TrainData.fromJson(json.decode(str));
|
TrainData trainDataFromJson(String str) => TrainData.fromJson(json.decode(str));
|
||||||
|
|
||||||
String trainDataToJson(TrainData data) => json.encode(data.toJson());
|
String trainDataToJson(TrainData data) => json.encode(data.toJson());
|
||||||
|
|
||||||
/// Results of scrapping InfoFer website for train info
|
/// Results of scrapping InfoFer website for train info
|
||||||
class TrainData {
|
@freezed
|
||||||
TrainData({
|
class TrainData with _$TrainData {
|
||||||
required this.date,
|
const TrainData._();
|
||||||
required this.number,
|
|
||||||
required this.operator,
|
const factory TrainData({
|
||||||
required this.rank,
|
required String rank,
|
||||||
required this.route,
|
required String number,
|
||||||
required this.stations,
|
required String date,
|
||||||
this.status,
|
required String operator,
|
||||||
});
|
required List<TrainDataGroup> groups,
|
||||||
|
}) = _TrainData;
|
||||||
|
|
||||||
final String date;
|
factory TrainData.fromJson(Map<String, dynamic> json) => _$TrainDataFromJson(json);
|
||||||
final String number;
|
|
||||||
final String operator;
|
TrainDataGroup get idealGroup {
|
||||||
final String rank;
|
var result = groups.first;
|
||||||
final Route route;
|
|
||||||
final List<Station> stations;
|
for (final group in groups) {
|
||||||
final TrainDataStatus? status;
|
if (result.stations.map((s) => s.linkName).toSet().difference(group.stations.map((s) => s.linkName).toSet()).isEmpty) {
|
||||||
|
result = group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
factory TrainData.fromJson(Map<String, dynamic> json) => TrainData(
|
return result;
|
||||||
date: json["date"],
|
}
|
||||||
number: json["number"],
|
|
||||||
operator: json["operator"],
|
List<TrainDataStation> get stations => idealGroup.stations;
|
||||||
rank: json["rank"],
|
TrainDataRoute get route => idealGroup.route;
|
||||||
route: Route.fromJson(json["route"]),
|
TrainDataStatus? get status => idealGroup.status;
|
||||||
stations: List<Station>.from(
|
}
|
||||||
json["stations"].map((x) => Station.fromJson(x))),
|
|
||||||
status: json["status"] == null
|
|
||||||
? null
|
|
||||||
: TrainDataStatus.fromJson(json["status"]),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
@freezed
|
||||||
"date": date,
|
class TrainDataGroup with _$TrainDataGroup {
|
||||||
"number": number,
|
const factory TrainDataGroup({
|
||||||
"operator": operator,
|
required TrainDataRoute route,
|
||||||
"rank": rank,
|
required List<TrainDataStation> stations,
|
||||||
"route": route.toJson(),
|
TrainDataStatus? status,
|
||||||
"stations": List<dynamic>.from(stations.map((x) => x.toJson())),
|
}) = _TrainDataGroup;
|
||||||
"status": status?.toJson(),
|
|
||||||
};
|
factory TrainDataGroup.fromJson(Map<String, dynamic> json) => _$TrainDataGroupFromJson(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Route of the train
|
/// Route of the train
|
||||||
class Route {
|
@freezed
|
||||||
Route({
|
class TrainDataRoute with _$TrainDataRoute {
|
||||||
required this.from,
|
const factory TrainDataRoute({
|
||||||
required this.to,
|
required String from,
|
||||||
});
|
required String to,
|
||||||
|
}) = _TrainDataRoute;
|
||||||
|
|
||||||
final String from;
|
factory TrainDataRoute.fromJson(Map<String, dynamic> json) => _$TrainDataRouteFromJson(json);
|
||||||
final String to;
|
|
||||||
|
|
||||||
factory Route.fromJson(Map<String, dynamic> json) => Route(
|
|
||||||
from: json["from"],
|
|
||||||
to: json["to"],
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
"from": from,
|
|
||||||
"to": to,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Station {
|
@freezed
|
||||||
Station({
|
class TrainDataStation with _$TrainDataStation {
|
||||||
this.arrival,
|
const factory TrainDataStation({
|
||||||
this.departure,
|
required String name,
|
||||||
required this.km,
|
required String linkName,
|
||||||
required this.name,
|
required int km,
|
||||||
this.platform,
|
int? stoppingTime,
|
||||||
this.stoppingTime,
|
String? platform,
|
||||||
});
|
StationArrDepTime? arrival,
|
||||||
|
StationArrDepTime? departure,
|
||||||
|
@TrainDataNoteConverter()
|
||||||
|
required List<TrainDataNote> notes,
|
||||||
|
}) = _TrainDataStation;
|
||||||
|
|
||||||
final StationArrDepTime? arrival;
|
factory TrainDataStation.fromJson(Map<String, dynamic> json) => _$TrainDataStationFromJson(json);
|
||||||
final StationArrDepTime? departure;
|
|
||||||
final int km;
|
|
||||||
final String name;
|
|
||||||
final String? platform;
|
|
||||||
final int? stoppingTime;
|
|
||||||
|
|
||||||
factory Station.fromJson(Map<String, dynamic> json) => Station(
|
|
||||||
arrival: json["arrival"] == null
|
|
||||||
? null
|
|
||||||
: StationArrDepTime.fromJson(json["arrival"]),
|
|
||||||
departure: json["departure"] == null
|
|
||||||
? null
|
|
||||||
: StationArrDepTime.fromJson(json["departure"]),
|
|
||||||
km: json["km"],
|
|
||||||
name: json["name"],
|
|
||||||
platform: json["platform"] == null ? null : json["platform"],
|
|
||||||
stoppingTime:
|
|
||||||
json["stoppingTime"] == null ? null : json["stoppingTime"],
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
"arrival": arrival?.toJson(),
|
|
||||||
"departure": departure?.toJson(),
|
|
||||||
"km": km,
|
|
||||||
"name": name,
|
|
||||||
"platform": platform == null ? null : platform,
|
|
||||||
"stoppingTime": stoppingTime == null ? null : stoppingTime,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StationArrDepTime {
|
@freezed
|
||||||
StationArrDepTime({
|
class StationArrDepTime with _$StationArrDepTime {
|
||||||
required this.scheduleTime,
|
const factory StationArrDepTime({
|
||||||
this.status,
|
required DateTime scheduleTime,
|
||||||
});
|
StationArrDepTimeStatus? status,
|
||||||
|
}) = _StationArrDepTime;
|
||||||
|
|
||||||
final DateTime scheduleTime;
|
factory StationArrDepTime.fromJson(Map<String, dynamic> json) => _$StationArrDepTimeFromJson(json);
|
||||||
final StationArrDepTimeStatus? status;
|
|
||||||
|
|
||||||
factory StationArrDepTime.fromJson(Map<String, dynamic> json) =>
|
|
||||||
StationArrDepTime(
|
|
||||||
scheduleTime: DateTime.parse(json["scheduleTime"] as String),
|
|
||||||
status: json["status"] == null ? null : StationArrDepTimeStatus.fromJson(json["status"]),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
"scheduleTime": scheduleTime.toIso8601String(),
|
|
||||||
"status": status?.toJson(),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class StationArrDepTimeStatus {
|
@freezed
|
||||||
StationArrDepTimeStatus({
|
class StationArrDepTimeStatus with _$StationArrDepTimeStatus {
|
||||||
required this.delay,
|
const factory StationArrDepTimeStatus({
|
||||||
required this.real,
|
required int delay,
|
||||||
});
|
required bool real,
|
||||||
|
required bool cancelled,
|
||||||
|
}) = _StationArrDepTimeStatus;
|
||||||
|
|
||||||
final int delay;
|
factory StationArrDepTimeStatus.fromJson(Map<String, dynamic> json) => _$StationArrDepTimeStatusFromJson(json);
|
||||||
final bool real;
|
|
||||||
|
|
||||||
factory StationArrDepTimeStatus.fromJson(Map<String, dynamic> json) =>
|
|
||||||
StationArrDepTimeStatus(
|
|
||||||
delay: json["delay"],
|
|
||||||
real: json["real"],
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
"delay": delay,
|
|
||||||
"real": real,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrainDataStatus {
|
@freezed
|
||||||
TrainDataStatus({
|
class TrainDataStatus with _$TrainDataStatus {
|
||||||
required this.delay,
|
const TrainDataStatus._();
|
||||||
required this.state,
|
|
||||||
required this.station,
|
|
||||||
});
|
|
||||||
|
|
||||||
final int delay;
|
const factory TrainDataStatus({
|
||||||
final State state;
|
required int delay,
|
||||||
final String station;
|
required String station,
|
||||||
|
required TrainDataStatusState state,
|
||||||
|
}) = _TrainDataStatus;
|
||||||
|
|
||||||
factory TrainDataStatus.fromJson(Map<String, dynamic> json) =>
|
factory TrainDataStatus.fromJson(Map<String, dynamic> json) => _$TrainDataStatusFromJson(json);
|
||||||
TrainDataStatus(
|
|
||||||
delay: json["delay"],
|
|
||||||
state: stateValues.map[json["state"]]!,
|
|
||||||
station: json["station"],
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
|
||||||
"delay": delay,
|
|
||||||
"state": stateValues.reverse[state],
|
|
||||||
"station": station,
|
|
||||||
};
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
@ -190,40 +127,118 @@ class TrainDataStatus {
|
||||||
result += '${delay.abs()} min';
|
result += '${delay.abs()} min';
|
||||||
}
|
}
|
||||||
result += ' la ';
|
result += ' la ';
|
||||||
switch (state) {
|
result += switch (state) {
|
||||||
case State.PASSING:
|
TrainDataStatusState.passing => 'trecerea fără oprire prin',
|
||||||
result += 'trecerea fără oprire prin';
|
TrainDataStatusState.arrival => 'sosirea în',
|
||||||
break;
|
TrainDataStatusState.departure => 'plecarea din',
|
||||||
case State.ARRIVAL:
|
};
|
||||||
result += 'sosirea în';
|
|
||||||
break;
|
|
||||||
case State.DEPARTURE:
|
|
||||||
result += 'plecarea din';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result += station;
|
result += station;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum State { PASSING, ARRIVAL, DEPARTURE }
|
enum TrainDataStatusState { passing, arrival, departure }
|
||||||
|
|
||||||
final stateValues = EnumValues({
|
abstract class TrainDataNote {
|
||||||
"arrival": State.ARRIVAL,
|
final String kind;
|
||||||
"departure": State.DEPARTURE,
|
|
||||||
"passing": State.PASSING
|
|
||||||
});
|
|
||||||
|
|
||||||
class EnumValues<T> {
|
const TrainDataNote({required this.kind});
|
||||||
Map<String, T> map;
|
|
||||||
Map<T, String>? reverseMap;
|
|
||||||
|
|
||||||
EnumValues(this.map);
|
Map<String, dynamic> toJson() => {
|
||||||
|
"kind": kind,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Map<T, String> get reverse {
|
class TrainDataNoteConverter implements JsonConverter<TrainDataNote, Map<String, dynamic>> {
|
||||||
if (reverseMap == null) {
|
const TrainDataNoteConverter();
|
||||||
reverseMap = map.map((k, v) => new MapEntry(v, k));
|
|
||||||
}
|
@override
|
||||||
return reverseMap!;
|
TrainDataNote fromJson(Map<String, dynamic> json) {
|
||||||
|
return switch(json['kind']) {
|
||||||
|
'trainNumberChange' => TrainDataNoteTrainNumberChange.fromJson(json),
|
||||||
|
'departsAs' => TrainDataNoteDepartsAs.fromJson(json),
|
||||||
|
'detachingWagons' => TrainDataNoteDetachingWagons.fromJson(json),
|
||||||
|
'receivingWagons' => TrainDataNoteReceivingWagons.fromJson(json),
|
||||||
|
_ => TrainDataNoteUnknown.fromJson(json),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson(TrainDataNote object) {
|
||||||
|
return object.toJson();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class TrainDataNoteTrainNumberChange with _$TrainDataNoteTrainNumberChange implements TrainDataNote {
|
||||||
|
@Implements<TrainDataNote>()
|
||||||
|
const factory TrainDataNoteTrainNumberChange({
|
||||||
|
// base
|
||||||
|
@Default("trainNumberChange")
|
||||||
|
String kind,
|
||||||
|
// impl
|
||||||
|
required String rank,
|
||||||
|
required String number,
|
||||||
|
}) = _TrainDataNoteTrainNumberChange;
|
||||||
|
|
||||||
|
factory TrainDataNoteTrainNumberChange.fromJson(Map<String, dynamic> json) => _$TrainDataNoteTrainNumberChangeFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class TrainDataNoteDepartsAs with _$TrainDataNoteDepartsAs implements TrainDataNote {
|
||||||
|
@Implements<TrainDataNote>()
|
||||||
|
const factory TrainDataNoteDepartsAs({
|
||||||
|
// base
|
||||||
|
@Default("departsAs")
|
||||||
|
String kind,
|
||||||
|
// impl
|
||||||
|
required String rank,
|
||||||
|
required String number,
|
||||||
|
required DateTime departureDate,
|
||||||
|
}) = _TrainDataNoteDepartsAs;
|
||||||
|
|
||||||
|
factory TrainDataNoteDepartsAs.fromJson(Map<String, dynamic> json) => _$TrainDataNoteDepartsAsFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class TrainDataNoteDetachingWagons with _$TrainDataNoteDetachingWagons implements TrainDataNote {
|
||||||
|
@Implements<TrainDataNote>()
|
||||||
|
const factory TrainDataNoteDetachingWagons({
|
||||||
|
// base
|
||||||
|
@Default("detachingWagons")
|
||||||
|
String kind,
|
||||||
|
// impl
|
||||||
|
required String station,
|
||||||
|
}) = _TrainDataNoteDetachingWagons;
|
||||||
|
|
||||||
|
factory TrainDataNoteDetachingWagons.fromJson(Map<String, dynamic> json) => _$TrainDataNoteDetachingWagonsFromJson(json);
|
||||||
|
}
|
||||||
|
@freezed
|
||||||
|
class TrainDataNoteReceivingWagons with _$TrainDataNoteReceivingWagons implements TrainDataNote {
|
||||||
|
@Implements<TrainDataNote>()
|
||||||
|
const factory TrainDataNoteReceivingWagons({
|
||||||
|
// base
|
||||||
|
@Default("receivingWagons")
|
||||||
|
String kind,
|
||||||
|
// impl
|
||||||
|
required String station,
|
||||||
|
}) = _TrainDataNoteReceivingWagons;
|
||||||
|
|
||||||
|
factory TrainDataNoteReceivingWagons.fromJson(Map<String, dynamic> json) => _$TrainDataNoteReceivingWagonsFromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class TrainDataNoteUnknown with _$TrainDataNoteUnknown implements TrainDataNote {
|
||||||
|
@Implements<TrainDataNote>()
|
||||||
|
const factory TrainDataNoteUnknown({
|
||||||
|
// base
|
||||||
|
required String kind,
|
||||||
|
// impl
|
||||||
|
required Map<String, dynamic> extra,
|
||||||
|
}) = _TrainDataNoteUnknown;
|
||||||
|
|
||||||
|
factory TrainDataNoteUnknown.fromJson(Map<String, dynamic> json) => TrainDataNoteUnknown(
|
||||||
|
kind: json['kind'],
|
||||||
|
extra: Map.from(json)..remove('kind'),
|
||||||
|
);
|
||||||
|
}
|
2365
lib/models/train_data.freezed.dart
Normal file
2365
lib/models/train_data.freezed.dart
Normal file
File diff suppressed because it is too large
Load diff
217
lib/models/train_data.g.dart
Normal file
217
lib/models/train_data.g.dart
Normal file
|
@ -0,0 +1,217 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'train_data.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$_TrainData _$$_TrainDataFromJson(Map<String, dynamic> json) => _$_TrainData(
|
||||||
|
rank: json['rank'] as String,
|
||||||
|
number: json['number'] as String,
|
||||||
|
date: json['date'] as String,
|
||||||
|
operator: json['operator'] as String,
|
||||||
|
groups: (json['groups'] as List<dynamic>)
|
||||||
|
.map((e) => TrainDataGroup.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_TrainDataToJson(_$_TrainData instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'rank': instance.rank,
|
||||||
|
'number': instance.number,
|
||||||
|
'date': instance.date,
|
||||||
|
'operator': instance.operator,
|
||||||
|
'groups': instance.groups,
|
||||||
|
};
|
||||||
|
|
||||||
|
_$_TrainDataGroup _$$_TrainDataGroupFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$_TrainDataGroup(
|
||||||
|
route: TrainDataRoute.fromJson(json['route'] as Map<String, dynamic>),
|
||||||
|
stations: (json['stations'] as List<dynamic>)
|
||||||
|
.map((e) => TrainDataStation.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
status: json['status'] == null
|
||||||
|
? null
|
||||||
|
: TrainDataStatus.fromJson(json['status'] as Map<String, dynamic>),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_TrainDataGroupToJson(_$_TrainDataGroup instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'route': instance.route,
|
||||||
|
'stations': instance.stations,
|
||||||
|
'status': instance.status,
|
||||||
|
};
|
||||||
|
|
||||||
|
_$_TrainDataRoute _$$_TrainDataRouteFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$_TrainDataRoute(
|
||||||
|
from: json['from'] as String,
|
||||||
|
to: json['to'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_TrainDataRouteToJson(_$_TrainDataRoute instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'from': instance.from,
|
||||||
|
'to': instance.to,
|
||||||
|
};
|
||||||
|
|
||||||
|
_$_TrainDataStation _$$_TrainDataStationFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$_TrainDataStation(
|
||||||
|
name: json['name'] as String,
|
||||||
|
linkName: json['linkName'] as String,
|
||||||
|
km: json['km'] as int,
|
||||||
|
stoppingTime: json['stoppingTime'] as int?,
|
||||||
|
platform: json['platform'] as String?,
|
||||||
|
arrival: json['arrival'] == null
|
||||||
|
? null
|
||||||
|
: StationArrDepTime.fromJson(json['arrival'] as Map<String, dynamic>),
|
||||||
|
departure: json['departure'] == null
|
||||||
|
? null
|
||||||
|
: StationArrDepTime.fromJson(
|
||||||
|
json['departure'] as Map<String, dynamic>),
|
||||||
|
notes: (json['notes'] as List<dynamic>)
|
||||||
|
.map((e) => const TrainDataNoteConverter()
|
||||||
|
.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_TrainDataStationToJson(_$_TrainDataStation instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'name': instance.name,
|
||||||
|
'linkName': instance.linkName,
|
||||||
|
'km': instance.km,
|
||||||
|
'stoppingTime': instance.stoppingTime,
|
||||||
|
'platform': instance.platform,
|
||||||
|
'arrival': instance.arrival,
|
||||||
|
'departure': instance.departure,
|
||||||
|
'notes':
|
||||||
|
instance.notes.map(const TrainDataNoteConverter().toJson).toList(),
|
||||||
|
};
|
||||||
|
|
||||||
|
_$_StationArrDepTime _$$_StationArrDepTimeFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$_StationArrDepTime(
|
||||||
|
scheduleTime: DateTime.parse(json['scheduleTime'] as String),
|
||||||
|
status: json['status'] == null
|
||||||
|
? null
|
||||||
|
: StationArrDepTimeStatus.fromJson(
|
||||||
|
json['status'] as Map<String, dynamic>),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_StationArrDepTimeToJson(
|
||||||
|
_$_StationArrDepTime instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'scheduleTime': instance.scheduleTime.toIso8601String(),
|
||||||
|
'status': instance.status,
|
||||||
|
};
|
||||||
|
|
||||||
|
_$_StationArrDepTimeStatus _$$_StationArrDepTimeStatusFromJson(
|
||||||
|
Map<String, dynamic> json) =>
|
||||||
|
_$_StationArrDepTimeStatus(
|
||||||
|
delay: json['delay'] as int,
|
||||||
|
real: json['real'] as bool,
|
||||||
|
cancelled: json['cancelled'] as bool,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_StationArrDepTimeStatusToJson(
|
||||||
|
_$_StationArrDepTimeStatus instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'delay': instance.delay,
|
||||||
|
'real': instance.real,
|
||||||
|
'cancelled': instance.cancelled,
|
||||||
|
};
|
||||||
|
|
||||||
|
_$_TrainDataStatus _$$_TrainDataStatusFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$_TrainDataStatus(
|
||||||
|
delay: json['delay'] as int,
|
||||||
|
station: json['station'] as String,
|
||||||
|
state: $enumDecode(_$TrainDataStatusStateEnumMap, json['state']),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_TrainDataStatusToJson(_$_TrainDataStatus instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'delay': instance.delay,
|
||||||
|
'station': instance.station,
|
||||||
|
'state': _$TrainDataStatusStateEnumMap[instance.state]!,
|
||||||
|
};
|
||||||
|
|
||||||
|
const _$TrainDataStatusStateEnumMap = {
|
||||||
|
TrainDataStatusState.passing: 'passing',
|
||||||
|
TrainDataStatusState.arrival: 'arrival',
|
||||||
|
TrainDataStatusState.departure: 'departure',
|
||||||
|
};
|
||||||
|
|
||||||
|
_$_TrainDataNoteTrainNumberChange _$$_TrainDataNoteTrainNumberChangeFromJson(
|
||||||
|
Map<String, dynamic> json) =>
|
||||||
|
_$_TrainDataNoteTrainNumberChange(
|
||||||
|
kind: json['kind'] as String? ?? "trainNumberChange",
|
||||||
|
rank: json['rank'] as String,
|
||||||
|
number: json['number'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_TrainDataNoteTrainNumberChangeToJson(
|
||||||
|
_$_TrainDataNoteTrainNumberChange instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'kind': instance.kind,
|
||||||
|
'rank': instance.rank,
|
||||||
|
'number': instance.number,
|
||||||
|
};
|
||||||
|
|
||||||
|
_$_TrainDataNoteDepartsAs _$$_TrainDataNoteDepartsAsFromJson(
|
||||||
|
Map<String, dynamic> json) =>
|
||||||
|
_$_TrainDataNoteDepartsAs(
|
||||||
|
kind: json['kind'] as String? ?? "departsAs",
|
||||||
|
rank: json['rank'] as String,
|
||||||
|
number: json['number'] as String,
|
||||||
|
departureDate: DateTime.parse(json['departureDate'] as String),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_TrainDataNoteDepartsAsToJson(
|
||||||
|
_$_TrainDataNoteDepartsAs instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'kind': instance.kind,
|
||||||
|
'rank': instance.rank,
|
||||||
|
'number': instance.number,
|
||||||
|
'departureDate': instance.departureDate.toIso8601String(),
|
||||||
|
};
|
||||||
|
|
||||||
|
_$_TrainDataNoteDetachingWagons _$$_TrainDataNoteDetachingWagonsFromJson(
|
||||||
|
Map<String, dynamic> json) =>
|
||||||
|
_$_TrainDataNoteDetachingWagons(
|
||||||
|
kind: json['kind'] as String? ?? "detachingWagons",
|
||||||
|
station: json['station'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_TrainDataNoteDetachingWagonsToJson(
|
||||||
|
_$_TrainDataNoteDetachingWagons instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'kind': instance.kind,
|
||||||
|
'station': instance.station,
|
||||||
|
};
|
||||||
|
|
||||||
|
_$_TrainDataNoteReceivingWagons _$$_TrainDataNoteReceivingWagonsFromJson(
|
||||||
|
Map<String, dynamic> json) =>
|
||||||
|
_$_TrainDataNoteReceivingWagons(
|
||||||
|
kind: json['kind'] as String? ?? "receivingWagons",
|
||||||
|
station: json['station'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_TrainDataNoteReceivingWagonsToJson(
|
||||||
|
_$_TrainDataNoteReceivingWagons instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'kind': instance.kind,
|
||||||
|
'station': instance.station,
|
||||||
|
};
|
||||||
|
|
||||||
|
_$_TrainDataNoteUnknown _$$_TrainDataNoteUnknownFromJson(
|
||||||
|
Map<String, dynamic> json) =>
|
||||||
|
_$_TrainDataNoteUnknown(
|
||||||
|
kind: json['kind'] as String,
|
||||||
|
extra: json['extra'] as Map<String, dynamic>,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_TrainDataNoteUnknownToJson(
|
||||||
|
_$_TrainDataNoteUnknown instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'kind': instance.kind,
|
||||||
|
'extra': instance.extra,
|
||||||
|
};
|
|
@ -1,42 +0,0 @@
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
|
|
||||||
part 'train_operator_lines.g.dart';
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class TrainOperatorLines {
|
|
||||||
@JsonKey(name: "short_name")
|
|
||||||
final String shortName;
|
|
||||||
final String operator;
|
|
||||||
@JsonKey(name: "versiune")
|
|
||||||
final String version;
|
|
||||||
@JsonKey(name: "trenuri")
|
|
||||||
final List<TrainOperatorTrainDescription> trains;
|
|
||||||
|
|
||||||
TrainOperatorLines({
|
|
||||||
required this.operator,
|
|
||||||
this.shortName = "",
|
|
||||||
required this.version,
|
|
||||||
required this.trains,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory TrainOperatorLines.fromJson(Map<String, dynamic> json) => _$TrainOperatorLinesFromJson(json);
|
|
||||||
Map<String, dynamic> toJson() => _$TrainOperatorLinesToJson(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class TrainOperatorTrainDescription {
|
|
||||||
final String rang;
|
|
||||||
@JsonKey(name: "numar")
|
|
||||||
final String number;
|
|
||||||
@JsonKey(name: "numar_intern")
|
|
||||||
final int internalNumber;
|
|
||||||
|
|
||||||
TrainOperatorTrainDescription({
|
|
||||||
this.number = '',
|
|
||||||
this.rang = '',
|
|
||||||
this.internalNumber = 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
factory TrainOperatorTrainDescription.fromJson(Map<String, dynamic> json) => _$TrainOperatorTrainDescriptionFromJson(json);
|
|
||||||
Map<String, dynamic> toJson() => _$TrainOperatorTrainDescriptionToJson(this);
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'train_operator_lines.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// JsonSerializableGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
TrainOperatorLines _$TrainOperatorLinesFromJson(Map<String, dynamic> json) =>
|
|
||||||
TrainOperatorLines(
|
|
||||||
operator: json['operator'] as String,
|
|
||||||
shortName: json['short_name'] as String? ?? "",
|
|
||||||
version: json['versiune'] as String,
|
|
||||||
trains: (json['trenuri'] as List<dynamic>)
|
|
||||||
.map((e) =>
|
|
||||||
TrainOperatorTrainDescription.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$TrainOperatorLinesToJson(TrainOperatorLines instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'short_name': instance.shortName,
|
|
||||||
'operator': instance.operator,
|
|
||||||
'versiune': instance.version,
|
|
||||||
'trenuri': instance.trains,
|
|
||||||
};
|
|
||||||
|
|
||||||
TrainOperatorTrainDescription _$TrainOperatorTrainDescriptionFromJson(
|
|
||||||
Map<String, dynamic> json) =>
|
|
||||||
TrainOperatorTrainDescription(
|
|
||||||
number: json['numar'] as String? ?? '',
|
|
||||||
rang: json['rang'] as String? ?? '',
|
|
||||||
internalNumber: json['numar_intern'] as int? ?? 0,
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$TrainOperatorTrainDescriptionToJson(
|
|
||||||
TrainOperatorTrainDescription instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'rang': instance.rang,
|
|
||||||
'numar': instance.number,
|
|
||||||
'numar_intern': instance.internalNumber,
|
|
||||||
};
|
|
15
lib/models/trains_result.dart
Normal file
15
lib/models/trains_result.dart
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'trains_result.g.dart';
|
||||||
|
part 'trains_result.freezed.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class TrainsResult with _$TrainsResult {
|
||||||
|
const factory TrainsResult({
|
||||||
|
required String rank,
|
||||||
|
required String number,
|
||||||
|
required String company,
|
||||||
|
}) = _TrainsResult;
|
||||||
|
|
||||||
|
factory TrainsResult.fromJson(Map<String, dynamic> json) => _$TrainsResultFromJson(json);
|
||||||
|
}
|
187
lib/models/trains_result.freezed.dart
Normal file
187
lib/models/trains_result.freezed.dart
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'trains_result.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
|
||||||
|
|
||||||
|
TrainsResult _$TrainsResultFromJson(Map<String, dynamic> json) {
|
||||||
|
return _TrainsResult.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$TrainsResult {
|
||||||
|
String get rank => throw _privateConstructorUsedError;
|
||||||
|
String get number => throw _privateConstructorUsedError;
|
||||||
|
String get company => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
$TrainsResultCopyWith<TrainsResult> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $TrainsResultCopyWith<$Res> {
|
||||||
|
factory $TrainsResultCopyWith(
|
||||||
|
TrainsResult value, $Res Function(TrainsResult) then) =
|
||||||
|
_$TrainsResultCopyWithImpl<$Res, TrainsResult>;
|
||||||
|
@useResult
|
||||||
|
$Res call({String rank, String number, String company});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$TrainsResultCopyWithImpl<$Res, $Val extends TrainsResult>
|
||||||
|
implements $TrainsResultCopyWith<$Res> {
|
||||||
|
_$TrainsResultCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? rank = null,
|
||||||
|
Object? number = null,
|
||||||
|
Object? company = null,
|
||||||
|
}) {
|
||||||
|
return _then(_value.copyWith(
|
||||||
|
rank: null == rank
|
||||||
|
? _value.rank
|
||||||
|
: rank // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
number: null == number
|
||||||
|
? _value.number
|
||||||
|
: number // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
company: null == company
|
||||||
|
? _value.company
|
||||||
|
: company // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
) as $Val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$_TrainsResultCopyWith<$Res>
|
||||||
|
implements $TrainsResultCopyWith<$Res> {
|
||||||
|
factory _$$_TrainsResultCopyWith(
|
||||||
|
_$_TrainsResult value, $Res Function(_$_TrainsResult) then) =
|
||||||
|
__$$_TrainsResultCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({String rank, String number, String company});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$_TrainsResultCopyWithImpl<$Res>
|
||||||
|
extends _$TrainsResultCopyWithImpl<$Res, _$_TrainsResult>
|
||||||
|
implements _$$_TrainsResultCopyWith<$Res> {
|
||||||
|
__$$_TrainsResultCopyWithImpl(
|
||||||
|
_$_TrainsResult _value, $Res Function(_$_TrainsResult) _then)
|
||||||
|
: super(_value, _then);
|
||||||
|
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? rank = null,
|
||||||
|
Object? number = null,
|
||||||
|
Object? company = null,
|
||||||
|
}) {
|
||||||
|
return _then(_$_TrainsResult(
|
||||||
|
rank: null == rank
|
||||||
|
? _value.rank
|
||||||
|
: rank // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
number: null == number
|
||||||
|
? _value.number
|
||||||
|
: number // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
company: null == company
|
||||||
|
? _value.company
|
||||||
|
: company // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$_TrainsResult implements _TrainsResult {
|
||||||
|
const _$_TrainsResult(
|
||||||
|
{required this.rank, required this.number, required this.company});
|
||||||
|
|
||||||
|
factory _$_TrainsResult.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$_TrainsResultFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String rank;
|
||||||
|
@override
|
||||||
|
final String number;
|
||||||
|
@override
|
||||||
|
final String company;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'TrainsResult(rank: $rank, number: $number, company: $company)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(dynamic other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$_TrainsResult &&
|
||||||
|
(identical(other.rank, rank) || other.rank == rank) &&
|
||||||
|
(identical(other.number, number) || other.number == number) &&
|
||||||
|
(identical(other.company, company) || other.company == company));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, rank, number, company);
|
||||||
|
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$_TrainsResultCopyWith<_$_TrainsResult> get copyWith =>
|
||||||
|
__$$_TrainsResultCopyWithImpl<_$_TrainsResult>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$_TrainsResultToJson(
|
||||||
|
this,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _TrainsResult implements TrainsResult {
|
||||||
|
const factory _TrainsResult(
|
||||||
|
{required final String rank,
|
||||||
|
required final String number,
|
||||||
|
required final String company}) = _$_TrainsResult;
|
||||||
|
|
||||||
|
factory _TrainsResult.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$_TrainsResult.fromJson;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get rank;
|
||||||
|
@override
|
||||||
|
String get number;
|
||||||
|
@override
|
||||||
|
String get company;
|
||||||
|
@override
|
||||||
|
@JsonKey(ignore: true)
|
||||||
|
_$$_TrainsResultCopyWith<_$_TrainsResult> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
21
lib/models/trains_result.g.dart
Normal file
21
lib/models/trains_result.g.dart
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'trains_result.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$_TrainsResult _$$_TrainsResultFromJson(Map<String, dynamic> json) =>
|
||||||
|
_$_TrainsResult(
|
||||||
|
rank: json['rank'] as String,
|
||||||
|
number: json['number'] as String,
|
||||||
|
company: json['company'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$_TrainsResultToJson(_$_TrainsResult instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'rank': instance.rank,
|
||||||
|
'number': instance.number,
|
||||||
|
'company': instance.company,
|
||||||
|
};
|
|
@ -1,6 +1,15 @@
|
||||||
enum UiDesign {
|
enum UiDesign {
|
||||||
MATERIAL,
|
MATERIAL,
|
||||||
CUPERTINO
|
CUPERTINO,
|
||||||
|
FLUENT,
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UIName on UiDesign {
|
||||||
|
String get userInterfaceName => (const {
|
||||||
|
UiDesign.MATERIAL: 'Material',
|
||||||
|
UiDesign.CUPERTINO: 'Cupertino',
|
||||||
|
UiDesign.FLUENT: 'Fluent',
|
||||||
|
})[this]!;
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnmatchedUiDesignException implements Exception {
|
class UnmatchedUiDesignException implements Exception {
|
||||||
|
|
94
lib/models/ui_timezone.dart
Normal file
94
lib/models/ui_timezone.dart
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import 'package:timezone/timezone.dart' as tz;
|
||||||
|
|
||||||
|
enum UiTimeZoneType {
|
||||||
|
ro,
|
||||||
|
local,
|
||||||
|
utc,
|
||||||
|
iana,
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UITimeZoneTypeName on UiTimeZoneType {
|
||||||
|
String get userInterfaceName => (const {
|
||||||
|
UiTimeZoneType.iana: 'Fus orar IANA',
|
||||||
|
UiTimeZoneType.local: 'Local',
|
||||||
|
UiTimeZoneType.ro: 'România',
|
||||||
|
UiTimeZoneType.utc: 'UTC',
|
||||||
|
})[this]!;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Map<UiTimeZoneType, UiTimeZone Function(String)> fromSerStringConstructors = {
|
||||||
|
UiTimeZoneType.ro: RoUiTimeZone.fromSerString,
|
||||||
|
UiTimeZoneType.local: LocalUiTimeZone.fromSerString,
|
||||||
|
UiTimeZoneType.utc: UtcUiTimeZone.fromSerString,
|
||||||
|
UiTimeZoneType.iana: IanaUiTimeZone.fromSerString,
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract class UiTimeZone {
|
||||||
|
final UiTimeZoneType type;
|
||||||
|
|
||||||
|
const UiTimeZone({required this.type});
|
||||||
|
|
||||||
|
DateTime convertDateTime(DateTime dt);
|
||||||
|
|
||||||
|
factory UiTimeZone.fromSerString(String ser) {
|
||||||
|
final arr = ser.split('\n');
|
||||||
|
return fromSerStringConstructors.map((key, value) => MapEntry(key.name, value))[arr[0]]!(ser);
|
||||||
|
}
|
||||||
|
|
||||||
|
String toSerString() {
|
||||||
|
return '${type.name}\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RoUiTimeZone extends UiTimeZone {
|
||||||
|
static final roTz = tz.getLocation('Europe/Bucharest');
|
||||||
|
|
||||||
|
const RoUiTimeZone() : super(type: UiTimeZoneType.ro);
|
||||||
|
|
||||||
|
factory RoUiTimeZone.fromSerString(String ser) => const RoUiTimeZone();
|
||||||
|
|
||||||
|
@override
|
||||||
|
DateTime convertDateTime(DateTime dt) {
|
||||||
|
return tz.TZDateTime.from(dt, roTz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocalUiTimeZone extends UiTimeZone {
|
||||||
|
const LocalUiTimeZone() : super(type: UiTimeZoneType.local);
|
||||||
|
|
||||||
|
factory LocalUiTimeZone.fromSerString(String ser) => LocalUiTimeZone();
|
||||||
|
|
||||||
|
@override
|
||||||
|
DateTime convertDateTime(DateTime dt) => dt.toLocal();
|
||||||
|
}
|
||||||
|
|
||||||
|
class UtcUiTimeZone extends UiTimeZone {
|
||||||
|
const UtcUiTimeZone() : super(type: UiTimeZoneType.utc);
|
||||||
|
|
||||||
|
factory UtcUiTimeZone.fromSerString(String ser) => UtcUiTimeZone();
|
||||||
|
|
||||||
|
@override
|
||||||
|
DateTime convertDateTime(DateTime dt) => dt.toUtc();
|
||||||
|
}
|
||||||
|
|
||||||
|
class IanaUiTimeZone extends UiTimeZone {
|
||||||
|
late final tz.Location location;
|
||||||
|
|
||||||
|
IanaUiTimeZone({required String ianaName}): super(type: UiTimeZoneType.iana) {
|
||||||
|
location = tz.getLocation(ianaName);
|
||||||
|
}
|
||||||
|
|
||||||
|
factory IanaUiTimeZone.fromSerString(String ser) => IanaUiTimeZone(
|
||||||
|
ianaName: ser.split('\n').skip(1).join('\n'),
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
DateTime convertDateTime(DateTime dt) {
|
||||||
|
return tz.TZDateTime.from(dt, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toSerString() {
|
||||||
|
return '${type.name}\n${location.name}';
|
||||||
|
}
|
||||||
|
}
|
80
lib/pages/about/about_page.dart
Normal file
80
lib/pages/about/about_page.dart
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/api/releases.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/pages/about/about_page_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/about/about_page_fluent.dart';
|
||||||
|
import 'package:info_tren/pages/about/about_page_material.dart';
|
||||||
|
import 'package:info_tren/providers.dart';
|
||||||
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
|
||||||
|
class AboutPage extends ConsumerWidget {
|
||||||
|
const AboutPage({super.key});
|
||||||
|
|
||||||
|
static String routeName = '/about';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
|
|
||||||
|
switch (uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
return const AboutPageMaterial();
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
return const AboutPageCupertino();
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return const AboutPageFluent();
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AboutPageShared extends StatefulWidget {
|
||||||
|
const AboutPageShared({super.key});
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AboutPageState<T extends AboutPageShared> extends State<T> {
|
||||||
|
static const String download = String.fromEnvironment('DOWNLOAD');
|
||||||
|
|
||||||
|
final String pageTitle = 'Despre aplicație';
|
||||||
|
final String versionTitleText = 'Versiunea aplicației';
|
||||||
|
final String latestVersionText = 'Cea mai recentă versiune';
|
||||||
|
final String currentVersionText = 'Versiunea curentă';
|
||||||
|
|
||||||
|
List<ChangelogEntry> localChangelog = [];
|
||||||
|
List<ChangelogEntry> remoteChangelog = [];
|
||||||
|
List<ChangelogEntry> get mergedChangelogs {
|
||||||
|
final logs = remoteChangelog.toList();
|
||||||
|
final versions = logs.map((log) => log.version).toSet();
|
||||||
|
for (final log in localChangelog) {
|
||||||
|
if (!versions.contains(log.version)) {
|
||||||
|
logs.add(log);
|
||||||
|
versions.add(log.version);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logs.sort((l1, l2) => l2.version.compareTo(l1.version));
|
||||||
|
return logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
PackageInfo? packageInfo;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
PackageInfo.fromPlatform().then((value) => setState(() {
|
||||||
|
packageInfo = value;
|
||||||
|
}));
|
||||||
|
|
||||||
|
DefaultAssetBundle.of(context).loadString('CHANGELOG.txt').then((value) {
|
||||||
|
setState(() {
|
||||||
|
localChangelog = ChangelogEntry.fromTextFile(value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
getRemoteReleases().then((value) => setState(() {
|
||||||
|
remoteChangelog = value;
|
||||||
|
}));
|
||||||
|
|
||||||
|
super.didChangeDependencies();
|
||||||
|
}
|
||||||
|
}
|
137
lib/pages/about/about_page_cupertino.dart
Normal file
137
lib/pages/about/about_page_cupertino.dart
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:info_tren/components/cupertino_divider.dart';
|
||||||
|
import 'package:info_tren/pages/about/about_page.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class AboutPageCupertino extends AboutPageShared {
|
||||||
|
const AboutPageCupertino({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AboutPageShared> createState() => AboutPageStateCupertino();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AboutPageStateCupertino extends AboutPageState<AboutPageCupertino> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CupertinoPageScaffold(
|
||||||
|
navigationBar: CupertinoNavigationBar(
|
||||||
|
middle: Text(pageTitle),
|
||||||
|
),
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final topPadding = MediaQuery.of(context).padding.top;
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: topPadding,
|
||||||
|
),
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
|
'Info Tren',
|
||||||
|
style: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (packageInfo != null)
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
|
packageInfo!.packageName,
|
||||||
|
style: const TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||||
|
child: CupertinoDivider(),
|
||||||
|
),
|
||||||
|
for (final log in mergedChangelogs) ...[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
log.version.toString(),
|
||||||
|
style: const TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontSize: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (localChangelog.isNotEmpty && log.version == localChangelog.first.version)
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: CupertinoTheme.of(context).textTheme.textStyle.color ?? CupertinoColors.inactiveGray,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
currentVersionText,
|
||||||
|
style: const TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (remoteChangelog.isNotEmpty && log.version == remoteChangelog.first.version && (localChangelog.isEmpty || localChangelog.first.version != log.version))
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: CupertinoColors.activeGreen,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
latestVersionText,
|
||||||
|
style: const TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: CupertinoColors.activeGreen,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (AboutPageState.download == 'apk' && log.apkLink != null)
|
||||||
|
CupertinoButton(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
minSize: 0,
|
||||||
|
onPressed: () {
|
||||||
|
launchUrl(
|
||||||
|
log.apkLink!,
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: const Icon(CupertinoIcons.arrow_down_circle),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: log.description,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const CupertinoDivider(),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
198
lib/pages/about/about_page_fluent.dart
Normal file
198
lib/pages/about/about_page_fluent.dart
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:info_tren/pages/about/about_page.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class AboutPageFluent extends AboutPageShared {
|
||||||
|
const AboutPageFluent({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AboutPageShared> createState() => AboutPageStateFluent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AboutPageStateFluent extends AboutPageState<AboutPageFluent> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return NavigationView(
|
||||||
|
appBar: NavigationAppBar(
|
||||||
|
title: Text(pageTitle),
|
||||||
|
),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
|
'Info Tren',
|
||||||
|
style: FluentTheme.of(context).typography.display,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (packageInfo != null)
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
|
packageInfo!.packageName,
|
||||||
|
style: FluentTheme.of(context).typography.caption,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// ListTile(
|
||||||
|
// title: Text(versionTitleText),
|
||||||
|
// subtitle: localChangelog.isEmpty ? null : Text(localChangelog.first.title),
|
||||||
|
// ),
|
||||||
|
const Divider(),
|
||||||
|
for (final log in mergedChangelogs) ...[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
log.version.toString(),
|
||||||
|
style: FluentTheme.of(context).typography.title,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (localChangelog.isNotEmpty && log.version == localChangelog.first.version)
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: FluentTheme.of(context).inactiveColor,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
currentVersionText,
|
||||||
|
style: const TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (remoteChangelog.isNotEmpty && log.version == remoteChangelog.first.version && (localChangelog.isEmpty || localChangelog.first.version != log.version))
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.green,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
latestVersionText,
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (AboutPageState.download == 'apk' && log.apkLink != null)
|
||||||
|
GestureDetector(
|
||||||
|
onSecondaryTap: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: log.apkLink!.toString()));
|
||||||
|
// ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
// content: Text('Link copied to clipboard'),
|
||||||
|
// ));
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: log.apkLink!.toString()));
|
||||||
|
// ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
// content: Text('Link copied to clipboard'),
|
||||||
|
// ));
|
||||||
|
},
|
||||||
|
onTap: () {
|
||||||
|
launchUrl(
|
||||||
|
log.apkLink!,
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
child: const Tooltip(
|
||||||
|
message: 'Download APK',
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
child: Icon(FluentIcons.download),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (AboutPageState.download == 'linux' && log.linuxLink != null)
|
||||||
|
GestureDetector(
|
||||||
|
onSecondaryTap: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: log.linuxLink!.toString()));
|
||||||
|
// ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
// content: Text('Link copied to clipboard'),
|
||||||
|
// ));
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: log.linuxLink!.toString()));
|
||||||
|
// ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
// content: Text('Link copied to clipboard'),
|
||||||
|
// ));
|
||||||
|
},
|
||||||
|
onTap: () {
|
||||||
|
launchUrl(
|
||||||
|
log.linuxLink!,
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
child: const Tooltip(
|
||||||
|
message: 'Download Linux ZIP',
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
child: Icon(FluentIcons.download),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (AboutPageState.download == 'windows' && log.windowsLink != null)
|
||||||
|
GestureDetector(
|
||||||
|
onSecondaryTap: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: log.windowsLink!.toString()));
|
||||||
|
// ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
// content: Text('Link copied to clipboard'),
|
||||||
|
// ));
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: log.windowsLink!.toString()));
|
||||||
|
// ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
// content: Text('Link copied to clipboard'),
|
||||||
|
// ));
|
||||||
|
},
|
||||||
|
onTap: () {
|
||||||
|
launchUrl(
|
||||||
|
log.windowsLink!,
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
child: const Tooltip(
|
||||||
|
message: 'Download Windows App ZIP',
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
child: Icon(FluentIcons.download),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: log.description,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
199
lib/pages/about/about_page_material.dart
Normal file
199
lib/pages/about/about_page_material.dart
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:info_tren/pages/about/about_page.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class AboutPageMaterial extends AboutPageShared {
|
||||||
|
const AboutPageMaterial({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AboutPageShared> createState() => AboutPageStateMaterial();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AboutPageStateMaterial extends AboutPageState<AboutPageMaterial> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(pageTitle),
|
||||||
|
centerTitle: true,
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
|
'Info Tren',
|
||||||
|
style: Theme.of(context).textTheme.displayMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (packageInfo != null)
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
|
packageInfo!.packageName,
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// ListTile(
|
||||||
|
// title: Text(versionTitleText),
|
||||||
|
// subtitle: localChangelog.isEmpty ? null : Text(localChangelog.first.title),
|
||||||
|
// ),
|
||||||
|
const Divider(),
|
||||||
|
for (final log in mergedChangelogs) ...[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
log.version.toString(),
|
||||||
|
style: Theme.of(context).textTheme.headlineMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (localChangelog.isNotEmpty && log.version == localChangelog.first.version)
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: Theme.of(context).colorScheme.onBackground,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
currentVersionText,
|
||||||
|
style: const TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (remoteChangelog.isNotEmpty && log.version == remoteChangelog.first.version && (localChangelog.isEmpty || localChangelog.first.version != log.version))
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.green,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
latestVersionText,
|
||||||
|
style: const TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (AboutPageState.download == 'apk' && log.apkLink != null)
|
||||||
|
GestureDetector(
|
||||||
|
onSecondaryTap: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: log.apkLink!.toString()));
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
content: Text('Link copied to clipboard'),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: log.apkLink!.toString()));
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
content: Text('Link copied to clipboard'),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
onTap: () {
|
||||||
|
launchUrl(
|
||||||
|
log.apkLink!,
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
child: const Tooltip(
|
||||||
|
message: 'Download APK',
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
child: Icon(Icons.download),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (AboutPageState.download == 'linux' && log.linuxLink != null)
|
||||||
|
GestureDetector(
|
||||||
|
onSecondaryTap: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: log.linuxLink!.toString()));
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
content: Text('Link copied to clipboard'),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: log.linuxLink!.toString()));
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
content: Text('Link copied to clipboard'),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
onTap: () {
|
||||||
|
launchUrl(
|
||||||
|
log.linuxLink!,
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
child: const Tooltip(
|
||||||
|
message: 'Download Linux ZIP',
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
child: Icon(Icons.download),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (AboutPageState.download == 'windows' && log.windowsLink != null)
|
||||||
|
GestureDetector(
|
||||||
|
onSecondaryTap: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: log.windowsLink!.toString()));
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
content: Text('Link copied to clipboard'),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
Clipboard.setData(ClipboardData(text: log.windowsLink!.toString()));
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||||
|
content: Text('Link copied to clipboard'),
|
||||||
|
));
|
||||||
|
},
|
||||||
|
onTap: () {
|
||||||
|
launchUrl(
|
||||||
|
log.windowsLink!,
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
child: const Tooltip(
|
||||||
|
message: 'Download Windows App ZIP',
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(4),
|
||||||
|
child: Icon(Icons.download),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: log.description,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +1,29 @@
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:info_tren/models/ui_design.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/pages/about/about_page.dart';
|
||||||
import 'package:info_tren/pages/main/main_page_cupertino.dart';
|
import 'package:info_tren/pages/main/main_page_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/main/main_page_fluent.dart';
|
||||||
import 'package:info_tren/pages/main/main_page_material.dart';
|
import 'package:info_tren/pages/main/main_page_material.dart';
|
||||||
|
import 'package:info_tren/pages/settings/setings_page.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/select_train/select_train.dart';
|
import 'package:info_tren/pages/train_info_page/select_train/select_train.dart';
|
||||||
import 'package:info_tren/utils/default_ui_design.dart';
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
class MainPage extends StatelessWidget {
|
class MainPage extends ConsumerWidget {
|
||||||
final UiDesign? uiDesign;
|
const MainPage({super.key,});
|
||||||
|
|
||||||
const MainPage({ Key? key, this.uiDesign }) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
|
|
||||||
switch (uiDesign) {
|
switch (uiDesign) {
|
||||||
case UiDesign.MATERIAL:
|
case UiDesign.MATERIAL:
|
||||||
return MainPageMaterial();
|
return const MainPageMaterial();
|
||||||
case UiDesign.CUPERTINO:
|
case UiDesign.CUPERTINO:
|
||||||
return MainPageCupertino();
|
return const MainPageCupertino();
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return const MainPageFluent();
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
|
@ -28,22 +32,43 @@ class MainPage extends StatelessWidget {
|
||||||
|
|
||||||
abstract class MainPageShared extends StatelessWidget {
|
abstract class MainPageShared extends StatelessWidget {
|
||||||
final String pageTitle = 'Info Tren';
|
final String pageTitle = 'Info Tren';
|
||||||
|
final String moreOptionsText = 'Mai multe opțiuni';
|
||||||
|
|
||||||
List<MainPageOption> get options => [
|
const MainPageShared({super.key});
|
||||||
MainPageOption(
|
|
||||||
|
List<MainPageAction> get popupMenu => [
|
||||||
|
MainPageAction(
|
||||||
|
name: 'Setări',
|
||||||
|
action: (context) {
|
||||||
|
Navigator.of(context).pushNamed(SettingsPage.routeName);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
MainPageAction(
|
||||||
|
name: 'Despre aplicație',
|
||||||
|
action: (context) {
|
||||||
|
Navigator.of(context).pushNamed(AboutPage.routeName);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
List<MainPageAction> get options => [
|
||||||
|
MainPageAction(
|
||||||
name: 'Informații despre tren',
|
name: 'Informații despre tren',
|
||||||
action: (BuildContext context) {
|
description: 'Află informații despre parcursul unui anumit tren',
|
||||||
|
action: (context) {
|
||||||
onTrainInfoPageInvoke(context);
|
onTrainInfoPageInvoke(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
MainPageOption(
|
MainPageAction(
|
||||||
name: 'Tabelă plecari/sosiri',
|
name: 'Tabelă plecari/sosiri',
|
||||||
|
description: 'Vezi trenurile care pleacă și sosesc dintr-o gară',
|
||||||
action: (context) {
|
action: (context) {
|
||||||
onStationBoardPageInvoke(context);
|
onStationBoardPageInvoke(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
MainPageOption(
|
MainPageAction(
|
||||||
name: 'Planificare rută',
|
name: 'Planificare rută',
|
||||||
|
description: 'Găsește trenurile disponibile pentru călătoria între două gări',
|
||||||
// TODO: Implement route planning
|
// TODO: Implement route planning
|
||||||
action: null,
|
action: null,
|
||||||
),
|
),
|
||||||
|
@ -62,9 +87,14 @@ abstract class MainPageShared extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MainPageOption {
|
class MainPageAction {
|
||||||
final String name;
|
final String name;
|
||||||
|
final String? description;
|
||||||
final void Function(BuildContext context)? action;
|
final void Function(BuildContext context)? action;
|
||||||
|
|
||||||
MainPageOption({required this.name, this.action});
|
MainPageAction({
|
||||||
|
required this.name,
|
||||||
|
this.action,
|
||||||
|
this.description,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,64 @@ import 'package:flutter/cupertino.dart';
|
||||||
import 'package:info_tren/pages/main/main_page.dart';
|
import 'package:info_tren/pages/main/main_page.dart';
|
||||||
|
|
||||||
class MainPageCupertino extends MainPageShared {
|
class MainPageCupertino extends MainPageShared {
|
||||||
|
const MainPageCupertino({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CupertinoPageScaffold(
|
return CupertinoPageScaffold(
|
||||||
navigationBar: CupertinoNavigationBar(
|
navigationBar: CupertinoNavigationBar(
|
||||||
middle: Text(pageTitle),
|
middle: Text(pageTitle),
|
||||||
|
trailing: CupertinoButton(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
onPressed: () {
|
||||||
|
showCupertinoModalPopup(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return CupertinoActionSheet(
|
||||||
|
actions: popupMenu.map((m) => CupertinoActionSheetAction(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
m.action?.call(context);
|
||||||
|
},
|
||||||
|
child: Text(m.name),
|
||||||
|
)).toList(),
|
||||||
|
cancelButton: CupertinoActionSheetAction(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: const Text('Anulare'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: const Icon(CupertinoIcons.ellipsis_circle),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: options.map((option) => CupertinoButton.filled(
|
children: options.map((option) => CupertinoButton.filled(
|
||||||
child: Text(option.name),
|
|
||||||
onPressed: option.action == null ? null : () => option.action!(context),
|
onPressed: option.action == null ? null : () => option.action!(context),
|
||||||
|
child: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(text: option.name),
|
||||||
|
if (option.description != null) ...[
|
||||||
|
const TextSpan(text: '\n'),
|
||||||
|
TextSpan(
|
||||||
|
text: option.description,
|
||||||
|
style: const TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
)).map((w) => Padding(
|
)).map((w) => Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(4, 2, 4, 2),
|
padding: const EdgeInsets.fromLTRB(4, 2, 4, 2),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
|
|
89
lib/pages/main/main_page_fluent.dart
Normal file
89
lib/pages/main/main_page_fluent.dart
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:info_tren/pages/main/main_page.dart';
|
||||||
|
|
||||||
|
class MainPageFluent extends MainPageShared {
|
||||||
|
const MainPageFluent({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return NavigationView(
|
||||||
|
appBar: NavigationAppBar(
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
title: Text(pageTitle),
|
||||||
|
actions: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: popupMenu.map((i) => Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 32,
|
||||||
|
height: 32,
|
||||||
|
child: IconButton(
|
||||||
|
icon: Icon({
|
||||||
|
'Setări': FluentIcons.settings,
|
||||||
|
'Despre aplicație': FluentIcons.info,
|
||||||
|
}[i.name]),
|
||||||
|
onPressed: i.action != null ? () => i.action!(context) : null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)).toList(),
|
||||||
|
),
|
||||||
|
// centerTitle: true,
|
||||||
|
// actions: [
|
||||||
|
// PopupMenuButton<int>(
|
||||||
|
// icon: const Icon(Icons.more_vert),
|
||||||
|
// tooltip: moreOptionsText,
|
||||||
|
// itemBuilder: (_) => popupMenu.asMap().entries.map((e) => PopupMenuItem(
|
||||||
|
// value: e.key,
|
||||||
|
// child: Text(e.value.name),
|
||||||
|
// )).toList(),
|
||||||
|
// onSelected: (index) {
|
||||||
|
// popupMenu[index].action?.call(context);
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
),
|
||||||
|
content: SafeArea(
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: options.map((option) => HoverButton(
|
||||||
|
onPressed: option.action != null ? () => option.action!(context) : null,
|
||||||
|
builder: (context, states) {
|
||||||
|
return Card(
|
||||||
|
backgroundColor: option.action != null ? (states.isHovering ? FluentTheme.of(context).accentColor.dark : FluentTheme.of(context).accentColor) : null,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
option.name,
|
||||||
|
style: FluentTheme.of(context)
|
||||||
|
.typography
|
||||||
|
.bodyLarge
|
||||||
|
?.copyWith(
|
||||||
|
color:
|
||||||
|
FluentTheme.of(context).activeColor,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(option.description!),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)).map((w) => Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(4, 2, 4, 2),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: w,
|
||||||
|
),
|
||||||
|
)).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,23 +2,55 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:info_tren/pages/main/main_page.dart';
|
import 'package:info_tren/pages/main/main_page.dart';
|
||||||
|
|
||||||
class MainPageMaterial extends MainPageShared {
|
class MainPageMaterial extends MainPageShared {
|
||||||
|
const MainPageMaterial({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(pageTitle),
|
title: Text(pageTitle),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
|
actions: [
|
||||||
|
PopupMenuButton<int>(
|
||||||
|
icon: const Icon(Icons.more_vert),
|
||||||
|
tooltip: moreOptionsText,
|
||||||
|
itemBuilder: (_) => popupMenu.asMap().entries.map((e) => PopupMenuItem(
|
||||||
|
value: e.key,
|
||||||
|
child: Text(e.value.name),
|
||||||
|
)).toList(),
|
||||||
|
onSelected: (index) {
|
||||||
|
popupMenu[index].action?.call(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: options.map((option) => ElevatedButton(
|
children: options.map((option) => Card(
|
||||||
child: Text(
|
color: option.action != null ? Theme.of(context).colorScheme.secondaryContainer : null,
|
||||||
option.name,
|
child: InkWell(
|
||||||
style: Theme.of(context).textTheme.button?.copyWith(fontSize: 18),
|
onTap: option.action != null ? () => option.action!(context) : null,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
option.name,
|
||||||
|
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.onSecondaryContainer,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(option.description!),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
onPressed: option.action != null ? () => option.action!(context) : null,
|
|
||||||
)).map((w) => Padding(
|
)).map((w) => Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(4, 2, 4, 2),
|
padding: const EdgeInsets.fromLTRB(4, 2, 4, 2),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
|
|
38
lib/pages/settings/setings_page.dart
Normal file
38
lib/pages/settings/setings_page.dart
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/pages/settings/settings_page_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/settings/settings_page_fluent.dart';
|
||||||
|
import 'package:info_tren/pages/settings/settings_page_material.dart';
|
||||||
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
|
class SettingsPage extends ConsumerWidget {
|
||||||
|
const SettingsPage({super.key,});
|
||||||
|
|
||||||
|
static const String routeName = '/settings';
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
|
|
||||||
|
switch (uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
return const SettingsPageMaterial();
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
return const SettingsPageCupertino();
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return const SettingsPageFluent();
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class SettingsPageShared extends StatelessWidget {
|
||||||
|
final String pageTitle = 'Setări';
|
||||||
|
final String appearanceTitle = 'Aspect';
|
||||||
|
final String timeZoneTitle = 'Fus orar';
|
||||||
|
|
||||||
|
const SettingsPageShared({super.key});
|
||||||
|
|
||||||
|
}
|
96
lib/pages/settings/settings_page_cupertino.dart
Normal file
96
lib/pages/settings/settings_page_cupertino.dart
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/pages/settings/setings_page.dart';
|
||||||
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
|
class SettingsPageCupertino extends SettingsPageShared {
|
||||||
|
const SettingsPageCupertino({super.key,});
|
||||||
|
|
||||||
|
Future<T?> singleChoice<T>({required BuildContext context, required List<T> choices, required String Function(T) labelBuilder, String? title}) async {
|
||||||
|
return await showCupertinoModalPopup<T>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return CupertinoActionSheet(
|
||||||
|
title: title != null ? Text(title) : null,
|
||||||
|
actions: choices.map((c) => CupertinoActionSheetAction(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop(c);
|
||||||
|
},
|
||||||
|
child: Text(labelBuilder(c)),
|
||||||
|
)).toList(),
|
||||||
|
cancelButton: CupertinoActionSheetAction(
|
||||||
|
child: const Text('Anulare'),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CupertinoPageScaffold(
|
||||||
|
navigationBar: CupertinoNavigationBar(
|
||||||
|
previousPageTitle: 'Info Tren',
|
||||||
|
middle: Text(pageTitle),
|
||||||
|
),
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final mq = MediaQuery.of(context);
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: mq.padding.top,
|
||||||
|
),
|
||||||
|
Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final currentUiDesign = ref.watch(uiDesignProvider);
|
||||||
|
return CupertinoListTile(
|
||||||
|
title: Text(appearanceTitle),
|
||||||
|
trailing: Text(currentUiDesign.userInterfaceName),
|
||||||
|
onTap: () async {
|
||||||
|
final choice = await singleChoice(
|
||||||
|
context: context,
|
||||||
|
choices: UiDesign.values,
|
||||||
|
labelBuilder: (UiDesign ud) => ud.userInterfaceName,
|
||||||
|
title: appearanceTitle,
|
||||||
|
);
|
||||||
|
if (choice != null) {
|
||||||
|
ref.read(uiDesignProvider.notifier).set(choice);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final currentTZ = ref.watch(uiTimeZoneProvider);
|
||||||
|
return CupertinoListTile(
|
||||||
|
title: Text(timeZoneTitle),
|
||||||
|
trailing: Text(currentTZ.type.userInterfaceName),
|
||||||
|
onTap: () async {
|
||||||
|
final choice = await singleChoice(
|
||||||
|
context: context,
|
||||||
|
choices: UiTimeZoneType.values.where((tz) => tz != UiTimeZoneType.iana).toList(),
|
||||||
|
labelBuilder: (UiTimeZoneType utzt) => utzt.userInterfaceName,
|
||||||
|
title: timeZoneTitle,
|
||||||
|
);
|
||||||
|
if (choice != null) {
|
||||||
|
ref.read(uiTimeZoneProvider.notifier).set(UiTimeZone.fromSerString('${choice.name}\n'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
65
lib/pages/settings/settings_page_fluent.dart
Normal file
65
lib/pages/settings/settings_page_fluent.dart
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/pages/settings/setings_page.dart';
|
||||||
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
|
class SettingsPageFluent extends SettingsPageShared {
|
||||||
|
const SettingsPageFluent({super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return NavigationView(
|
||||||
|
appBar: NavigationAppBar(
|
||||||
|
title: Text(pageTitle),
|
||||||
|
),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final currentUiDesign = ref.watch(uiDesignProvider);
|
||||||
|
return ListTile(
|
||||||
|
title: Text(appearanceTitle),
|
||||||
|
trailing: ComboBox<UiDesign>(
|
||||||
|
items: UiDesign.values.map((d) => ComboBoxItem(
|
||||||
|
value: d,
|
||||||
|
child: Text(d.userInterfaceName),
|
||||||
|
)).toList(),
|
||||||
|
value: currentUiDesign,
|
||||||
|
onChanged: (newUiDesign) {
|
||||||
|
ref.read(uiDesignProvider.notifier).set(newUiDesign);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final currentTZ = ref.watch(uiTimeZoneProvider);
|
||||||
|
return ListTile(
|
||||||
|
title: Text(timeZoneTitle),
|
||||||
|
trailing: ComboBox<UiTimeZoneType>(
|
||||||
|
items: UiTimeZoneType.values.where((tz) => tz != UiTimeZoneType.iana).map((tzt) => ComboBoxItem(
|
||||||
|
value: tzt,
|
||||||
|
child: Text(tzt.userInterfaceName),
|
||||||
|
)).toList(),
|
||||||
|
value: currentTZ.type,
|
||||||
|
onChanged: (newTZ) {
|
||||||
|
if (newTZ != null) {
|
||||||
|
ref.read(uiTimeZoneProvider.notifier).set(UiTimeZone.fromSerString('${newTZ.name}\n'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ref.read(uiTimeZoneProvider.notifier).set(null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
66
lib/pages/settings/settings_page_material.dart
Normal file
66
lib/pages/settings/settings_page_material.dart
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/pages/settings/setings_page.dart';
|
||||||
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
|
class SettingsPageMaterial extends SettingsPageShared {
|
||||||
|
const SettingsPageMaterial({super.key,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(pageTitle),
|
||||||
|
centerTitle: true,
|
||||||
|
),
|
||||||
|
body: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final currentUiDesign = ref.watch(uiDesignProvider);
|
||||||
|
return ListTile(
|
||||||
|
title: Text(appearanceTitle),
|
||||||
|
trailing: DropdownButton<UiDesign>(
|
||||||
|
items: UiDesign.values.map((d) => DropdownMenuItem(
|
||||||
|
value: d,
|
||||||
|
child: Text(d.userInterfaceName),
|
||||||
|
)).toList(),
|
||||||
|
value: currentUiDesign,
|
||||||
|
onChanged: (newUiDesign) {
|
||||||
|
ref.read(uiDesignProvider.notifier).set(newUiDesign);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final currentTZ = ref.watch(uiTimeZoneProvider);
|
||||||
|
return ListTile(
|
||||||
|
title: Text(timeZoneTitle),
|
||||||
|
trailing: DropdownButton<UiTimeZoneType>(
|
||||||
|
items: UiTimeZoneType.values.where((tz) => tz != UiTimeZoneType.iana).map((tzt) => DropdownMenuItem(
|
||||||
|
value: tzt,
|
||||||
|
child: Text(tzt.userInterfaceName),
|
||||||
|
)).toList(),
|
||||||
|
value: currentTZ.type,
|
||||||
|
onChanged: (newTZ) {
|
||||||
|
if (newTZ != null) {
|
||||||
|
ref.read(uiTimeZoneProvider.notifier).set(UiTimeZone.fromSerString('${newTZ.name}\n'));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ref.read(uiTimeZoneProvider.notifier).set(null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,31 +1,39 @@
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:info_tren/models/ui_design.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station_cupertino.dart';
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station_fluent.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station_material.dart';
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station_material.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
||||||
import 'package:info_tren/utils/default_ui_design.dart';
|
import 'package:info_tren/providers.dart';
|
||||||
import 'package:info_tren/api/stations.dart' as apiStations;
|
import 'package:info_tren/api/stations.dart' as api_stations;
|
||||||
|
|
||||||
class SelectStationPage extends StatefulWidget {
|
class SelectStationPage extends ConsumerWidget {
|
||||||
final UiDesign? uiDesign;
|
const SelectStationPage({ super.key });
|
||||||
|
|
||||||
const SelectStationPage({ Key? key, this.uiDesign }) : super(key: key);
|
|
||||||
|
|
||||||
static String routeName = '/stationArrDep/selectStation';
|
static String routeName = '/stationArrDep/selectStation';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
SelectStationPageState createState() {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
switch (uiDesign) {
|
switch (uiDesign) {
|
||||||
case UiDesign.MATERIAL:
|
case UiDesign.MATERIAL:
|
||||||
return SelectStationPageStateMaterial();
|
return const SelectStationPageMaterial();
|
||||||
case UiDesign.CUPERTINO:
|
case UiDesign.CUPERTINO:
|
||||||
return SelectStationPageStateCupertino();
|
return const SelectStationPageCupertino();
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return const SelectStationPageFluent();
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class SelectStationPageState extends State<SelectStationPage> {
|
abstract class SelectStationPageShared extends StatefulWidget {
|
||||||
|
const SelectStationPageShared({super.key});
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class SelectStationPageState extends State<SelectStationPageShared> {
|
||||||
static const pageTitle = 'Plecări/sosiri stație';
|
static const pageTitle = 'Plecări/sosiri stație';
|
||||||
static const textFieldLabel = 'Numele stației';
|
static const textFieldLabel = 'Numele stației';
|
||||||
static const roToEn = {
|
static const roToEn = {
|
||||||
|
@ -35,6 +43,9 @@ abstract class SelectStationPageState extends State<SelectStationPage> {
|
||||||
'ș': 's',
|
'ș': 's',
|
||||||
'ț': 't',
|
'ț': 't',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
final textEditingController = TextEditingController();
|
||||||
|
|
||||||
List<String> stations = [];
|
List<String> stations = [];
|
||||||
|
|
||||||
List<String> get filteredStations {
|
List<String> get filteredStations {
|
||||||
|
@ -58,7 +69,7 @@ abstract class SelectStationPageState extends State<SelectStationPage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
apiStations.stations.then((value) {
|
api_stations.stations.then((value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
stations = value.map((e) => e.name).toList(growable: false,);
|
stations = value.map((e) => e.name).toList(growable: false,);
|
||||||
});
|
});
|
||||||
|
@ -72,9 +83,10 @@ abstract class SelectStationPageState extends State<SelectStationPage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSuggestionSelected(String suggestion) {
|
void onSuggestionSelected(String suggestion) {
|
||||||
Navigator.of(context).pushNamed(ViewStationPage.routeName, arguments: suggestion);
|
Navigator.of(context).pushNamed(
|
||||||
|
ViewStationPage.routeName,
|
||||||
|
arguments: ViewStationArguments(stationName: suggestion),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final TextEditingController textEditingController = TextEditingController();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,18 @@ import 'package:flutter/cupertino.dart';
|
||||||
import 'package:info_tren/components/cupertino_divider.dart';
|
import 'package:info_tren/components/cupertino_divider.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
||||||
|
|
||||||
|
class SelectStationPageCupertino extends SelectStationPageShared {
|
||||||
|
const SelectStationPageCupertino({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => SelectStationPageStateCupertino();
|
||||||
|
}
|
||||||
|
|
||||||
class SelectStationPageStateCupertino extends SelectStationPageState {
|
class SelectStationPageStateCupertino extends SelectStationPageState {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CupertinoPageScaffold(
|
return CupertinoPageScaffold(
|
||||||
navigationBar: CupertinoNavigationBar(
|
navigationBar: const CupertinoNavigationBar(
|
||||||
middle: Text(SelectStationPageState.pageTitle),
|
middle: Text(SelectStationPageState.pageTitle),
|
||||||
),
|
),
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
|
@ -38,7 +45,7 @@ class SelectStationPageStateCupertino extends SelectStationPageState {
|
||||||
),
|
),
|
||||||
onTap: () => onSuggestionSelected(filteredStations[index]),
|
onTap: () => onSuggestionSelected(filteredStations[index]),
|
||||||
),
|
),
|
||||||
CupertinoDivider(),
|
const CupertinoDivider(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
||||||
|
|
||||||
|
class SelectStationPageFluent extends SelectStationPageShared {
|
||||||
|
const SelectStationPageFluent({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => SelectStationPageStateFluent();
|
||||||
|
}
|
||||||
|
|
||||||
|
class SelectStationPageStateFluent extends SelectStationPageState {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return NavigationView(
|
||||||
|
appBar: const NavigationAppBar(
|
||||||
|
title: Text(SelectStationPageState.pageTitle),
|
||||||
|
// centerTitle: true,
|
||||||
|
),
|
||||||
|
content: SafeArea(
|
||||||
|
bottom: false,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: TextBox(
|
||||||
|
controller: textEditingController,
|
||||||
|
autofocus: true,
|
||||||
|
placeholder: SelectStationPageState.textFieldLabel,
|
||||||
|
textInputAction: TextInputAction.search,
|
||||||
|
onChanged: onTextChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
// dense: true,
|
||||||
|
title: Text(filteredStations[index]),
|
||||||
|
onPressed: () => onSuggestionSelected(filteredStations[index]),
|
||||||
|
),
|
||||||
|
const Divider(
|
||||||
|
size: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: filteredStations.length,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,19 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/select_station/select_station.dart';
|
||||||
|
|
||||||
|
class SelectStationPageMaterial extends SelectStationPageShared {
|
||||||
|
const SelectStationPageMaterial({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => SelectStationPageStateMaterial();
|
||||||
|
}
|
||||||
|
|
||||||
class SelectStationPageStateMaterial extends SelectStationPageState {
|
class SelectStationPageStateMaterial extends SelectStationPageState {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(SelectStationPageState.pageTitle),
|
title: const Text(SelectStationPageState.pageTitle),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
|
@ -20,7 +26,7 @@ class SelectStationPageStateMaterial extends SelectStationPageState {
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: textEditingController,
|
controller: textEditingController,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
decoration: InputDecoration(
|
decoration: const InputDecoration(
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
labelText: SelectStationPageState.textFieldLabel,
|
labelText: SelectStationPageState.textFieldLabel,
|
||||||
),
|
),
|
||||||
|
@ -39,7 +45,7 @@ class SelectStationPageStateMaterial extends SelectStationPageState {
|
||||||
title: Text(filteredStations[index]),
|
title: Text(filteredStations[index]),
|
||||||
onTap: () => onSuggestionSelected(filteredStations[index]),
|
onTap: () => onSuggestionSelected(filteredStations[index]),
|
||||||
),
|
),
|
||||||
Divider(
|
const Divider(
|
||||||
height: 1,
|
height: 1,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,84 +1,100 @@
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:info_tren/api/station_data.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/components/refresh_future_builder.dart';
|
import 'package:info_tren/components/refresh_future_builder.dart';
|
||||||
import 'package:info_tren/models/station_data.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/models/ui_design.dart';
|
|
||||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station_cupertino.dart';
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station_fluent.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station_material.dart';
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station_material.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
||||||
import 'package:info_tren/utils/default_ui_design.dart';
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
class ViewStationPage extends StatefulWidget {
|
class ViewStationPage extends HookConsumerWidget {
|
||||||
final UiDesign? uiDesign;
|
const ViewStationPage({ super.key, });
|
||||||
final String stationName;
|
|
||||||
|
|
||||||
const ViewStationPage({ Key? key, required this.stationName, this.uiDesign }) : super(key: key);
|
|
||||||
|
|
||||||
static String routeName = '/stationArrDep/viewStation';
|
static String routeName = '/stationArrDep/viewStation';
|
||||||
|
|
||||||
|
ValueNotifier<ViewStationPageTab> useTab() => useState(ViewStationPageTab.departures);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ViewStationPageState createState() {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
final tab = useTab();
|
||||||
|
|
||||||
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
switch (uiDesign) {
|
switch (uiDesign) {
|
||||||
case UiDesign.MATERIAL:
|
case UiDesign.MATERIAL:
|
||||||
return ViewStationPageStateMaterial();
|
return ViewStationPageMaterial(
|
||||||
|
tab: tab.value,
|
||||||
|
setTab: (newTab) => tab.value = newTab,
|
||||||
|
);
|
||||||
case UiDesign.CUPERTINO:
|
case UiDesign.CUPERTINO:
|
||||||
return ViewStationPageStateCupertino();
|
return ViewStationPageCupertino(
|
||||||
|
tab: tab.value,
|
||||||
|
setTab: (newTab) => tab.value = newTab,
|
||||||
|
);
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return ViewStationPageFluent(
|
||||||
|
tab: tab.value,
|
||||||
|
setTab: (newTab) => tab.value = newTab,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ViewStationPageState extends State<ViewStationPage> {
|
class ViewStationArguments {
|
||||||
|
final String stationName;
|
||||||
|
final DateTime? date;
|
||||||
|
|
||||||
|
const ViewStationArguments({required this.stationName, this.date});
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class ViewStationPageShared extends StatelessWidget {
|
||||||
static const arrivals = 'Sosiri';
|
static const arrivals = 'Sosiri';
|
||||||
static const departures = 'Pleacări';
|
static const departures = 'Plecări';
|
||||||
static const loadingText = 'Se încarcă...';
|
static const loadingText = 'Se încarcă...';
|
||||||
static const arrivesFrom = 'Sosește de la';
|
static const arrivesFrom = 'Sosește de la';
|
||||||
|
static const arrivedFrom = 'A sosit de la';
|
||||||
|
static const cancelledArrival = 'Anulat - de la';
|
||||||
static const departsTo = 'Pleacă către';
|
static const departsTo = 'Pleacă către';
|
||||||
|
static const departedTo = 'A plecat către';
|
||||||
|
static const cancelledDeparture = 'Anulat - către';
|
||||||
|
static const errorText = 'A apărut o eroare';
|
||||||
|
static const retryText = 'Reîncearcă';
|
||||||
|
|
||||||
ViewStationPageTab tab = ViewStationPageTab.departures;
|
final ViewStationPageTab tab;
|
||||||
late String stationName;
|
final void Function(ViewStationPageTab) setTab;
|
||||||
late Future<StationData> Function() futureCreator;
|
const ViewStationPageShared({required this.tab, required this.setTab, super.key});
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
initData();
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeDependencies() {
|
|
||||||
if (stationName != widget.stationName) {
|
|
||||||
setState(() {
|
|
||||||
initData();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
super.didChangeDependencies();
|
|
||||||
}
|
|
||||||
|
|
||||||
void initData() {
|
|
||||||
stationName = widget.stationName;
|
|
||||||
futureCreator = () => getStationData(stationName);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget buildContent(BuildContext context, Future Function() refresh, Future Function(Future<StationData> Function() newFutureBuilder) _, RefreshFutureBuilderSnapshot<StationData> snapshot);
|
Widget buildContent(BuildContext context, Future Function() refresh, Future Function(Future<StationData> Function() newFutureBuilder) _, RefreshFutureBuilderSnapshot<StationData> snapshot);
|
||||||
Widget buildStationArrivalItem(BuildContext context, StationArrival item);
|
Widget buildStationArrivalItem(BuildContext context, StationArrDep item);
|
||||||
Widget buildStationDepartureItem(BuildContext context, StationDeparture item);
|
Widget buildStationDepartureItem(BuildContext context, StationArrDep item);
|
||||||
|
|
||||||
void onTabChange(int index) {
|
void onTrainTapped(BuildContext context, StationTrain train) {
|
||||||
setState(() {
|
Navigator.of(context).pushNamed(
|
||||||
tab = ViewStationPageTab.values[index];
|
TrainInfo.routeName,
|
||||||
});
|
arguments: TrainInfoArguments(
|
||||||
|
trainNumber: train.number,
|
||||||
|
date: train.departureDate,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onTrainTapped(String trainNumber) {
|
void onTabChange (int index) {
|
||||||
Navigator.of(context).pushNamed(TrainInfo.routeName, arguments: trainNumber);
|
setTab(ViewStationPageTab.values[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return RefreshFutureBuilder(
|
return Consumer(
|
||||||
futureCreator: futureCreator,
|
builder: (context, ref, _) {
|
||||||
builder: buildContent,
|
return RefreshFutureBuilderProviderAdapter(
|
||||||
|
futureProvider: viewStationDataProvider,
|
||||||
|
refresh: () async {
|
||||||
|
ref.invalidate(stationDataProvider);
|
||||||
|
},
|
||||||
|
builder: buildContent,
|
||||||
|
);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,4 +102,4 @@ abstract class ViewStationPageState extends State<ViewStationPage> {
|
||||||
enum ViewStationPageTab {
|
enum ViewStationPageTab {
|
||||||
arrivals,
|
arrivals,
|
||||||
departures,
|
departures,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,37 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/components/loading/loading.dart';
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
import 'package:info_tren/components/refresh_future_builder.dart';
|
import 'package:info_tren/components/refresh_future_builder.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:info_tren/components/sliver_persistent_header_padding.dart';
|
import 'package:info_tren/components/sliver_persistent_header_padding.dart';
|
||||||
import 'package:info_tren/models/station_data.dart';
|
import 'package:info_tren/components/train_id_text_span.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
||||||
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
|
class ViewStationPageCupertino extends ViewStationPageShared {
|
||||||
|
const ViewStationPageCupertino({super.key, required super.tab, required super.setTab});
|
||||||
|
|
||||||
class ViewStationPageStateCupertino extends ViewStationPageState {
|
|
||||||
@override
|
@override
|
||||||
Widget buildContent(BuildContext context, Future Function() refresh, Future Function(Future<StationData> Function()) _, RefreshFutureBuilderSnapshot<StationData> snapshot) {
|
Widget buildContent(BuildContext context, Future Function() refresh, Future Function(Future<StationData> Function()) _, RefreshFutureBuilderSnapshot<StationData> snapshot) {
|
||||||
return CupertinoPageScaffold(
|
return CupertinoPageScaffold(
|
||||||
navigationBar: CupertinoNavigationBar(
|
navigationBar: CupertinoNavigationBar(
|
||||||
middle: Text(snapshot.hasData ? snapshot.data!.stationName : stationName),
|
middle: Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final stationName = ref.watch(viewStationArgumentsProvider.select((value) => value.stationName));
|
||||||
|
return Text(snapshot.hasData ? snapshot.data!.stationName : stationName);
|
||||||
|
}
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: snapshot.hasData ? CupertinoTabScaffold(
|
child: snapshot.hasData ? CupertinoTabScaffold(
|
||||||
tabBar: CupertinoTabBar(
|
tabBar: CupertinoTabBar(
|
||||||
items: [
|
items: const [
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(CupertinoIcons.arrow_down),
|
icon: Icon(CupertinoIcons.arrow_down),
|
||||||
label: ViewStationPageState.arrivals,
|
label: ViewStationPageShared.arrivals,
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(CupertinoIcons.arrow_up),
|
icon: Icon(CupertinoIcons.arrow_up),
|
||||||
label: ViewStationPageState.departures,
|
label: ViewStationPageShared.departures,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
onTap: onTabChange,
|
onTap: onTabChange,
|
||||||
|
@ -48,73 +57,63 @@ class ViewStationPageStateCupertino extends ViewStationPageState {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
) : snapshot.state == RefreshFutureBuilderState.waiting ? Loading(text: ViewStationPageState.loadingText, uiDesign: widget.uiDesign,) : Container(),
|
) : snapshot.state == RefreshFutureBuilderState.waiting ? const Loading(text: ViewStationPageShared.loadingText,) : Container(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildStationArrivalItem(BuildContext context, StationArrival item) {
|
Widget buildStationArrivalItem(BuildContext context, StationArrDep item) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => onTrainTapped(item.train.number),
|
onTap: () => onTrainTapped(context, item.train),
|
||||||
child: CupertinoFormRow(
|
child: CupertinoFormRow(
|
||||||
child: Text('${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}'),
|
|
||||||
prefix: Text.rich(
|
prefix: Text.rich(
|
||||||
TextSpan(
|
trainIdSpan(rank: item.train.rank, number: item.train.number),
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: item.train.rank,
|
|
||||||
style: TextStyle(
|
|
||||||
color: item.train.rank.startsWith('IR') ? Color.fromARGB(255, 255, 0, 0) : null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextSpan(text: ' '),
|
|
||||||
TextSpan(text: item.train.number,),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
helper: Text.rich(
|
helper: Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
children: [
|
children: [
|
||||||
TextSpan(text: ViewStationPageState.arrivesFrom),
|
const TextSpan(text: ViewStationPageShared.arrivesFrom),
|
||||||
TextSpan(text: ' '),
|
const TextSpan(text: ' '),
|
||||||
TextSpan(text: item.train.origin),
|
TextSpan(text: item.train.terminus),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
child: Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final tz = ref.watch(uiTimeZoneProvider);
|
||||||
|
final time = tz.convertDateTime(item.time);
|
||||||
|
return Text('${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}');
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildStationDepartureItem(BuildContext context, StationDeparture item) {
|
Widget buildStationDepartureItem(BuildContext context, StationArrDep item) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => onTrainTapped(item.train.number),
|
onTap: () => onTrainTapped(context, item.train),
|
||||||
child: CupertinoFormRow(
|
child: CupertinoFormRow(
|
||||||
child: Text('${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}'),
|
|
||||||
prefix: Text.rich(
|
prefix: Text.rich(
|
||||||
TextSpan(
|
trainIdSpan(rank: item.train.rank, number: item.train.number),
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: item.train.rank,
|
|
||||||
style: TextStyle(
|
|
||||||
color: item.train.rank.startsWith('IR') ? Color.fromARGB(255, 255, 0, 0) : null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextSpan(text: ' '),
|
|
||||||
TextSpan(text: item.train.number,),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
helper: Text.rich(
|
helper: Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
children: [
|
children: [
|
||||||
TextSpan(text: ViewStationPageState.departsTo),
|
const TextSpan(text: ViewStationPageShared.departsTo),
|
||||||
TextSpan(text: ' '),
|
const TextSpan(text: ' '),
|
||||||
TextSpan(text: item.train.destination),
|
TextSpan(text: item.train.terminus),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
child: Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final tz = ref.watch(uiTimeZoneProvider);
|
||||||
|
final time = tz.convertDateTime(item.time);
|
||||||
|
return Text('${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}');
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,264 @@
|
||||||
|
import 'dart:math';
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/components/badge/badge.dart';
|
||||||
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
|
import 'package:info_tren/components/refresh_future_builder.dart';
|
||||||
|
import 'package:info_tren/components/train_id_text_span.dart';
|
||||||
|
import 'package:info_tren/models.dart';
|
||||||
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
||||||
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
|
class ViewStationPageFluent extends ViewStationPageShared {
|
||||||
|
const ViewStationPageFluent({super.key, required super.tab, required super.setTab});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildContent(BuildContext context, Future Function() refresh, Future Function(Future<StationData> Function()) _, RefreshFutureBuilderSnapshot<StationData> snapshot) {
|
||||||
|
return NavigationView(
|
||||||
|
appBar: NavigationAppBar(
|
||||||
|
title: Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final stationName = ref.watch(viewStationArgumentsProvider.select((value) => value.stationName));
|
||||||
|
return Text(snapshot.hasData ? snapshot.data!.stationName : stationName);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
content: snapshot.state == RefreshFutureBuilderState.waiting || snapshot.state == RefreshFutureBuilderState.refreshError
|
||||||
|
? const Loading(text: ViewStationPageShared.loadingText,)
|
||||||
|
: snapshot.state == RefreshFutureBuilderState.error
|
||||||
|
? Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
FluentIcons.error,
|
||||||
|
size: 32,
|
||||||
|
color: Colors.red.normal,
|
||||||
|
),
|
||||||
|
const Text(
|
||||||
|
ViewStationPageShared.errorText,
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontSize: 32,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
snapshot.error.toString(),
|
||||||
|
style: FluentTheme.of(context).typography.subtitle,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Button(
|
||||||
|
onPressed: () {
|
||||||
|
refresh();
|
||||||
|
},
|
||||||
|
child: const Text(ViewStationPageShared.retryText),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
pane: snapshot.hasData ? NavigationPane(
|
||||||
|
onChanged: onTabChange,
|
||||||
|
selected: tab.index,
|
||||||
|
items: [
|
||||||
|
PaneItem(
|
||||||
|
body: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverToBoxAdapter(child: SafeArea(left: false, bottom: false, right: false,child: Container(),),),
|
||||||
|
SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
return tab == ViewStationPageTab.arrivals ? buildStationArrivalItem(context, snapshot.data!.arrivals![index]) : buildStationDepartureItem(context, snapshot.data!.departures![index]);
|
||||||
|
},
|
||||||
|
childCount: tab == ViewStationPageTab.arrivals ? snapshot.data!.arrivals?.length ?? 0 : snapshot.data!.departures?.length ?? 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
title: const Text(ViewStationPageShared.arrivals),
|
||||||
|
icon: const Icon(FluentIcons.arrow_down_right8),
|
||||||
|
),
|
||||||
|
PaneItem(
|
||||||
|
body: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverToBoxAdapter(child: SafeArea(left: false, bottom: false, right: false,child: Container(),),),
|
||||||
|
SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
return tab == ViewStationPageTab.arrivals ? buildStationArrivalItem(context, snapshot.data!.arrivals![index]) : buildStationDepartureItem(context, snapshot.data!.departures![index]);
|
||||||
|
},
|
||||||
|
childCount: tab == ViewStationPageTab.arrivals ? snapshot.data!.arrivals?.length ?? 0 : snapshot.data!.departures?.length ?? 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
title: const Text(ViewStationPageShared.departures),
|
||||||
|
icon: const Icon(FluentIcons.arrow_up_right8),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
) : null,
|
||||||
|
// bottomNavigationBar: snapshot.hasData ? BottomNavigationBar(
|
||||||
|
// items: const [
|
||||||
|
// BottomNavigationBarItem(
|
||||||
|
// icon: Icon(Icons.arrow_downward),
|
||||||
|
// label: ViewStationPageShared.arrivals,
|
||||||
|
// ),
|
||||||
|
// BottomNavigationBarItem(
|
||||||
|
// icon: Icon(Icons.arrow_upward),
|
||||||
|
// label: ViewStationPageShared.departures,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// currentIndex: tab.index,
|
||||||
|
// onTap: onTabChange,
|
||||||
|
// ) : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildStationItem(BuildContext context, StationArrDep item, {required bool arrival}) {
|
||||||
|
return HoverButton(
|
||||||
|
onPressed: () => onTrainTapped(context, item.train),
|
||||||
|
builder: (context, states) {
|
||||||
|
return Container(
|
||||||
|
color: item.status.cancelled
|
||||||
|
? Colors.red.withAlpha(100)
|
||||||
|
: states.isPressing
|
||||||
|
? FluentTheme.of(context).scaffoldBackgroundColor
|
||||||
|
: states.isHovering
|
||||||
|
? FluentTheme.of(context).inactiveBackgroundColor
|
||||||
|
: null,
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final tz = ref.watch(uiTimeZoneProvider);
|
||||||
|
final time = tz.convertDateTime(item.time);
|
||||||
|
return Text(
|
||||||
|
'${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontFeatures: const [
|
||||||
|
FontFeature.tabularFigures(),
|
||||||
|
],
|
||||||
|
decoration: item.status.cancelled || item.status.delay != 0 ? TextDecoration.lineThrough : null,
|
||||||
|
fontSize: item.status.delay != 0 ? 12 : null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (item.status.delay != 0) Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final tz = ref.watch(uiTimeZoneProvider);
|
||||||
|
final newTime = tz.convertDateTime(item.time.add(Duration(minutes: item.status.delay)));
|
||||||
|
final delay = item.status.delay > 0;
|
||||||
|
|
||||||
|
return Text(
|
||||||
|
'${newTime.hour.toString().padLeft(2, '0')}:${newTime.minute.toString().padLeft(2, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontFeatures: const [
|
||||||
|
FontFeature.tabularFigures(),
|
||||||
|
],
|
||||||
|
color: delay ? Colors.red : Colors.green,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: ListTile(
|
||||||
|
// isThreeLine: item.status.delay != 0,
|
||||||
|
title: Text.rich(
|
||||||
|
trainIdSpan(rank: item.train.rank, number: item.train.number),
|
||||||
|
),
|
||||||
|
subtitle: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: item.status.cancelled
|
||||||
|
? (arrival ? ViewStationPageShared.cancelledArrival : ViewStationPageShared.cancelledDeparture)
|
||||||
|
: item.time.add(Duration(minutes: max(0, item.status.delay))).compareTo(DateTime.now()) < 0
|
||||||
|
? (arrival ? ViewStationPageShared.arrivedFrom : ViewStationPageShared.departedTo)
|
||||||
|
: (arrival ? ViewStationPageShared.arrivesFrom : ViewStationPageShared.departsTo)
|
||||||
|
),
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
TextSpan(text: item.train.terminus),
|
||||||
|
if (item.status.delay != 0) ...[
|
||||||
|
const TextSpan(text: '\n'),
|
||||||
|
if (item.status.delay.abs() >= 60) ...[
|
||||||
|
TextSpan(text: (item.status.delay.abs() ~/ 60).toString()),
|
||||||
|
TextSpan(text: item.status.delay.abs() >= 120 ? ' ore' : ' oră'),
|
||||||
|
if (item.status.delay.abs() % 60 != 0)
|
||||||
|
const TextSpan(text: ' și '),
|
||||||
|
],
|
||||||
|
TextSpan(text: (item.status.delay.abs() % 60).toString()),
|
||||||
|
TextSpan(text: item.status.delay.abs() > 1 ? ' minute' : ' minut'),
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
if (item.status.delay > 0)
|
||||||
|
TextSpan(
|
||||||
|
text: 'întârziere',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
TextSpan(
|
||||||
|
text: 'mai devreme',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (item.status.platform != null)
|
||||||
|
IntrinsicHeight(
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1,
|
||||||
|
child: Badge(
|
||||||
|
text: item.status.platform!,
|
||||||
|
caption: 'Linia',
|
||||||
|
isOnTime: item.status.real && item.status.delay <= 0,
|
||||||
|
isDelayed: item.status.real && item.status.delay > 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildStationArrivalItem(BuildContext context, StationArrDep item) {
|
||||||
|
return buildStationItem(context, item, arrival: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildStationDepartureItem(BuildContext context, StationArrDep item) {
|
||||||
|
return buildStationItem(context, item, arrival: false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,40 +1,90 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'dart:math';
|
||||||
|
import 'dart:ui';
|
||||||
|
import 'package:flutter/material.dart' hide Badge;
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:info_tren/components/badge/badge.dart';
|
||||||
import 'package:info_tren/components/loading/loading.dart';
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
import 'package:info_tren/components/refresh_future_builder.dart';
|
import 'package:info_tren/components/refresh_future_builder.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
import 'package:info_tren/components/train_id_text_span.dart';
|
||||||
import 'package:info_tren/models/station_data.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
import 'package:info_tren/pages/station_arrdep_page/view_station/view_station.dart';
|
||||||
|
import 'package:info_tren/providers.dart';
|
||||||
|
|
||||||
|
class ViewStationPageMaterial extends ViewStationPageShared {
|
||||||
|
const ViewStationPageMaterial({super.key, required super.tab, required super.setTab});
|
||||||
|
|
||||||
class ViewStationPageStateMaterial extends ViewStationPageState {
|
|
||||||
@override
|
@override
|
||||||
Widget buildContent(BuildContext context, Future Function() refresh, Future Function(Future<StationData> Function()) _, RefreshFutureBuilderSnapshot<StationData> snapshot) {
|
Widget buildContent(BuildContext context, Future Function() refresh, Future Function(Future<StationData> Function()) _, RefreshFutureBuilderSnapshot<StationData> snapshot) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(snapshot.hasData ? snapshot.data!.stationName : stationName),
|
title: Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final stationName = ref.watch(viewStationArgumentsProvider.select((value) => value.stationName));
|
||||||
|
return Text(snapshot.hasData ? snapshot.data!.stationName : stationName);
|
||||||
|
}
|
||||||
|
),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
),
|
),
|
||||||
body: snapshot.state == RefreshFutureBuilderState.waiting ? Loading(text: ViewStationPageState.loadingText, uiDesign: widget.uiDesign,) : CustomScrollView(
|
body: snapshot.state == RefreshFutureBuilderState.waiting
|
||||||
slivers: [
|
? const Loading(text: ViewStationPageShared.loadingText,)
|
||||||
SliverToBoxAdapter(child: SafeArea(child: Container(), left: false, bottom: false, right: false,),),
|
: snapshot.state == RefreshFutureBuilderState.error
|
||||||
SliverList(
|
? Padding(
|
||||||
delegate: SliverChildBuilderDelegate(
|
padding: const EdgeInsets.all(8.0),
|
||||||
(context, index) {
|
child: Center(
|
||||||
return tab == ViewStationPageTab.arrivals ? buildStationArrivalItem(context, snapshot.data!.arrivals![index]) : buildStationDepartureItem(context, snapshot.data!.departures![index]);
|
child: Column(
|
||||||
},
|
mainAxisSize: MainAxisSize.min,
|
||||||
childCount: tab == ViewStationPageTab.arrivals ? snapshot.data!.arrivals?.length ?? 0 : snapshot.data!.departures?.length ?? 0,
|
children: [
|
||||||
|
const Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
size: 32,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
const Text(
|
||||||
|
ViewStationPageShared.errorText,
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontSize: 32,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
snapshot.error.toString(),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
refresh();
|
||||||
|
},
|
||||||
|
child: const Text(ViewStationPageShared.retryText),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
)
|
||||||
),
|
: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverToBoxAdapter(child: SafeArea(left: false, bottom: false, right: false,child: Container(),),),
|
||||||
|
SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
return tab == ViewStationPageTab.arrivals ? buildStationArrivalItem(context, snapshot.data!.arrivals![index]) : buildStationDepartureItem(context, snapshot.data!.departures![index]);
|
||||||
|
},
|
||||||
|
childCount: tab == ViewStationPageTab.arrivals ? snapshot.data!.arrivals?.length ?? 0 : snapshot.data!.departures?.length ?? 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
bottomNavigationBar: snapshot.hasData ? BottomNavigationBar(
|
bottomNavigationBar: snapshot.hasData ? BottomNavigationBar(
|
||||||
items: [
|
items: const [
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.arrow_downward),
|
icon: Icon(Icons.arrow_downward),
|
||||||
label: ViewStationPageState.arrivals,
|
label: ViewStationPageShared.arrivals,
|
||||||
),
|
),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
icon: Icon(Icons.arrow_upward),
|
icon: Icon(Icons.arrow_upward),
|
||||||
label: ViewStationPageState.departures,
|
label: ViewStationPageShared.departures,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
currentIndex: tab.index,
|
currentIndex: tab.index,
|
||||||
|
@ -43,65 +93,136 @@ class ViewStationPageStateMaterial extends ViewStationPageState {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
Widget buildStationItem(BuildContext context, StationArrDep item, {required bool arrival}) {
|
||||||
Widget buildStationArrivalItem(BuildContext context, StationArrival item) {
|
return InkWell(
|
||||||
return ListTile(
|
onTap: () => onTrainTapped(context, item.train),
|
||||||
leading: Text('${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}'),
|
child: Container(
|
||||||
title: Text.rich(
|
color: item.status.cancelled ? Colors.red.withAlpha(100) : null,
|
||||||
TextSpan(
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
Padding(
|
||||||
text: item.train.rank,
|
padding: const EdgeInsets.all(8),
|
||||||
style: TextStyle(
|
child: Column(
|
||||||
color: item.train.rank.startsWith('IR') ? Color.fromARGB(255, 255, 0, 0) : null,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final tz = ref.watch(uiTimeZoneProvider);
|
||||||
|
final time = tz.convertDateTime(item.time);
|
||||||
|
return Text(
|
||||||
|
'${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontFeatures: const [
|
||||||
|
FontFeature.tabularFigures(),
|
||||||
|
],
|
||||||
|
decoration: item.status.cancelled || item.status.delay != 0 ? TextDecoration.lineThrough : null,
|
||||||
|
fontSize: item.status.delay != 0 ? 12 : null,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
if (item.status.delay != 0) Consumer(
|
||||||
|
builder: (context, ref, _) {
|
||||||
|
final tz = ref.watch(uiTimeZoneProvider);
|
||||||
|
final newTime = tz.convertDateTime(item.time.add(Duration(minutes: item.status.delay)));
|
||||||
|
final delay = item.status.delay > 0;
|
||||||
|
|
||||||
|
return Text(
|
||||||
|
'${newTime.hour.toString().padLeft(2, '0')}:${newTime.minute.toString().padLeft(2, '0')}',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
fontFeatures: const [
|
||||||
|
FontFeature.tabularFigures(),
|
||||||
|
],
|
||||||
|
color: delay ? Colors.red : Colors.green,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
TextSpan(text: ' '),
|
Expanded(
|
||||||
TextSpan(text: item.train.number,),
|
child: IgnorePointer(
|
||||||
|
child: ListTile(
|
||||||
|
isThreeLine: item.status.delay != 0,
|
||||||
|
title: Text.rich(
|
||||||
|
trainIdSpan(rank: item.train.rank, number: item.train.number),
|
||||||
|
),
|
||||||
|
subtitle: Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
TextSpan(
|
||||||
|
text: item.status.cancelled
|
||||||
|
? (arrival ? ViewStationPageShared.cancelledArrival : ViewStationPageShared.cancelledDeparture)
|
||||||
|
: item.time.add(Duration(minutes: max(0, item.status.delay))).compareTo(DateTime.now()) < 0
|
||||||
|
? (arrival ? ViewStationPageShared.arrivedFrom : ViewStationPageShared.departedTo)
|
||||||
|
: (arrival ? ViewStationPageShared.arrivesFrom : ViewStationPageShared.departsTo)
|
||||||
|
),
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
TextSpan(text: item.train.terminus),
|
||||||
|
if (item.status.delay != 0) ...[
|
||||||
|
const TextSpan(text: '\n'),
|
||||||
|
if (item.status.delay.abs() >= 60) ...[
|
||||||
|
TextSpan(text: (item.status.delay.abs() ~/ 60).toString()),
|
||||||
|
TextSpan(text: item.status.delay.abs() >= 120 ? ' ore' : ' oră'),
|
||||||
|
if (item.status.delay.abs() % 60 != 0)
|
||||||
|
const TextSpan(text: ' și '),
|
||||||
|
],
|
||||||
|
TextSpan(text: (item.status.delay.abs() % 60).toString()),
|
||||||
|
TextSpan(text: item.status.delay.abs() > 1 ? ' minute' : ' minut'),
|
||||||
|
const TextSpan(text: ' '),
|
||||||
|
if (item.status.delay > 0)
|
||||||
|
const TextSpan(
|
||||||
|
text: 'întârziere',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: Colors.red,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
const TextSpan(
|
||||||
|
text: 'mai devreme',
|
||||||
|
style: TextStyle(
|
||||||
|
inherit: true,
|
||||||
|
color: Colors.green,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (item.status.platform != null)
|
||||||
|
IntrinsicHeight(
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1,
|
||||||
|
child: Badge(
|
||||||
|
text: item.status.platform!,
|
||||||
|
caption: 'Linia',
|
||||||
|
isOnTime: item.status.real && item.status.delay <= 0,
|
||||||
|
isDelayed: item.status.real && item.status.delay > 0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
subtitle: Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
TextSpan(text: ViewStationPageState.arrivesFrom),
|
|
||||||
TextSpan(text: ' '),
|
|
||||||
TextSpan(text: item.train.origin),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onTap: () => onTrainTapped(item.train.number),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget buildStationDepartureItem(BuildContext context, StationDeparture item) {
|
Widget buildStationArrivalItem(BuildContext context, StationArrDep item) {
|
||||||
return ListTile(
|
return buildStationItem(context, item, arrival: true);
|
||||||
leading: Text('${item.time.toLocal().hour.toString().padLeft(2, '0')}:${item.time.toLocal().minute.toString().padLeft(2, '0')}'),
|
|
||||||
title: Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
TextSpan(
|
|
||||||
text: item.train.rank,
|
|
||||||
style: TextStyle(
|
|
||||||
color: item.train.rank.startsWith('IR') ? Color.fromARGB(255, 255, 0, 0) : null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
TextSpan(text: ' '),
|
|
||||||
TextSpan(text: item.train.number,),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
subtitle: Text.rich(
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
TextSpan(text: ViewStationPageState.departsTo),
|
|
||||||
TextSpan(text: ' '),
|
|
||||||
TextSpan(text: item.train.destination),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onTap: () => onTrainTapped(item.train.number),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@override
|
||||||
|
Widget buildStationDepartureItem(BuildContext context, StationArrDep item) {
|
||||||
|
return buildStationItem(context, item, arrival: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,50 +1,110 @@
|
||||||
import 'dart:io' show Platform;
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions.dart';
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions.dart';
|
||||||
import 'package:info_tren/models/ui_design.dart';
|
import 'package:info_tren/models.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/select_train/select_train_cupertino.dart';
|
import 'package:info_tren/pages/train_info_page/select_train/select_train_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/select_train/select_train_fluent.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/select_train/select_train_material.dart';
|
import 'package:info_tren/pages/train_info_page/select_train/select_train_material.dart';
|
||||||
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
||||||
import 'package:info_tren/utils/default_ui_design.dart';
|
import 'package:info_tren/providers.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:info_tren/api/trains.dart' as api_trains;
|
||||||
|
|
||||||
typedef TrainSelectedCallback(int trainNumber);
|
typedef TrainSelectedCallback = Function(int trainNumber);
|
||||||
|
|
||||||
class SelectTrainPage extends StatefulWidget {
|
class SelectTrainPage extends ConsumerWidget {
|
||||||
final UiDesign? uiDesign;
|
const SelectTrainPage({super.key});
|
||||||
|
|
||||||
SelectTrainPage({Key? key, this.uiDesign}) : super(key: key);
|
|
||||||
|
|
||||||
static String routeName = "/trainInfo/selectTrain";
|
static String routeName = "/trainInfo/selectTrain";
|
||||||
|
|
||||||
void onTrainSelected(BuildContext context, String selection) {
|
|
||||||
Navigator.of(context).pushNamed(TrainInfo.routeName, arguments: selection);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
SelectTrainPageState createState() {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
final uiDesign = ref.watch(uiDesignProvider);
|
||||||
|
|
||||||
switch(uiDesign) {
|
switch(uiDesign) {
|
||||||
case UiDesign.MATERIAL:
|
case UiDesign.MATERIAL:
|
||||||
return SelectTrainPageStateMaterial();
|
return const SelectTrainPageMaterial();
|
||||||
case UiDesign.CUPERTINO:
|
case UiDesign.CUPERTINO:
|
||||||
return SelectTrainPageStateCupertino();
|
return const SelectTrainPageCupertino();
|
||||||
|
case UiDesign.FLUENT:
|
||||||
|
return const SelectTrainPageFluent();
|
||||||
default:
|
default:
|
||||||
throw UnmatchedUiDesignException(uiDesign);
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class SelectTrainPageState extends State<SelectTrainPage> {
|
abstract class SelectTrainPageShared extends StatefulWidget {
|
||||||
|
const SelectTrainPageShared({super.key});
|
||||||
|
|
||||||
|
void onTrainSelected(BuildContext context, String selection) {
|
||||||
|
selection = selection.characters.takeWhile((char) => List.generate(10, (i) => i.toString()).contains(char)).join();
|
||||||
|
Navigator.of(context).pushNamed(
|
||||||
|
TrainInfo.routeName,
|
||||||
|
arguments: TrainInfoArguments(trainNumber: selection),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class SelectTrainPageState extends State<SelectTrainPageShared> {
|
||||||
final String pageTitle = 'Informații despre tren';
|
final String pageTitle = 'Informații despre tren';
|
||||||
final String textFieldLabel = 'Numărul trenului';
|
final String textFieldLabel = 'Numărul trenului';
|
||||||
|
|
||||||
TextEditingController trainNoController = TextEditingController();
|
final trainNoController = TextEditingController();
|
||||||
|
|
||||||
|
List<TrainsResult> trains = [];
|
||||||
|
|
||||||
|
List<TrainsResult> get filteredTrains {
|
||||||
|
final filter = trainNoController.text
|
||||||
|
.trim()
|
||||||
|
.toLowerCase();
|
||||||
|
if (filter.isEmpty) {
|
||||||
|
return trains;
|
||||||
|
}
|
||||||
|
|
||||||
|
final filtered = trains.where((e) => e.number.contains(filter)).toList(growable: false);
|
||||||
|
|
||||||
|
filtered.sort((t1, t2) {
|
||||||
|
final posInNum1 = t1.number.indexOf(filter);
|
||||||
|
final posInNum2 = t2.number.indexOf(filter);
|
||||||
|
|
||||||
|
if (posInNum1 != posInNum2) {
|
||||||
|
return posInNum1.compareTo(posInNum2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t1.number.length != t2.number.length) {
|
||||||
|
return t1.number.length.compareTo(t2.number.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return t1.number.compareTo(t2.number);
|
||||||
|
});
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
api_trains.trains.then((value) {
|
||||||
|
setState(() {
|
||||||
|
trains = value;
|
||||||
|
trains.sort((t1, t2) {
|
||||||
|
if (t1.company != t2.company) {
|
||||||
|
return t1.company.compareTo(t2.company);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t1.rank != t2.rank) {
|
||||||
|
return t1.rank.compareTo(t2.rank);
|
||||||
|
}
|
||||||
|
|
||||||
|
final t1Num = t1.number.padLeft(t2.number.length, '0');
|
||||||
|
final t2Num = t2.number.padLeft(t1.number.length, '0');
|
||||||
|
|
||||||
|
return t1Num.compareTo(t2Num);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,9 +113,9 @@ abstract class SelectTrainPageState extends State<SelectTrainPage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget get suggestionsList => SelectTrainSuggestions(
|
Widget get suggestionsList => SelectTrainSuggestions(
|
||||||
uiDesign: widget.uiDesign,
|
choices: filteredTrains,
|
||||||
userInput: trainNoController.text,
|
|
||||||
onTrainSelected: (trainNumber) => widget.onTrainSelected(context, trainNumber),
|
onTrainSelected: (trainNumber) => widget.onTrainSelected(context, trainNumber),
|
||||||
|
currentInput: trainNoController.text,
|
||||||
key: ValueKey(trainNoController.text),
|
key: ValueKey(trainNoController.text),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue