Transition WebView to API #1
|
@ -1,3 +1,8 @@
|
||||||
|
v2.0.7
|
||||||
|
Switched from WebView to API
|
||||||
|
Updated app to latest Flutter
|
||||||
|
Tweaks
|
||||||
|
|
||||||
v2.0.6
|
v2.0.6
|
||||||
Brought feature parity with iOS _(except for v2.0.2, which is iOS specific)_.
|
Brought feature parity with iOS _(except for v2.0.2, which is iOS specific)_.
|
||||||
|
|
||||||
|
|
29
analysis_options.yaml
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# This file configures the analyzer, which statically analyzes Dart code to
|
||||||
|
# check for errors, warnings, and lints.
|
||||||
|
#
|
||||||
|
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||||
|
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||||
|
# invoked from the command line by running `flutter analyze`.
|
||||||
|
|
||||||
|
# The following line activates a set of recommended lints for Flutter apps,
|
||||||
|
# packages, and plugins designed to encourage good coding practices.
|
||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
linter:
|
||||||
|
# The lint rules applied to this project can be customized in the
|
||||||
|
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||||
|
# included above or to enable additional rules. A list of all available lints
|
||||||
|
# and their documentation is published at
|
||||||
|
# https://dart-lang.github.io/linter/lints/index.html.
|
||||||
|
#
|
||||||
|
# Instead of disabling a lint rule for the entire project in the
|
||||||
|
# section below, it can also be suppressed for a single line of code
|
||||||
|
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||||
|
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||||
|
# producing the lint.
|
||||||
|
rules:
|
||||||
|
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||||
|
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||||
|
|
||||||
|
# Additional information about this file can be found at
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
13
android/.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
gradle-wrapper.jar
|
||||||
|
/.gradle
|
||||||
|
/captures/
|
||||||
|
/gradlew
|
||||||
|
/gradlew.bat
|
||||||
|
/local.properties
|
||||||
|
GeneratedPluginRegistrant.java
|
||||||
|
|
||||||
|
# Remember to never publicly share your keystore.
|
||||||
|
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
|
||||||
|
key.properties
|
||||||
|
**/*.keystore
|
||||||
|
**/*.jks
|
|
@ -38,7 +38,7 @@ 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 "ml.dandevelop.info_tren"
|
applicationId "xyz.dcdevelop.infotren"
|
||||||
minSdkVersion 16
|
minSdkVersion 16
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package xyz.dcdevelop.info_tren
|
||||||
|
|
||||||
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
class MainActivity: FlutterActivity() {
|
||||||
|
}
|
12
android/app/src/main/res/drawable-v21/launch_background.xml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Modify this file to customize your launch splash screen -->
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="?android:colorBackground" />
|
||||||
|
|
||||||
|
<!-- You can insert your own image assets here -->
|
||||||
|
<!-- <item>
|
||||||
|
<bitmap
|
||||||
|
android:gravity="center"
|
||||||
|
android:src="@mipmap/launch_image" />
|
||||||
|
</item> -->
|
||||||
|
</layer-list>
|
18
android/app/src/main/res/values-night/styles.xml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||||
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
|
Flutter draws its first frame -->
|
||||||
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
|
</style>
|
||||||
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
|
This theme determines the color of the Android Window while your
|
||||||
|
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||||
|
running.
|
||||||
|
|
||||||
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
BIN
fonts/ah/ah-Bold.ttf
Normal file
BIN
fonts/ah/ah-BoldItalic.ttf
Normal file
BIN
fonts/ah/ah-Italic.ttf
Normal file
BIN
fonts/ah/ah-Regular.ttf
Normal file
33
ios/.gitignore
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
*.mode1v3
|
||||||
|
*.mode2v3
|
||||||
|
*.moved-aside
|
||||||
|
*.pbxuser
|
||||||
|
*.perspectivev3
|
||||||
|
**/*sync/
|
||||||
|
.sconsign.dblite
|
||||||
|
.tags*
|
||||||
|
**/.vagrant/
|
||||||
|
**/DerivedData/
|
||||||
|
Icon?
|
||||||
|
**/Pods/
|
||||||
|
**/.symlinks/
|
||||||
|
profile
|
||||||
|
xcuserdata
|
||||||
|
**/.generated/
|
||||||
|
Flutter/App.framework
|
||||||
|
Flutter/Flutter.framework
|
||||||
|
Flutter/Flutter.podspec
|
||||||
|
Flutter/Generated.xcconfig
|
||||||
|
Flutter/ephemeral/
|
||||||
|
Flutter/app.flx
|
||||||
|
Flutter/app.zip
|
||||||
|
Flutter/flutter_assets/
|
||||||
|
Flutter/flutter_export_environment.sh
|
||||||
|
ServiceDefinitions.json
|
||||||
|
Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!default.mode1v3
|
||||||
|
!default.mode2v3
|
||||||
|
!default.pbxuser
|
||||||
|
!default.perspectivev3
|
|
@ -3,7 +3,7 @@
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>en</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>App</string>
|
<string>App</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
|
@ -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>8.0</string>
|
<string>9.0</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
|
||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
#
|
|
||||||
# NOTE: This podspec is NOT to be published. It is only used as a local source!
|
|
||||||
# This is a generated file; do not edit or check into version control.
|
|
||||||
#
|
|
||||||
|
|
||||||
Pod::Spec.new do |s|
|
|
||||||
s.name = 'Flutter'
|
|
||||||
s.version = '1.0.0'
|
|
||||||
s.summary = 'High-performance, high-fidelity mobile apps.'
|
|
||||||
s.homepage = 'https://flutter.io'
|
|
||||||
s.license = { :type => 'MIT' }
|
|
||||||
s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
|
|
||||||
s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
|
|
||||||
s.ios.deployment_target = '8.0'
|
|
||||||
# Framework linking is handled by Flutter tooling, not CocoaPods.
|
|
||||||
# Add a placeholder to satisfy `s.dependency 'Flutter'` plugin podspecs.
|
|
||||||
s.vendored_frameworks = 'path/to/nothing'
|
|
||||||
end
|
|
|
@ -1,2 +1 @@
|
||||||
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
|
||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|
|
@ -5,7 +5,6 @@ export "FLUTTER_APPLICATION_PATH=/Users/dan.cojocaru/info_tren"
|
||||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||||
export "FLUTTER_TARGET=/Users/dan.cojocaru/info_tren/lib/main.dart"
|
export "FLUTTER_TARGET=/Users/dan.cojocaru/info_tren/lib/main.dart"
|
||||||
export "FLUTTER_BUILD_DIR=build"
|
export "FLUTTER_BUILD_DIR=build"
|
||||||
export "SYMROOT=${SOURCE_ROOT}/../build/ios"
|
|
||||||
export "FLUTTER_BUILD_NAME=2.0.6"
|
export "FLUTTER_BUILD_NAME=2.0.6"
|
||||||
export "FLUTTER_BUILD_NUMBER=2.0.6"
|
export "FLUTTER_BUILD_NUMBER=2.0.6"
|
||||||
export "DART_DEFINES=Zmx1dHRlci5pbnNwZWN0b3Iuc3RydWN0dXJlZEVycm9ycz10cnVl,RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
|
export "DART_DEFINES=Zmx1dHRlci5pbnNwZWN0b3Iuc3RydWN0dXJlZEVycm9ycz10cnVl,RkxVVFRFUl9XRUJfQVVUT19ERVRFQ1Q9dHJ1ZQ=="
|
||||||
|
|
41
ios/Podfile
|
@ -1,41 +0,0 @@
|
||||||
# Uncomment this line to define a global platform for your project
|
|
||||||
# platform :ios, '9.0'
|
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
|
||||||
|
|
||||||
project 'Runner', {
|
|
||||||
'Debug' => :debug,
|
|
||||||
'Profile' => :release,
|
|
||||||
'Release' => :release,
|
|
||||||
}
|
|
||||||
|
|
||||||
def flutter_root
|
|
||||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
|
||||||
unless File.exist?(generated_xcode_build_settings_path)
|
|
||||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
|
||||||
end
|
|
||||||
|
|
||||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
|
||||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
|
||||||
return matches[1].strip if matches
|
|
||||||
end
|
|
||||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
|
||||||
end
|
|
||||||
|
|
||||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
|
||||||
|
|
||||||
flutter_ios_podfile_setup
|
|
||||||
|
|
||||||
target 'Runner' do
|
|
||||||
use_frameworks!
|
|
||||||
use_modular_headers!
|
|
||||||
|
|
||||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
|
||||||
end
|
|
||||||
|
|
||||||
post_install do |installer|
|
|
||||||
installer.pods_project.targets.each do |target|
|
|
||||||
flutter_additional_ios_build_settings(target)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,22 +0,0 @@
|
||||||
PODS:
|
|
||||||
- Flutter (1.0.0)
|
|
||||||
- webview_flutter (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
|
|
||||||
DEPENDENCIES:
|
|
||||||
- Flutter (from `Flutter`)
|
|
||||||
- webview_flutter (from `.symlinks/plugins/webview_flutter/ios`)
|
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
|
||||||
Flutter:
|
|
||||||
:path: Flutter
|
|
||||||
webview_flutter:
|
|
||||||
:path: ".symlinks/plugins/webview_flutter/ios"
|
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
|
||||||
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
|
|
||||||
webview_flutter: 1aa7604e6cdb451a9b7ed2c37d5454c0b440246b
|
|
||||||
|
|
||||||
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
|
|
||||||
|
|
||||||
COCOAPODS: 1.10.1
|
|
|
@ -3,15 +3,13 @@
|
||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 46;
|
objectVersion = 50;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
722F441253D3B79676E4DE80 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F72320B12B1F4015789BBC8E /* Pods_Runner.framework */; };
|
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
|
|
||||||
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 */; };
|
||||||
|
@ -33,12 +31,9 @@
|
||||||
/* 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>"; };
|
||||||
313F1E773DA06364A0C4F20A /* 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>"; };
|
||||||
636963D381657D3BAEDC0A47 /* 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>"; };
|
|
||||||
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>"; };
|
||||||
74CD890ACD2E394E606FCBEB /* 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>"; };
|
|
||||||
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>"; };
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||||
|
@ -47,7 +42,6 @@
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
F72320B12B1F4015789BBC8E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -55,21 +49,12 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
722F441253D3B79676E4DE80 /* Pods_Runner.framework in Frameworks */,
|
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
0B24EBF53F1DCC708FA961FD /* Frameworks */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
F72320B12B1F4015789BBC8E /* Pods_Runner.framework */,
|
|
||||||
);
|
|
||||||
name = Frameworks;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -87,8 +72,6 @@
|
||||||
9740EEB11CF90186004384FC /* Flutter */,
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
A2E7A2EB20EFBBAC4AB0299B /* Pods */,
|
|
||||||
0B24EBF53F1DCC708FA961FD /* Frameworks */,
|
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
@ -107,7 +90,6 @@
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||||
97C147021CF9000F007C117D /* Info.plist */,
|
97C147021CF9000F007C117D /* Info.plist */,
|
||||||
97C146F11CF9000F007C117D /* Supporting Files */,
|
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||||
|
@ -116,23 +98,6 @@
|
||||||
path = Runner;
|
path = Runner;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
97C146F11CF9000F007C117D /* Supporting Files */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
);
|
|
||||||
name = "Supporting Files";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
A2E7A2EB20EFBBAC4AB0299B /* Pods */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
313F1E773DA06364A0C4F20A /* Pods-Runner.debug.xcconfig */,
|
|
||||||
74CD890ACD2E394E606FCBEB /* Pods-Runner.release.xcconfig */,
|
|
||||||
636963D381657D3BAEDC0A47 /* Pods-Runner.profile.xcconfig */,
|
|
||||||
);
|
|
||||||
path = Pods;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
|
@ -140,14 +105,12 @@
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
0D525F98970BF5A8EFFD825C /* [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 */,
|
||||||
1B7EDCF8AB293318D8391906 /* [CP] Embed Pods Frameworks */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
|
@ -165,18 +128,16 @@
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 1020;
|
LastUpgradeCheck = 1020;
|
||||||
ORGANIZATIONNAME = "The Chromium Authors";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
97C146ED1CF9000F007C117D = {
|
97C146ED1CF9000F007C117D = {
|
||||||
CreatedOnToolsVersion = 7.3.1;
|
CreatedOnToolsVersion = 7.3.1;
|
||||||
DevelopmentTeam = NF9A3KMT8Q;
|
LastSwiftMigration = 1100;
|
||||||
LastSwiftMigration = 0910;
|
|
||||||
ProvisioningStyle = Automatic;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||||
compatibilityVersion = "Xcode 3.2";
|
compatibilityVersion = "Xcode 9.3";
|
||||||
developmentRegion = en;
|
developmentRegion = en;
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
knownRegions = (
|
knownRegions = (
|
||||||
|
@ -200,7 +161,6 @@
|
||||||
files = (
|
files = (
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||||
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
|
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||||
);
|
);
|
||||||
|
@ -209,46 +169,6 @@
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
0D525F98970BF5A8EFFD825C /* [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;
|
|
||||||
};
|
|
||||||
1B7EDCF8AB293318D8391906 /* [CP] Embed Pods Frameworks */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputPaths = (
|
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
|
|
||||||
"${BUILT_PRODUCTS_DIR}/webview_flutter/webview_flutter.framework",
|
|
||||||
);
|
|
||||||
name = "[CP] Embed Pods Frameworks";
|
|
||||||
outputPaths = (
|
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/webview_flutter.framework",
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -352,9 +272,10 @@
|
||||||
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 = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
};
|
};
|
||||||
|
@ -365,27 +286,19 @@
|
||||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CURRENT_PROJECT_VERSION = 2.0.7;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
|
||||||
DEVELOPMENT_TEAM = NF9A3KMT8Q;
|
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
|
||||||
LIBRARY_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = ml.dandevelop.infoTren;
|
MARKETING_VERSION = 2.0.7;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = xyz.dcdevelop.infotren;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 4.0;
|
SWIFT_VERSION = 5.0;
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
};
|
};
|
||||||
name = Profile;
|
name = Profile;
|
||||||
|
@ -437,7 +350,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 = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
|
@ -486,10 +399,12 @@
|
||||||
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 = 8.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
TARGETED_DEVICE_FAMILY = "1,2";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
};
|
};
|
||||||
|
@ -501,29 +416,19 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CURRENT_PROJECT_VERSION = 2.0.7;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
|
||||||
DEVELOPMENT_TEAM = NF9A3KMT8Q;
|
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
|
||||||
LIBRARY_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = ml.dandevelop.infoTren;
|
MARKETING_VERSION = 2.0.7;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = xyz.dcdevelop.infotren;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
|
||||||
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";
|
||||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
SWIFT_VERSION = 5.0;
|
||||||
SWIFT_VERSION = 4.0;
|
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
|
@ -534,28 +439,18 @@
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CURRENT_PROJECT_VERSION = 2.0.7;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
|
||||||
DEVELOPMENT_TEAM = NF9A3KMT8Q;
|
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
|
||||||
"$(PROJECT_DIR)/Flutter",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
|
||||||
LIBRARY_SEARCH_PATHS = (
|
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Flutter",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = ml.dandevelop.infoTren;
|
MARKETING_VERSION = 2.0.7;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = xyz.dcdevelop.infotren;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_SWIFT3_OBJC_INFERENCE = On;
|
SWIFT_VERSION = 5.0;
|
||||||
SWIFT_VERSION = 4.0;
|
|
||||||
VERSIONING_SYSTEM = "apple-generic";
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
|
@ -4,7 +4,4 @@
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "group:Runner.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
<FileRef
|
|
||||||
location = "group:Pods/Pods.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -5,7 +5,7 @@ import Flutter
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
override func application(
|
override func application(
|
||||||
_ application: UIApplication,
|
_ application: UIApplication,
|
||||||
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
GeneratedPluginRegistrant.register(with: self)
|
GeneratedPluginRegistrant.register(with: self)
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
|
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
@ -17,24 +17,13 @@
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
<string>$(MARKETING_VERSION)</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSAppTransportSecurity</key>
|
|
||||||
<dict>
|
|
||||||
<key>NSExceptionDomains</key>
|
|
||||||
<dict>
|
|
||||||
<key>cfr-scrapper.herokuapp.com</key>
|
|
||||||
<dict>
|
|
||||||
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
</dict>
|
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
<key>UIMainStoryboardFile</key>
|
<key>UIMainStoryboardFile</key>
|
||||||
|
@ -42,6 +31,8 @@
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
<array>
|
<array>
|
||||||
|
@ -52,7 +43,5 @@
|
||||||
</array>
|
</array>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>io.flutter.embedded_views_preview</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
#import "GeneratedPluginRegistrant.h"
|
#import "GeneratedPluginRegistrant.h"
|
||||||
|
|
9
lib/api/train_data.dart
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:info_tren/models/train_data.dart';
|
||||||
|
|
||||||
|
const AUTHORITY = 'scraper.infotren.dcdevelop.xyz';
|
||||||
|
|
||||||
|
Future<TrainData> getTrain(int trainNumber) async {
|
||||||
|
final response = await http.get(Uri.https(AUTHORITY, 'train/$trainNumber'));
|
||||||
|
return trainDataFromJson(response.body);
|
||||||
|
}
|
60
lib/components/cupertino_divider.dart
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/train_info_constants.dart';
|
||||||
|
|
||||||
|
class CupertinoDivider extends StatelessWidget {
|
||||||
|
final Color color;
|
||||||
|
|
||||||
|
CupertinoDivider({Key? key, Color? color}):
|
||||||
|
color = color ?? FOREGROUND_DARK_GREY,
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
height: 1,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 1,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: color,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CupertinoVerticalDivider extends StatelessWidget {
|
||||||
|
final Color color;
|
||||||
|
|
||||||
|
CupertinoVerticalDivider({Key? key, Color? color}):
|
||||||
|
color = color ?? FOREGROUND_DARK_GREY,
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 1,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: color,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
42
lib/components/future_display.dart
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:info_tren/models/ui_design.dart';
|
||||||
|
import 'package:info_tren/utils/default_ui_design.dart';
|
||||||
|
|
||||||
|
class FutureDisplay<T> extends StatelessWidget {
|
||||||
|
final UiDesign? uiDesign;
|
||||||
|
final Future<T> future;
|
||||||
|
final Widget Function<T>(BuildContext context, T data) builder;
|
||||||
|
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);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
||||||
|
return FutureBuilder(
|
||||||
|
future: future,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasData) return builder(context, snapshot.data);
|
||||||
|
if (snapshot.hasError) return (errorBuilder != null ? errorBuilder!(context, snapshot.error!, snapshot.stackTrace) : throw snapshot.error!);
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) return Container();
|
||||||
|
|
||||||
|
Widget loadingWidget;
|
||||||
|
switch (uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
loadingWidget = CircularProgressIndicator();
|
||||||
|
break;
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
loadingWidget = CupertinoActivityIndicator();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Center(
|
||||||
|
child: loadingWidget,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
31
lib/components/loading/loading.dart
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:info_tren/components/loading/loading_cupertino.dart';
|
||||||
|
import 'package:info_tren/components/loading/loading_material.dart';
|
||||||
|
import 'package:info_tren/models/ui_design.dart';
|
||||||
|
import 'package:info_tren/utils/default_ui_design.dart';
|
||||||
|
|
||||||
|
class Loading extends StatelessWidget {
|
||||||
|
static const DEFAULT_TEXT = 'Loading...';
|
||||||
|
|
||||||
|
final UiDesign? uiDesign;
|
||||||
|
final String? text;
|
||||||
|
const Loading({ Key? key, this.text, this.uiDesign }) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
||||||
|
switch (uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
return LoadingMaterial(text: text ?? DEFAULT_TEXT,);
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
return LoadingCupertino(text: text ?? DEFAULT_TEXT,);
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class LoadingCommon extends StatelessWidget {
|
||||||
|
final String text;
|
||||||
|
LoadingCommon({required this.text});
|
||||||
|
}
|
28
lib/components/loading/loading_cupertino.dart
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/src/widgets/framework.dart';
|
||||||
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
|
|
||||||
|
class LoadingCupertino extends LoadingCommon {
|
||||||
|
LoadingCupertino({required String text}) : super(text: text,);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: CupertinoActivityIndicator(),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(text),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
26
lib/components/loading/loading_material.dart
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
|
|
||||||
|
class LoadingMaterial extends LoadingCommon {
|
||||||
|
LoadingMaterial({required String text}) : super(text: text,);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(text),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
117
lib/components/refresh_future_builder.dart
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
class RefreshFutureBuilder<T> extends StatefulWidget {
|
||||||
|
final Future<T> Function()? futureCreator;
|
||||||
|
final T? initialData;
|
||||||
|
final Widget Function(BuildContext context, Future Function() refresh, RefreshFutureBuilderSnapshot<T> snapshot) builder;
|
||||||
|
|
||||||
|
const RefreshFutureBuilder({ Key? key, this.futureCreator, this.initialData, required this.builder }) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_RefreshFutureBuilderState<T> createState() => _RefreshFutureBuilderState<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _RefreshFutureBuilderState<T> extends State<RefreshFutureBuilder<T>> {
|
||||||
|
late RefreshFutureBuilderSnapshot<T> snapshot;
|
||||||
|
Future<T> Function()? futureCreator;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
snapshot = widget.initialData != null ? RefreshFutureBuilderSnapshot.initial(widget.initialData!) : RefreshFutureBuilderSnapshot.nothing();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
if (futureCreator != widget.futureCreator) {
|
||||||
|
futureCreator = widget.futureCreator;
|
||||||
|
runFuture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future runFuture() async {
|
||||||
|
if (futureCreator == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Set state to signify loading
|
||||||
|
setState(() {
|
||||||
|
switch (snapshot.state) {
|
||||||
|
case RefreshFutureBuilderState.none:
|
||||||
|
snapshot = RefreshFutureBuilderSnapshot.waiting();
|
||||||
|
break;
|
||||||
|
case RefreshFutureBuilderState.initial:
|
||||||
|
snapshot = RefreshFutureBuilderSnapshot.refresh(snapshot.data);
|
||||||
|
break;
|
||||||
|
case RefreshFutureBuilderState.waiting:
|
||||||
|
return;
|
||||||
|
case RefreshFutureBuilderState.error:
|
||||||
|
snapshot = RefreshFutureBuilderSnapshot.refresh(null, snapshot.error, snapshot.stackTrace);
|
||||||
|
break;
|
||||||
|
case RefreshFutureBuilderState.done:
|
||||||
|
snapshot = RefreshFutureBuilderSnapshot.refresh(snapshot.data);
|
||||||
|
break;
|
||||||
|
case RefreshFutureBuilderState.refreshing:
|
||||||
|
return;
|
||||||
|
case RefreshFutureBuilderState.refreshError:
|
||||||
|
snapshot = RefreshFutureBuilderSnapshot.refresh(null, snapshot.error, snapshot.stackTrace);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
final data = await futureCreator!();
|
||||||
|
setState(() {
|
||||||
|
snapshot = RefreshFutureBuilderSnapshot.withData(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (e, st) {
|
||||||
|
setState(() {
|
||||||
|
if (snapshot.state == RefreshFutureBuilderState.waiting) {
|
||||||
|
snapshot = RefreshFutureBuilderSnapshot.withError(e, st);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
snapshot = RefreshFutureBuilderSnapshot.refreshError(snapshot.data, e, st);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return widget.builder(
|
||||||
|
context,
|
||||||
|
runFuture,
|
||||||
|
snapshot,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RefreshFutureBuilderSnapshot<T> {
|
||||||
|
final RefreshFutureBuilderState state;
|
||||||
|
final T? data;
|
||||||
|
final Object? error;
|
||||||
|
final StackTrace? stackTrace;
|
||||||
|
|
||||||
|
bool get hasData => data != null;
|
||||||
|
bool get hasError => error != null;
|
||||||
|
|
||||||
|
const RefreshFutureBuilderSnapshot._(this.state, this.data, this.error, this.stackTrace);
|
||||||
|
const RefreshFutureBuilderSnapshot.nothing() : state = RefreshFutureBuilderState.none, data = null, error = null, stackTrace = null;
|
||||||
|
const RefreshFutureBuilderSnapshot.initial(this.data) : state = RefreshFutureBuilderState.initial, error = null, stackTrace = null;
|
||||||
|
const RefreshFutureBuilderSnapshot.waiting() : state = RefreshFutureBuilderState.waiting, data = null, error = null, stackTrace = null;
|
||||||
|
const RefreshFutureBuilderSnapshot.withError(this.error, [this.stackTrace]) : state = RefreshFutureBuilderState.error, data = null;
|
||||||
|
const RefreshFutureBuilderSnapshot.withData(this.data) : state = RefreshFutureBuilderState.done, error = null, stackTrace = null;
|
||||||
|
const RefreshFutureBuilderSnapshot.refresh(this.data, [this.error, this.stackTrace]) : state = RefreshFutureBuilderState.refreshing;
|
||||||
|
const RefreshFutureBuilderSnapshot.refreshError(this.data, this.error, this.stackTrace) : state = RefreshFutureBuilderState.refreshError;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RefreshFutureBuilderState {
|
||||||
|
none,
|
||||||
|
initial,
|
||||||
|
waiting,
|
||||||
|
error,
|
||||||
|
done,
|
||||||
|
refreshing,
|
||||||
|
refreshError,
|
||||||
|
}
|
|
@ -0,0 +1,209 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/widgets.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_material.dart';
|
||||||
|
import 'package:info_tren/models/train_operator_lines.dart';
|
||||||
|
import 'package:info_tren/models/ui_design.dart';
|
||||||
|
import 'package:info_tren/utils/default_ui_design.dart';
|
||||||
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
|
class SelectTrainSuggestions extends StatefulWidget {
|
||||||
|
final UiDesign? uiDesign;
|
||||||
|
final String userInput;
|
||||||
|
final void Function(int trainNumber) onTrainSelected;
|
||||||
|
|
||||||
|
const SelectTrainSuggestions({ Key? key, required this.uiDesign, required this.userInput, required this.onTrainSelected }) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
SelectTrainSuggestionsState createState() {
|
||||||
|
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
||||||
|
switch(uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
return SelectTrainSuggestionsStateMaterial();
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
return SelectTrainSuggestionsStateCupertino();
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class SelectTrainSuggestionsState extends State<SelectTrainSuggestions> {
|
||||||
|
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(int currentInput) => 'Caută trenul cu numărul $currentInput';
|
||||||
|
Widget getUseCurrentInputWidget(int currentInput, void Function(int) onTrainSelected);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
var sliversTuple = operators.map(
|
||||||
|
(op) => Tuple2(
|
||||||
|
getFilteredLines(op, userInput),
|
||||||
|
op.operator,
|
||||||
|
)
|
||||||
|
).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();
|
||||||
|
|
||||||
|
return CustomScrollView(
|
||||||
|
slivers: <Widget>[
|
||||||
|
...slivers,
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: int.tryParse(userInput) != null ? getUseCurrentInputWidget(int.parse(userInput), widget.onTrainSelected) : Container(),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
|
height: MediaQuery.of(context).viewPadding.bottom,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
final UiDesign? uiDesign;
|
||||||
|
final String operatorName;
|
||||||
|
final List<TrainOperatorTrainDescription> trains;
|
||||||
|
final void Function(int) onTrainSelected;
|
||||||
|
|
||||||
|
const OperatorAutocompleteSliver({ Key? key, required this.uiDesign, required this.operatorName, required this.trains, required this.onTrainSelected }) : super(key: key);
|
||||||
|
|
||||||
|
Widget mapTrainToItem(TrainOperatorTrainDescription train) {
|
||||||
|
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
||||||
|
switch (uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
return OperatorAutocompleteTileMaterial(
|
||||||
|
onTrainSelected: onTrainSelected,
|
||||||
|
operatorName: operatorName,
|
||||||
|
train: train,
|
||||||
|
);
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
return OperatorAutocompleteTileCupertino(
|
||||||
|
onTrainSelected: onTrainSelected,
|
||||||
|
operatorName: operatorName,
|
||||||
|
train: train,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (trains.isEmpty) {
|
||||||
|
return SliverToBoxAdapter(child: Container(),);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SliverPrototypeExtentList(
|
||||||
|
prototypeItem: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
mapTrainToItem(TrainOperatorTrainDescription()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
return Column(
|
||||||
|
children: <Widget>[
|
||||||
|
mapTrainToItem(trains[index]),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
childCount: trains.length,
|
||||||
|
addSemanticIndexes: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class OperatorAutocompleteTile extends StatelessWidget {
|
||||||
|
final String operatorName;
|
||||||
|
final TrainOperatorTrainDescription train;
|
||||||
|
final void Function(int) onTrainSelected;
|
||||||
|
|
||||||
|
const OperatorAutocompleteTile({ Key? key, required this.onTrainSelected, required this.operatorName, required this.train }) : super(key: key);
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions.dart';
|
||||||
|
import 'package:info_tren/models/train_operator_lines.dart';
|
||||||
|
|
||||||
|
class SelectTrainSuggestionsStateCupertino extends SelectTrainSuggestionsState {
|
||||||
|
@override
|
||||||
|
Widget getUseCurrentInputWidget(int currentInput, void Function(int p1) onTrainSelected) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
onTrainSelected(currentInput);
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(getUseCurrentInputWidgetText(currentInput)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Divider(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OperatorAutocompleteTileCupertino extends OperatorAutocompleteTile {
|
||||||
|
OperatorAutocompleteTileCupertino({
|
||||||
|
Key? key,
|
||||||
|
required String operatorName,
|
||||||
|
required void Function(int) onTrainSelected,
|
||||||
|
required TrainOperatorTrainDescription train
|
||||||
|
}): super(
|
||||||
|
onTrainSelected: onTrainSelected,
|
||||||
|
operatorName: operatorName,
|
||||||
|
train: train,
|
||||||
|
key: key,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
onTrainSelected(train.internalNumber);
|
||||||
|
},
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
operatorName,
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(fontSize: 10, fontWeight: FontWeight.w200),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${train.rang} ${train.number}",
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:info_tren/components/select_train_suggestions/select_train_suggestions.dart';
|
||||||
|
import 'package:info_tren/models/train_operator_lines.dart';
|
||||||
|
|
||||||
|
class SelectTrainSuggestionsStateMaterial extends SelectTrainSuggestionsState {
|
||||||
|
@override
|
||||||
|
Widget getUseCurrentInputWidget(int currentInput, void Function(int) onTrainSelected) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
ListTile(
|
||||||
|
title: Text(getUseCurrentInputWidgetText(currentInput)),
|
||||||
|
onTap: () {
|
||||||
|
onTrainSelected(currentInput);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Divider(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OperatorAutocompleteTileMaterial extends OperatorAutocompleteTile {
|
||||||
|
OperatorAutocompleteTileMaterial({
|
||||||
|
Key? key,
|
||||||
|
required String operatorName,
|
||||||
|
required void Function(int) onTrainSelected,
|
||||||
|
required TrainOperatorTrainDescription train
|
||||||
|
}): super(
|
||||||
|
onTrainSelected: onTrainSelected,
|
||||||
|
operatorName: operatorName,
|
||||||
|
train: train,
|
||||||
|
key: key,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
dense: true,
|
||||||
|
title: Text("${train.rang} ${train.number}"),
|
||||||
|
subtitle: Text(operatorName),
|
||||||
|
onTap: () {
|
||||||
|
onTrainSelected(train.internalNumber);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
62
lib/components/slim_app_bar.dart
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class SlimAppBar extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final double size;
|
||||||
|
// final Function onBackTap;
|
||||||
|
|
||||||
|
SlimAppBar({
|
||||||
|
required this.title,
|
||||||
|
this.size = 24,
|
||||||
|
// this.onBackTap,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height: size,
|
||||||
|
child: Container(
|
||||||
|
color:
|
||||||
|
Theme.of(context).appBarTheme.color ??
|
||||||
|
Theme.of(context).primaryColor,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: (ModalRoute.of(context)?.canPop ?? false)
|
||||||
|
? () => Navigator.of(context).pop()
|
||||||
|
: null,
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: <Widget>[
|
||||||
|
Container(
|
||||||
|
height: size,
|
||||||
|
width: size,
|
||||||
|
child: (ModalRoute.of(context)?.canPop ?? false)
|
||||||
|
? BackButtonIcon()
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style:
|
||||||
|
Theme.of(context).appBarTheme.textTheme?.caption?.copyWith(color: Theme.of(context).appBarTheme.textTheme?.bodyText2?.color) ??
|
||||||
|
Theme.of(context).textTheme.caption?.copyWith(color: Theme.of(context).textTheme.bodyText2?.color),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
height: size,
|
||||||
|
width: size,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,23 +0,0 @@
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
|
||||||
|
|
||||||
class HiddenWebView extends StatelessWidget {
|
|
||||||
final WebView webView;
|
|
||||||
final Widget child;
|
|
||||||
|
|
||||||
HiddenWebView({@required this.child, this.webView});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Stack(
|
|
||||||
children: <Widget>[
|
|
||||||
Offstage(
|
|
||||||
offstage: true,
|
|
||||||
child: webView,
|
|
||||||
),
|
|
||||||
Positioned.fill(child: child)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
226
lib/main.dart
|
@ -2,195 +2,73 @@ import 'dart:io' show Platform;
|
||||||
|
|
||||||
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/train_data.dart';
|
// import 'package:flutter_redux/flutter_redux.dart';
|
||||||
import 'package:info_tren/train_info_page/train_info.dart';
|
import 'package:info_tren/models/ui_design.dart';
|
||||||
import 'package:info_tren/train_info_page/train_info_cupertino.dart';
|
import 'package:info_tren/pages/main/main_page.dart';
|
||||||
import 'package:info_tren/train_info_page/train_info_material.dart';
|
import 'package:info_tren/pages/train_info_page/view_train/train_info.dart';
|
||||||
import 'package:info_tren/train_info_page/train_info_prompt.dart';
|
import 'package:info_tren/pages/train_info_page/select_train/select_train.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void main() => runApp(StartPoint());
|
void main() {
|
||||||
|
// final store = createStore();
|
||||||
|
// runApp(
|
||||||
|
// StoreProvider(
|
||||||
|
// store: store,
|
||||||
|
// child: StartPoint(),
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
runApp(
|
||||||
|
StartPoint(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, WidgetBuilder> routesByUiDesign(UiDesign uiDesign) => {
|
||||||
|
Navigator.defaultRouteName: (context) {
|
||||||
|
return MainPage(uiDesign: uiDesign,);
|
||||||
|
},
|
||||||
|
SelectTrainPage.routeName: (context) {
|
||||||
|
return SelectTrainPage(uiDesign: uiDesign);
|
||||||
|
},
|
||||||
|
TrainInfo.routeName: (context) {
|
||||||
|
return TrainInfo(
|
||||||
|
trainNumber: ModalRoute.of(context)!.settings.arguments as int,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
class StartPoint extends StatelessWidget {
|
class StartPoint extends StatelessWidget {
|
||||||
|
final String appTitle = 'Info Tren';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isIOS) {
|
||||||
|
return CupertinoApp(
|
||||||
|
title: appTitle,
|
||||||
|
theme: CupertinoThemeData(
|
||||||
|
primaryColor: Colors.blue.shade600,
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
// textTheme: CupertinoTextThemeData(
|
||||||
|
// textStyle: TextStyle(
|
||||||
|
// fontFamily: 'Atkinson Hyperlegible',
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
),
|
||||||
|
routes: routesByUiDesign(UiDesign.CUPERTINO),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'Info Tren',
|
title: appTitle,
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
primarySwatch: Colors.blue,
|
primarySwatch: Colors.blue,
|
||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
primaryColor: Colors.blue.shade600,
|
primaryColor: Colors.blue.shade600,
|
||||||
accentColor: Colors.blue.shade700,
|
accentColor: Colors.blue.shade700,
|
||||||
|
// fontFamily: 'Atkinson Hyperlegible',
|
||||||
),
|
),
|
||||||
// home: MainPageMaterial(),
|
routes: routesByUiDesign(UiDesign.MATERIAL),
|
||||||
routes: {
|
|
||||||
Navigator.defaultRouteName: (context) {
|
|
||||||
return MainPageMaterial();
|
|
||||||
},
|
|
||||||
TrainInfoPromptCommon.routeName: (context) {
|
|
||||||
return TrainInfoPromptMaterial();
|
|
||||||
},
|
|
||||||
TrainInfo.routeName: (context) {
|
|
||||||
return TrainDataWebViewAdapter(
|
|
||||||
builder: (context) {
|
|
||||||
return TrainInfoMaterial(
|
|
||||||
trainNumber: ModalRoute.of(context).settings.arguments as int,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (Platform.isIOS) {
|
|
||||||
return CupertinoApp(
|
|
||||||
title: "Info Tren",
|
|
||||||
theme: CupertinoThemeData(
|
|
||||||
primaryColor: Colors.blue.shade600,
|
|
||||||
brightness: Brightness.dark,
|
|
||||||
),
|
|
||||||
// home: MainPageCupertino(),
|
|
||||||
routes: {
|
|
||||||
Navigator.defaultRouteName: (context) {
|
|
||||||
return MainPageCupertino();
|
|
||||||
},
|
|
||||||
TrainInfoPromptCommon.routeName: (context) {
|
|
||||||
return TrainInfoPromptCupertino();
|
|
||||||
},
|
|
||||||
TrainInfo.routeName: (context) {
|
|
||||||
return TrainDataWebViewAdapter(
|
|
||||||
builder: (context) {
|
|
||||||
return TrainInfoCupertino(
|
|
||||||
trainNumber: ModalRoute.of(context).settings.arguments as int,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mixin MainPageAction {
|
|
||||||
onTrainInfoPageInvoke(BuildContext context) {
|
|
||||||
Navigator.of(context).pushNamed(TrainInfoPromptCommon.routeName);
|
|
||||||
}
|
|
||||||
|
|
||||||
onStationBoardPageInvoke(BuildContext context) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
onRoutePlanPageInvoke(BuildContext context) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MainPageMaterial extends StatelessWidget with MainPageAction {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text("Info Tren"),
|
|
||||||
centerTitle: true,
|
|
||||||
),
|
|
||||||
body: SafeArea(
|
|
||||||
child: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
ElevatedButton(
|
|
||||||
child: Text(
|
|
||||||
"Informații despre tren",
|
|
||||||
style: Theme.of(context).textTheme.button.copyWith(fontSize: 18),
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
onTrainInfoPageInvoke(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
child: Text(
|
|
||||||
"Tabelă plecari/sosiri",
|
|
||||||
style: Theme.of(context).textTheme.button.copyWith(fontSize: 18),
|
|
||||||
),
|
|
||||||
// TODO: Implement departure/arrival
|
|
||||||
onPressed: null,
|
|
||||||
// onPressed: () {
|
|
||||||
// onStationBoardPageInvoke(context);
|
|
||||||
// },
|
|
||||||
),
|
|
||||||
ElevatedButton(
|
|
||||||
child: Text(
|
|
||||||
"Planificare rută",
|
|
||||||
style: Theme.of(context).textTheme.button.copyWith(fontSize: 18),
|
|
||||||
),
|
|
||||||
// TODO: Implement route planning
|
|
||||||
onPressed: null,
|
|
||||||
// onPressed: () {
|
|
||||||
// onRoutePlanPageInvoke(context);
|
|
||||||
// },
|
|
||||||
)
|
|
||||||
].map((w) => Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(4, 2, 4, 2),
|
|
||||||
child: SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: w,
|
|
||||||
),
|
|
||||||
)).toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MainPageCupertino extends StatelessWidget with MainPageAction {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return CupertinoPageScaffold(
|
|
||||||
navigationBar: CupertinoNavigationBar(
|
|
||||||
middle: Text("Info Tren"),
|
|
||||||
),
|
|
||||||
child: SafeArea(
|
|
||||||
child: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
CupertinoButton.filled(
|
|
||||||
child: Text("Informații despre tren"),
|
|
||||||
onPressed: () {
|
|
||||||
onTrainInfoPageInvoke(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
CupertinoButton.filled(
|
|
||||||
child: Text("Tabelă plecari/sosiri"),
|
|
||||||
// TODO: Implement departure/arrival
|
|
||||||
onPressed: null,
|
|
||||||
// onPressed: () {
|
|
||||||
// onStationBoardPageInvoke(context);
|
|
||||||
// },
|
|
||||||
),
|
|
||||||
CupertinoButton.filled(
|
|
||||||
child: Text("Planificare rută"),
|
|
||||||
// TODO: Implement route planning
|
|
||||||
onPressed: null,
|
|
||||||
// onPressed: () {
|
|
||||||
// onRoutePlanPageInvoke(context);
|
|
||||||
// },
|
|
||||||
),
|
|
||||||
].map((w) => Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(4, 2, 4, 2),
|
|
||||||
child: SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: w,
|
|
||||||
),
|
|
||||||
)).toList(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'train_data.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// JsonSerializableGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
TrainData _$TrainDataFromJson(Map<String, dynamic> json) {
|
|
||||||
return TrainData(
|
|
||||||
rang: json['rang'] as String,
|
|
||||||
trainNumber: json['tren'] as String,
|
|
||||||
operator: json['operator'] as String,
|
|
||||||
lastInfo: json['ultima_informatie'] == null
|
|
||||||
? null
|
|
||||||
: LastInfo.fromJson(
|
|
||||||
json['ultima_informatie'] as Map<String, dynamic>),
|
|
||||||
state: json['stare'] as String,
|
|
||||||
route: json['relatia'] as String,
|
|
||||||
tripLength: json['durata_calatoriei'] as String,
|
|
||||||
stations: (json['stations'] as List)
|
|
||||||
?.map((e) => e == null
|
|
||||||
? null
|
|
||||||
: StationEntry.fromJson(e as Map<String, dynamic>))
|
|
||||||
?.toList(),
|
|
||||||
nextStop: json['urmatoarea_oprire'] == null
|
|
||||||
? null
|
|
||||||
: StopInfo.fromJson(
|
|
||||||
json['urmatoarea_oprire'] as Map<String, dynamic>),
|
|
||||||
distance: json['distanta'] as String,
|
|
||||||
destination: json['destinatie'] == null
|
|
||||||
? null
|
|
||||||
: StopInfo.fromJson(json['destinatie'] as Map<String, dynamic>));
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> _$TrainDataToJson(TrainData instance) => <String, dynamic>{
|
|
||||||
'rang': instance.rang,
|
|
||||||
'tren': instance.trainNumber,
|
|
||||||
'operator': instance.operator,
|
|
||||||
'relatia': instance.route,
|
|
||||||
'stare': instance.state,
|
|
||||||
'ultima_informatie': instance.lastInfo,
|
|
||||||
'destinatie': instance.destination,
|
|
||||||
'urmatoarea_oprire': instance.nextStop,
|
|
||||||
'durata_calatoriei': instance.tripLength,
|
|
||||||
'distanta': instance.distance,
|
|
||||||
'stations': instance.stations
|
|
||||||
};
|
|
||||||
|
|
||||||
LastInfo _$LastInfoFromJson(Map<String, dynamic> json) {
|
|
||||||
return LastInfo(
|
|
||||||
dateAndTime: json['data_si_ora'] as String,
|
|
||||||
delay: json['intarziere'] as int,
|
|
||||||
event: json['eveniment'] as String,
|
|
||||||
station: json['statia'] as String);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> _$LastInfoToJson(LastInfo instance) => <String, dynamic>{
|
|
||||||
'statia': instance.station,
|
|
||||||
'eveniment': instance.event,
|
|
||||||
'data_si_ora': instance.dateAndTime,
|
|
||||||
'intarziere': instance.delay
|
|
||||||
};
|
|
||||||
|
|
||||||
StopInfo _$StopInfoFromJson(Map<String, dynamic> json) {
|
|
||||||
return StopInfo(
|
|
||||||
station: json['statia'] as String,
|
|
||||||
dateAndTime: json['data_si_ora'] as String);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> _$StopInfoToJson(StopInfo instance) => <String, dynamic>{
|
|
||||||
'statia': instance.station,
|
|
||||||
'data_si_ora': instance.dateAndTime
|
|
||||||
};
|
|
||||||
|
|
||||||
StationEntry _$StationEntryFromJson(Map<String, dynamic> json) {
|
|
||||||
return StationEntry(
|
|
||||||
name: json['statia'] as String,
|
|
||||||
delay: json['intarziere'] as int,
|
|
||||||
realOrEstimate: json['real/estimat'] as String,
|
|
||||||
arrivalTime: json['sosire'] as String,
|
|
||||||
departureTime: json['plecare'] as String,
|
|
||||||
km: json['km'] as String,
|
|
||||||
observations: json['observatii'] as String,
|
|
||||||
waitTime: json['stationeaza_pentru'] as String);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> _$StationEntryToJson(StationEntry instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'km': instance.km,
|
|
||||||
'statia': instance.name,
|
|
||||||
'sosire': instance.arrivalTime,
|
|
||||||
'stationeaza_pentru': instance.waitTime,
|
|
||||||
'plecare': instance.departureTime,
|
|
||||||
'real/estimat': instance.realOrEstimate,
|
|
||||||
'intarziere': instance.delay,
|
|
||||||
'observatii': instance.observations
|
|
||||||
};
|
|
42
lib/models/train_operator_lines.dart
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
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);
|
||||||
|
}
|
42
lib/models/train_operator_lines.g.dart
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// 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/ui_design.dart
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
enum UiDesign {
|
||||||
|
MATERIAL,
|
||||||
|
CUPERTINO
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnmatchedUiDesignException implements Exception {
|
||||||
|
final UiDesign uiDesign;
|
||||||
|
|
||||||
|
UnmatchedUiDesignException(this.uiDesign);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '$uiDesign was not matched';
|
||||||
|
}
|
||||||
|
}
|
68
lib/pages/main/main_page.dart
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:info_tren/models/ui_design.dart';
|
||||||
|
import 'package:info_tren/pages/main/main_page_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/main/main_page_material.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/select_train/select_train.dart';
|
||||||
|
import 'package:info_tren/utils/default_ui_design.dart';
|
||||||
|
|
||||||
|
class MainPage extends StatelessWidget {
|
||||||
|
final UiDesign? uiDesign;
|
||||||
|
|
||||||
|
const MainPage({ Key? key, this.uiDesign }) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
||||||
|
|
||||||
|
switch (uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
return MainPageMaterial();
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
return MainPageCupertino();
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class MainPageShared extends StatelessWidget {
|
||||||
|
final String pageTitle = 'Info Tren';
|
||||||
|
|
||||||
|
List<MainPageOption> get options => [
|
||||||
|
MainPageOption(
|
||||||
|
name: 'Informații despre tren',
|
||||||
|
action: (BuildContext context) {
|
||||||
|
onTrainInfoPageInvoke(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
MainPageOption(
|
||||||
|
name: 'Tabelă plecari/sosiri',
|
||||||
|
// TODO: Implement departure/arrival
|
||||||
|
action: null,
|
||||||
|
),
|
||||||
|
MainPageOption(
|
||||||
|
name: 'Planificare rută',
|
||||||
|
// TODO: Implement route planning
|
||||||
|
action: null,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
onTrainInfoPageInvoke(BuildContext context) {
|
||||||
|
Navigator.of(context).pushNamed(SelectTrainPage.routeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
onStationBoardPageInvoke(BuildContext context) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onRoutePlanPageInvoke(BuildContext context) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainPageOption {
|
||||||
|
final String name;
|
||||||
|
final void Function(BuildContext context)? action;
|
||||||
|
|
||||||
|
MainPageOption({required this.name, this.action});
|
||||||
|
}
|
30
lib/pages/main/main_page_cupertino.dart
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/main/main_page.dart';
|
||||||
|
|
||||||
|
class MainPageCupertino extends MainPageShared {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CupertinoPageScaffold(
|
||||||
|
navigationBar: CupertinoNavigationBar(
|
||||||
|
middle: Text(pageTitle),
|
||||||
|
),
|
||||||
|
child: SafeArea(
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: options.map((option) => CupertinoButton.filled(
|
||||||
|
child: Text(option.name),
|
||||||
|
onPressed: option.action == null ? null : () => option.action!(context),
|
||||||
|
)).map((w) => Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(4, 2, 4, 2),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: w,
|
||||||
|
),
|
||||||
|
)).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
34
lib/pages/main/main_page_material.dart
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:info_tren/pages/main/main_page.dart';
|
||||||
|
|
||||||
|
class MainPageMaterial extends MainPageShared {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(pageTitle),
|
||||||
|
centerTitle: true,
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: options.map((option) => ElevatedButton(
|
||||||
|
child: Text(
|
||||||
|
option.name,
|
||||||
|
style: Theme.of(context).textTheme.button?.copyWith(fontSize: 18),
|
||||||
|
),
|
||||||
|
onPressed: option.action != null ? () => option.action!(context) : null,
|
||||||
|
)).map((w) => Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(4, 2, 4, 2),
|
||||||
|
child: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: w,
|
||||||
|
),
|
||||||
|
)).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
61
lib/pages/train_info_page/select_train/select_train.dart
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import 'dart:io' show Platform;
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/cupertino.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/pages/train_info_page/select_train/select_train_cupertino.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/utils/default_ui_design.dart';
|
||||||
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
|
typedef TrainSelectedCallback(int trainNumber);
|
||||||
|
|
||||||
|
class SelectTrainPage extends StatefulWidget {
|
||||||
|
final UiDesign? uiDesign;
|
||||||
|
|
||||||
|
SelectTrainPage({Key? key, this.uiDesign}) : super(key: key);
|
||||||
|
|
||||||
|
static String routeName = "/trainInfo/selectTrain";
|
||||||
|
|
||||||
|
void onTrainSelected(BuildContext context, int selection) {
|
||||||
|
Navigator.of(context).pushNamed(TrainInfo.routeName, arguments: selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
SelectTrainPageState createState() {
|
||||||
|
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
||||||
|
switch(uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
return SelectTrainPageStateMaterial();
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
return SelectTrainPageStateCupertino();
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class SelectTrainPageState extends State<SelectTrainPage> {
|
||||||
|
final String pageTitle = 'Informații despre tren';
|
||||||
|
final String textFieldLabel = 'Numărul trenului';
|
||||||
|
|
||||||
|
TextEditingController trainNoController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onTextChanged() {
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget get suggestionsList => SelectTrainSuggestions(
|
||||||
|
uiDesign: widget.uiDesign,
|
||||||
|
userInput: trainNoController.text,
|
||||||
|
onTrainSelected: (trainNumber) => widget.onTrainSelected(context, trainNumber),
|
||||||
|
key: ValueKey(trainNoController.text),
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/select_train/select_train.dart';
|
||||||
|
|
||||||
|
class SelectTrainPageStateCupertino extends SelectTrainPageState {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CupertinoPageScaffold(
|
||||||
|
navigationBar: CupertinoNavigationBar(
|
||||||
|
middle: Text(pageTitle),
|
||||||
|
),
|
||||||
|
child: SafeArea(
|
||||||
|
bottom: false,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: CupertinoTextField(
|
||||||
|
controller: trainNoController,
|
||||||
|
autofocus: true,
|
||||||
|
placeholder: textFieldLabel,
|
||||||
|
textInputAction: TextInputAction.search,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
onChanged: (_) => onTextChanged(),
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.digitsOnly,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: suggestionsList,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/select_train/select_train.dart';
|
||||||
|
|
||||||
|
class SelectTrainPageStateMaterial extends SelectTrainPageState {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(pageTitle),
|
||||||
|
centerTitle: true,
|
||||||
|
),
|
||||||
|
body: SafeArea(
|
||||||
|
bottom: false,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: TextField(
|
||||||
|
controller: trainNoController,
|
||||||
|
autofocus: true,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: textFieldLabel,
|
||||||
|
),
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.digitsOnly,
|
||||||
|
],
|
||||||
|
textInputAction: TextInputAction.search,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
onChanged: (_) => onTextChanged(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: suggestionsList,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:info_tren/train_info_page/train_info_constants.dart';
|
import 'package:info_tren/pages/train_info_page/train_info_constants.dart';
|
||||||
|
|
||||||
import 'dart:io' show Platform;
|
import 'dart:io' show Platform;
|
||||||
|
|
69
lib/pages/train_info_page/view_train/train_info.dart
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:info_tren/api/train_data.dart';
|
||||||
|
import 'package:info_tren/components/loading/loading.dart';
|
||||||
|
import 'package:info_tren/components/refresh_future_builder.dart';
|
||||||
|
import 'package:info_tren/models/train_data.dart';
|
||||||
|
import 'package:info_tren/models/ui_design.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/view_train/train_info_cupertino.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/view_train/train_info_material.dart';
|
||||||
|
import 'package:info_tren/utils/default_ui_design.dart';
|
||||||
|
|
||||||
|
|
||||||
|
class TrainInfo extends StatelessWidget {
|
||||||
|
static String routeName = "/trainInfo/display";
|
||||||
|
|
||||||
|
final UiDesign? uiDesign;
|
||||||
|
final int trainNumber;
|
||||||
|
|
||||||
|
TrainInfo({Key? key, required this.trainNumber, this.uiDesign}): super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final uiDesign = this.uiDesign ?? defaultUiDesign;
|
||||||
|
|
||||||
|
return RefreshFutureBuilder<TrainData>(
|
||||||
|
futureCreator: () => getTrain(trainNumber),
|
||||||
|
builder: (context, refresh, snapshot) {
|
||||||
|
|
||||||
|
switch (uiDesign) {
|
||||||
|
case UiDesign.MATERIAL:
|
||||||
|
if ([RefreshFutureBuilderState.none, RefreshFutureBuilderState.waiting].contains(snapshot.state)) {
|
||||||
|
return TrainInfoLoadingMaterial(title: trainNumber.toString(),);
|
||||||
|
}
|
||||||
|
else if (snapshot.state == RefreshFutureBuilderState.error) {
|
||||||
|
return TrainInfoErrorMaterial(title: '$trainNumber - Error', error: snapshot.error!,);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TrainInfoMaterial(trainData: snapshot.data!,);
|
||||||
|
case UiDesign.CUPERTINO:
|
||||||
|
if ([RefreshFutureBuilderState.none, RefreshFutureBuilderState.waiting].contains(snapshot.state)) {
|
||||||
|
return TrainInfoLoadingCupertino(title: trainNumber.toString(),);
|
||||||
|
}
|
||||||
|
else if (snapshot.state == RefreshFutureBuilderState.error) {
|
||||||
|
return TrainInfoErrorCupertino(title: '$trainNumber - Error', error: snapshot.error!,);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TrainInfoCupertino(trainData: snapshot.data!,);
|
||||||
|
default:
|
||||||
|
throw UnmatchedUiDesignException(uiDesign);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class TrainInfoLoading extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final Widget loadingWidget;
|
||||||
|
|
||||||
|
TrainInfoLoading({required this.title, String? loadingText, UiDesign? uiDesign}) : loadingWidget = Loading(uiDesign: uiDesign, text: loadingText,);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class TrainInfoError extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final Object error;
|
||||||
|
|
||||||
|
TrainInfoError({required this.title, required this.error});
|
||||||
|
}
|
741
lib/pages/train_info_page/view_train/train_info_cupertino.dart
Normal file
|
@ -0,0 +1,741 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:info_tren/components/cupertino_divider.dart';
|
||||||
|
import 'package:info_tren/models/train_data.dart' hide State;
|
||||||
|
import 'package:info_tren/models/ui_design.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/train_info_constants.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_cupertino_DisplayTrainStation.dart';
|
||||||
|
import 'package:info_tren/utils/state_to_string.dart';
|
||||||
|
|
||||||
|
class TrainInfoLoadingCupertino extends TrainInfoLoading {
|
||||||
|
TrainInfoLoadingCupertino({required String title, String? loadingText}) : super(title: title, loadingText: loadingText, uiDesign: UiDesign.CUPERTINO);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CupertinoPageScaffold(
|
||||||
|
navigationBar: CupertinoNavigationBar(
|
||||||
|
middle: Text(title),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: loadingWidget,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrainInfoErrorCupertino extends TrainInfoError {
|
||||||
|
TrainInfoErrorCupertino({required Object error, required String title,}) : super(error: error, title: title,);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CupertinoPageScaffold(
|
||||||
|
navigationBar: CupertinoNavigationBar(
|
||||||
|
middle: Text(title),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Text(error.toString()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrainInfoCupertino extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
TrainInfoCupertino({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return CupertinoPageScaffold(
|
||||||
|
navigationBar: CupertinoNavigationBar(
|
||||||
|
middle: Text("Informații despre ${trainData.rank} ${trainData.number}"),
|
||||||
|
),
|
||||||
|
child: SafeArea(
|
||||||
|
top: false,
|
||||||
|
bottom: false,
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final topPadding = MediaQuery.of(context).padding.top;
|
||||||
|
|
||||||
|
return CustomScrollView(
|
||||||
|
slivers: <Widget>[
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
top: topPadding,
|
||||||
|
),
|
||||||
|
child: Container(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DisplayTrainID(trainData: trainData,),
|
||||||
|
DisplayTrainOperator(trainData: trainData,),
|
||||||
|
DisplayTrainRoute(trainData: trainData,),
|
||||||
|
DisplayTrainDeparture(trainData: trainData,),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: CupertinoDivider(
|
||||||
|
color: FOREGROUND_WHITE,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DisplayTrainLastInfo(trainData: trainData,),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: CupertinoDivider(),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
// Expanded(
|
||||||
|
// child: DisplayTrainNextStop(trainData: trainData,),
|
||||||
|
// ),
|
||||||
|
Expanded(
|
||||||
|
child: DisplayTrainDestination(trainData: trainData,),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: double.infinity,
|
||||||
|
child: CupertinoVerticalDivider(),
|
||||||
|
),
|
||||||
|
Expanded(child: DisplayTrainRouteDistance(trainData: trainData,),),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: CupertinoDivider(),
|
||||||
|
// ),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: IntrinsicHeight(
|
||||||
|
// child: Row(
|
||||||
|
// children: <Widget>[
|
||||||
|
// // Expanded(
|
||||||
|
// // child: DisplayTrainRouteDuration(trainData: trainData,),
|
||||||
|
// // ),
|
||||||
|
// Expanded(child: Container(),),
|
||||||
|
// SizedBox(
|
||||||
|
// height: double.infinity,
|
||||||
|
// child: CupertinoVerticalDivider(),
|
||||||
|
// ),
|
||||||
|
// Expanded(
|
||||||
|
// child: DisplayTrainRouteDistance(trainData: trainData,),
|
||||||
|
// )
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: CupertinoDivider(
|
||||||
|
color: FOREGROUND_WHITE,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DisplayTrainStations(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
|
height: MediaQuery.of(context).viewPadding.bottom,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// return CupertinoPageScaffold(
|
||||||
|
// navigationBar: CupertinoNavigationBar(
|
||||||
|
// middle: Text(title ?? ""),
|
||||||
|
// ),
|
||||||
|
// child: SafeArea(
|
||||||
|
// bottom: false,
|
||||||
|
// child: FutureBuilder<OnDemandTrainData>(
|
||||||
|
// future: TrainDataWebViewAdapter.of(context).trainData(onInvalidation: () {
|
||||||
|
// Navigator.of(context).pop();
|
||||||
|
// }),
|
||||||
|
// builder: (context, snapshot) {
|
||||||
|
// if (!snapshot.hasData) {
|
||||||
|
// return Center(
|
||||||
|
// child: CupertinoActivityIndicator(),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// Future.wait([
|
||||||
|
// snapshot.data.rang,
|
||||||
|
// snapshot.data.trainNumber
|
||||||
|
// ]).then((values) {
|
||||||
|
// setState(() {
|
||||||
|
// title = "Informații despre ${values[0]} ${values[1]}";
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
// return CustomScrollView(
|
||||||
|
// slivers: <Widget>[
|
||||||
|
// DisplayTrainID(data: snapshot.data,),
|
||||||
|
// DisplayTrainOperator(data: snapshot.data,),
|
||||||
|
// DisplayTrainRoute(data: snapshot.data,),
|
||||||
|
// DisplayTrainDeparture(data: snapshot.data,),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: CupertinoDivider(
|
||||||
|
// color: FOREGROUND_WHITE,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// DisplayTrainLastInfo(data: snapshot.data,),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: CupertinoDivider(),
|
||||||
|
// ),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: IntrinsicHeight(
|
||||||
|
// child: Row(
|
||||||
|
// children: <Widget>[
|
||||||
|
// Expanded(
|
||||||
|
// child: DisplayTrainNextStop(data: snapshot.data,),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// height: double.infinity,
|
||||||
|
// child: CupertinoVerticalDivider(),
|
||||||
|
// ),
|
||||||
|
// Expanded(
|
||||||
|
// child: DisplayTrainDestination(data: snapshot.data,),
|
||||||
|
// )
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: CupertinoDivider(),
|
||||||
|
// ),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: IntrinsicHeight(
|
||||||
|
// child: Row(
|
||||||
|
// children: <Widget>[
|
||||||
|
// Expanded(
|
||||||
|
// child: DisplayTrainRouteDuration(data: snapshot.data,),
|
||||||
|
// ),
|
||||||
|
// SizedBox(
|
||||||
|
// height: double.infinity,
|
||||||
|
// child: CupertinoVerticalDivider(),
|
||||||
|
// ),
|
||||||
|
// Expanded(
|
||||||
|
// child: DisplayTrainRouteDistance(data: snapshot.data,),
|
||||||
|
// )
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: CupertinoDivider(
|
||||||
|
// color: FOREGROUND_WHITE,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// DisplayTrainStations(
|
||||||
|
// data: snapshot.data,
|
||||||
|
// pageLoadFuture: TrainDataWebViewAdapter.of(context).nextLoadFuture,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// on OnDemandInvalidatedException {
|
||||||
|
// Navigator.of(context).pop();
|
||||||
|
// print("Got OnDemandInvalidatedException!");
|
||||||
|
// return Container();
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainID extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
DisplayTrainID({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SliverToBoxAdapter(
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
"${trainData.rank} ${trainData.number}",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainRoute extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainRoute({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SliverToBoxAdapter(
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
trainData.route.from,
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
Center(child: Text("-")),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
trainData.route.to,
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainOperator extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainOperator({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SliverToBoxAdapter(
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
trainData.operator,
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 14,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainDeparture extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainDeparture({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SliverToBoxAdapter(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Text(
|
||||||
|
// "Plecare în ${dataPlecare.day.toString().padLeft(2, '0')}.${dataPlecare.month.toString().padLeft(2, '0')}.${dataPlecare.year.toString().padLeft(4, '0')}",
|
||||||
|
"Plecare în ${trainData.date}",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
fontWeight: FontWeight.w200,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainLastInfo extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainLastInfo({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (trainData.status == null) {
|
||||||
|
return SliverToBoxAdapter(child: Container(),);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SliverToBoxAdapter(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Text(
|
||||||
|
"Ultima informație",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
trainData.status!.station,
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle,
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
stateToString(trainData.status!.state),
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle,
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// FutureDisplay<DateTime>(
|
||||||
|
// future: trainData.lastInfo.dateAndTime,
|
||||||
|
// builder: (context, dt) {
|
||||||
|
// return Text(
|
||||||
|
// "Raportat în ${dt.day.toString().padLeft(2, '0')}.${dt.month.toString().padLeft(2, '0')}.${dt.year.toString().padLeft(4, '0')}, la ${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}",
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final data = trainData.status!.delay;
|
||||||
|
|
||||||
|
if (data == 0) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data > 0) {
|
||||||
|
return Text(
|
||||||
|
"$data minute întârziere",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 14,
|
||||||
|
color: CupertinoColors.destructiveRed,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Text(
|
||||||
|
"${-data} minute mai devreme",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 12,
|
||||||
|
color: CupertinoColors.activeGreen,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// class DisplayTrainNextStop extends StatelessWidget {
|
||||||
|
// final TrainData trainData;
|
||||||
|
//
|
||||||
|
// DisplayTrainNextStop({required this.trainData});
|
||||||
|
//
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// return FutureBuilder(
|
||||||
|
// future: trainData.nextStop.stationName,
|
||||||
|
// builder: (context, snapshot) {
|
||||||
|
// if (!snapshot.hasData) return Container();
|
||||||
|
//
|
||||||
|
// return Column(
|
||||||
|
// mainAxisSize: MainAxisSize.min,
|
||||||
|
// children: <Widget>[
|
||||||
|
// Padding(
|
||||||
|
// padding: const EdgeInsets.all(4),
|
||||||
|
// child: Text(
|
||||||
|
// "Următoarea oprire",
|
||||||
|
// style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
// fontSize: 20,
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// CupertinoDivider(
|
||||||
|
// color: Color.fromRGBO(15, 15, 15, 1),
|
||||||
|
// ),
|
||||||
|
// FutureDisplay(
|
||||||
|
// future: trainData.nextStop.stationName,
|
||||||
|
// builder: (context, station) {
|
||||||
|
// return Padding(
|
||||||
|
// padding: const EdgeInsets.fromLTRB(4, 0, 4, 0),
|
||||||
|
// child: Text(
|
||||||
|
// station,
|
||||||
|
// style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
// fontSize: 18,
|
||||||
|
// fontWeight: FontWeight.w500,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// FutureDisplay<DateTime>(
|
||||||
|
// future: trainData.nextStop.arrival,
|
||||||
|
// builder: (context, arrival) {
|
||||||
|
// const months = ["ian", "feb", "mar", "apr", "mai", "iun", "iul", "aug", "sep", "oct", "noi", "dec"];
|
||||||
|
//
|
||||||
|
// return Column(
|
||||||
|
// mainAxisSize: MainAxisSize.min,
|
||||||
|
// children: <Widget>[
|
||||||
|
// Text(
|
||||||
|
// "în ${arrival.day} ${months[arrival.month - 1]} ${arrival.year}",
|
||||||
|
// style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
// fontSize: 14,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// Text(
|
||||||
|
// "la ${arrival.hour.toString().padLeft(2, '0')}:${arrival.minute.toString().padLeft(2, '0')}",
|
||||||
|
// style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
// fontSize: 14,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// )
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
class DisplayTrainDestination extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainDestination({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
"Destinația",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
CupertinoDivider(
|
||||||
|
color: Color.fromRGBO(15, 15, 15, 1),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(4, 0, 4, 0),
|
||||||
|
child: Text(
|
||||||
|
trainData.stations.last.name,
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final arrival = trainData.stations.last.arrival!.scheduleTime;
|
||||||
|
final delay = trainData.stations.last.arrival!.status?.delay ?? 0;
|
||||||
|
final parts = arrival.split(':');
|
||||||
|
final arrivalDT = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, int.parse(parts[0]), int.parse(parts[1]));
|
||||||
|
final arrivalWithDelay = arrivalDT.add(Duration(minutes: delay));
|
||||||
|
final arrivalWithDelayString = '${arrivalWithDelay.hour}:${arrivalWithDelay.minute.toString().padLeft(2, "0")}';
|
||||||
|
// const months = ["ian", "feb", "mar", "apr", "mai", "iun", "iul", "aug", "sep", "oct", "noi", "dec"];
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
// Text(
|
||||||
|
// "în ${arrival.day} ${months[arrival.month - 1]} ${arrival.year}",
|
||||||
|
// style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
// fontSize: 14,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
Text.rich(
|
||||||
|
TextSpan(
|
||||||
|
text: 'la',
|
||||||
|
children: [
|
||||||
|
TextSpan(text: ' '),
|
||||||
|
TextSpan(
|
||||||
|
text: '$arrival',
|
||||||
|
style: delay == 0 ? null : TextStyle(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (delay != 0) ...[
|
||||||
|
TextSpan(text: ' '),
|
||||||
|
TextSpan(
|
||||||
|
text: '$arrivalWithDelayString',
|
||||||
|
style: TextStyle(
|
||||||
|
color: delay > 0 ? CupertinoColors.destructiveRed : CupertinoColors.activeGreen,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// "la ${arrival.hour.toString().padLeft(2, '0')}:${arrival.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainRouteDistance extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainRouteDistance({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"Distanța rutei",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${trainData.stations.last.km} km",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// class DisplayTrainRouteDuration extends StatelessWidget {
|
||||||
|
// final TrainData trainData;
|
||||||
|
//
|
||||||
|
// DisplayTrainRouteDuration({required this.trainData});
|
||||||
|
//
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// return Column(
|
||||||
|
// mainAxisSize: MainAxisSize.min,
|
||||||
|
// children: <Widget>[
|
||||||
|
// Text(
|
||||||
|
// "Durata rutei",
|
||||||
|
// style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
// fontSize: 18,
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// FutureDisplay<Duration>(
|
||||||
|
// future: trainData.routeDuration,
|
||||||
|
// builder: (context, duration) {
|
||||||
|
// var durationString = StringBuffer();
|
||||||
|
//
|
||||||
|
// bool firstWritten = false;
|
||||||
|
//
|
||||||
|
// if (duration.inDays > 0) {
|
||||||
|
// firstWritten = true;
|
||||||
|
// if (duration.inDays == 1) durationString.write("1 zi");
|
||||||
|
// else durationString.write("${duration.inDays} zile");
|
||||||
|
// duration -= Duration(days: duration.inDays);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (duration.inHours > 0) {
|
||||||
|
// if (firstWritten) {
|
||||||
|
// durationString.write(", ");
|
||||||
|
// }
|
||||||
|
// firstWritten = true;
|
||||||
|
// if (duration.inHours == 1) durationString.write("1 oră");
|
||||||
|
// else durationString.write("${duration.inHours} ore");
|
||||||
|
// duration -= Duration(hours: duration.inHours);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (duration.inMinutes > 0) {
|
||||||
|
// if (firstWritten) {
|
||||||
|
// durationString.write(", ");
|
||||||
|
// }
|
||||||
|
// firstWritten = true;
|
||||||
|
// if (duration.inMinutes == 1) durationString.write("1 minut");
|
||||||
|
// else durationString.write("${duration.inMinutes} minute");
|
||||||
|
// duration -= Duration(minutes: duration.inMinutes);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return Text(
|
||||||
|
// durationString.toString(),
|
||||||
|
// style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
// fontSize: 16,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
class DisplayTrainStations extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainStations({required this.trainData,});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
if (index.isOdd) {
|
||||||
|
return CupertinoDivider();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final itemIndex = index ~/ 2;
|
||||||
|
return IndexedSemantics(
|
||||||
|
child: DisplayTrainStation(
|
||||||
|
station: trainData.stations[itemIndex],
|
||||||
|
),
|
||||||
|
index: itemIndex,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
childCount: trainData.stations.length * 2 - 1,
|
||||||
|
addSemanticIndexes: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,466 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:info_tren/models/train_data.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/train_info_constants.dart';
|
||||||
|
|
||||||
|
class DisplayTrainStation extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
DisplayTrainStation({required this.station});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: <Widget>[
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final delay = station.departure?.status?.delay ?? station.arrival?.status?.delay;
|
||||||
|
final real = station.departure?.status?.real ?? station.arrival?.status?.real;
|
||||||
|
|
||||||
|
final isDelayed = delay != null && delay > 0 && real == true;
|
||||||
|
final isOnTime = delay != null && delay <= 0 && real == true;
|
||||||
|
final isNotScheduled = false;
|
||||||
|
|
||||||
|
return KmBadge(
|
||||||
|
station: station,
|
||||||
|
isNotScheduled: isNotScheduled,
|
||||||
|
isDelayed: isDelayed,
|
||||||
|
isOnTime: isOnTime,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Title(
|
||||||
|
station: station,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Time(
|
||||||
|
station: station,
|
||||||
|
),
|
||||||
|
Delay(
|
||||||
|
station: station,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KmBadge extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
final bool isNotScheduled;
|
||||||
|
final bool isOnTime;
|
||||||
|
final bool isDelayed;
|
||||||
|
|
||||||
|
KmBadge({
|
||||||
|
required this.station,
|
||||||
|
this.isNotScheduled = false,
|
||||||
|
this.isOnTime = false,
|
||||||
|
this.isDelayed = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Color foregroundColor = FOREGROUND_WHITE;
|
||||||
|
Color? backgroundColor;
|
||||||
|
|
||||||
|
if (isNotScheduled) {
|
||||||
|
foregroundColor = Color.fromRGBO(225, 175, 30, 1);
|
||||||
|
backgroundColor = Color.fromRGBO(80, 40, 10, 1);
|
||||||
|
}
|
||||||
|
else if (isOnTime) {
|
||||||
|
foregroundColor = Color.fromRGBO(130, 175, 65, 1);
|
||||||
|
backgroundColor = Color.fromRGBO(40, 80, 10, 1);
|
||||||
|
}
|
||||||
|
else if (isDelayed) {
|
||||||
|
foregroundColor = Color.fromRGBO(225, 75, 30, 1);
|
||||||
|
backgroundColor = 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(
|
||||||
|
station.km.toString(),
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w400 : FontWeight.w200,
|
||||||
|
color: MediaQuery.of(context).boldText ? FOREGROUND_WHITE : foregroundColor,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"km",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 10,
|
||||||
|
color: MediaQuery.of(context).boldText ? FOREGROUND_WHITE : foregroundColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Title extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
Title({
|
||||||
|
required this.station
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Text(
|
||||||
|
station.name,
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w500 : FontWeight.w300,
|
||||||
|
// fontStyle: items[1] == "ONI" ? FontStyle.italic : FontStyle.normal,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Time extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
Time({
|
||||||
|
required this.station,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (station.arrival == null) {
|
||||||
|
// Plecare
|
||||||
|
return DepartureTime(
|
||||||
|
station: station,
|
||||||
|
firstStation: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (station.departure == null) {
|
||||||
|
// Sosire
|
||||||
|
return ArrivalTime(
|
||||||
|
station: station,
|
||||||
|
finalStation: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"→",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(width: 2,),
|
||||||
|
ArrivalTime(station: station,),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
StopTime(station: station,),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
DepartureTime(station: station,),
|
||||||
|
Container(width: 2,),
|
||||||
|
Text(
|
||||||
|
"→",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArrivalTime extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
final bool finalStation;
|
||||||
|
|
||||||
|
ArrivalTime({
|
||||||
|
required this.station,
|
||||||
|
this.finalStation = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (finalStation) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"→",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(width: 2,),
|
||||||
|
Text("sosire la "),
|
||||||
|
ArrivalTime(station: station,),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final delay = station.arrival!.status?.delay ?? 0;
|
||||||
|
final time = station.arrival!.scheduleTime;
|
||||||
|
|
||||||
|
if (delay == 0) {
|
||||||
|
return Text("$time");
|
||||||
|
}
|
||||||
|
else if (delay > 0) {
|
||||||
|
final splits = time.split(":").map((s) => int.parse(s)).toList();
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
final oldDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
||||||
|
final newDate = oldDate.add(Duration(minutes: delay));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
color: CupertinoColors.destructiveRed,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final splits = time.split(":").map((s) => int.parse(s)).toList();
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
final oldDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
||||||
|
final newDate = oldDate.subtract(Duration(minutes: delay));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
color: CupertinoColors.activeGreen,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StopTime extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
StopTime({
|
||||||
|
required this.station,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final stopsFor = station.stoppingTime!;
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"staționează pentru",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
int stopsForInt = stopsFor;
|
||||||
|
if (stopsForInt == 1) {
|
||||||
|
return Text(
|
||||||
|
"1 minut",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (stopsForInt < 20) {
|
||||||
|
return Text(
|
||||||
|
"$stopsFor minute",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Text(
|
||||||
|
"$stopsFor de minute",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DepartureTime extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
final bool firstStation;
|
||||||
|
|
||||||
|
DepartureTime({
|
||||||
|
required this.station,
|
||||||
|
this.firstStation = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (firstStation) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
Text("plecare la "),
|
||||||
|
DepartureTime(station: station,),
|
||||||
|
Container(width: 2,),
|
||||||
|
Text(
|
||||||
|
"→",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final delay = station.departure!.status?.delay ?? 0;
|
||||||
|
final time = station.departure!.scheduleTime;
|
||||||
|
|
||||||
|
if (delay == 0) {
|
||||||
|
return Text("$time");
|
||||||
|
}
|
||||||
|
else if (delay > 0) {
|
||||||
|
final splits = time.split(":").map((s) => int.parse(s)).toList();
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
final oldDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
||||||
|
final newDate = oldDate.add(Duration(minutes: delay));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
color: CupertinoColors.destructiveRed,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final splits = time.split(":").map((s) => int.parse(s)).toList();
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
final oldDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
||||||
|
final newDate = oldDate.subtract(Duration(minutes: delay));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
color: CupertinoColors.activeGreen,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Delay extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
Delay({
|
||||||
|
required this.station,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (station.arrival?.status == null && station.departure?.status == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
var delay = station.arrival?.status?.delay;
|
||||||
|
if (station.departure?.status?.real == true) {
|
||||||
|
delay = station.departure?.status?.delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delay == 0 || delay == null) return Container();
|
||||||
|
else if (delay > 0) {
|
||||||
|
return Text(
|
||||||
|
"$delay minute întârziere",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
color: CupertinoColors.destructiveRed,
|
||||||
|
fontSize: 14,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (delay < 0) {
|
||||||
|
return Text(
|
||||||
|
"${-delay} minute mai devreme",
|
||||||
|
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
||||||
|
color: CupertinoColors.activeGreen,
|
||||||
|
fontSize: 14,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
659
lib/pages/train_info_page/view_train/train_info_material.dart
Normal file
|
@ -0,0 +1,659 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:info_tren/components/slim_app_bar.dart';
|
||||||
|
import 'package:info_tren/models/train_data.dart' hide State;
|
||||||
|
import 'package:info_tren/models/ui_design.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_material_DisplayTrainStation.dart';
|
||||||
|
import 'package:info_tren/utils/state_to_string.dart';
|
||||||
|
|
||||||
|
class TrainInfoLoadingMaterial extends TrainInfoLoading {
|
||||||
|
TrainInfoLoadingMaterial({required String title, String? loadingText}) : super(title: title, loadingText: loadingText, uiDesign: UiDesign.MATERIAL);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(title),
|
||||||
|
),
|
||||||
|
body: Center(
|
||||||
|
child: loadingWidget,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrainInfoErrorMaterial extends TrainInfoError {
|
||||||
|
TrainInfoErrorMaterial({required Object error, required String title,}) : super(error: error, title: title,);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text(title),
|
||||||
|
),
|
||||||
|
body: Center(
|
||||||
|
child: Text(error.toString()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSmallScreen(BuildContext context) => MediaQuery.of(context).size.height <= 425;
|
||||||
|
|
||||||
|
class TrainInfoMaterial extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
TrainInfoMaterial({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Builder(
|
||||||
|
builder: (context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: isSmallScreen(context) ? null : AppBar(
|
||||||
|
centerTitle: true,
|
||||||
|
title: Text("Informații despre ${trainData.rank} ${trainData.number}"),
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
if (isSmallScreen(context))
|
||||||
|
SlimAppBar(
|
||||||
|
title: 'INFO TREN - ${trainData.rank} ${trainData.number}'
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: SafeArea(
|
||||||
|
bottom: false,
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: <Widget>[
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainID(trainData: trainData,),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainOperator(trainData: trainData,),
|
||||||
|
),
|
||||||
|
SliverPadding(
|
||||||
|
padding: const EdgeInsets.only(left: 2, right: 2),
|
||||||
|
sliver: SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainRoute(trainData: trainData,),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainDeparture(trainData: trainData,),
|
||||||
|
),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: Divider(
|
||||||
|
// color: Colors.white70,
|
||||||
|
// height: isSmallScreen(context) ? 8 : 16,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DisplayTrainLastInfo(trainData: trainData,),
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: IntrinsicHeight(
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
// Expanded(child: DisplayTrainNextStop(trainData: trainData,)),
|
||||||
|
Expanded(child: DisplayTrainDestination(trainData: trainData,)),
|
||||||
|
Expanded(child: DisplayTrainRouteDistance(trainData: trainData,),),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// SliverToBoxAdapter(
|
||||||
|
// child: IntrinsicHeight(
|
||||||
|
// child: Row(
|
||||||
|
// children: <Widget>[
|
||||||
|
// // Expanded(child: DisplayTrainRouteDuration(trainData: trainData,)),
|
||||||
|
// Expanded(child: Container(),),
|
||||||
|
// Expanded(child: DisplayTrainRouteDistance(trainData: trainData,)),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Divider(
|
||||||
|
color: Colors.white70,
|
||||||
|
height: isSmallScreen(context) ? 8 : 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DisplayTrainStations(
|
||||||
|
trainData: trainData,
|
||||||
|
),
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Container(
|
||||||
|
height: MediaQuery.of(context).viewPadding.bottom,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainID extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainID({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Text(
|
||||||
|
"${trainData.rank} ${trainData.number}",
|
||||||
|
style: (isSmallScreen(context)
|
||||||
|
? Theme.of(context).textTheme.headline4
|
||||||
|
: Theme.of(context).textTheme.headline3)?.copyWith(
|
||||||
|
color: Theme.of(context).textTheme.bodyText2?.color,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainOperator extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainOperator({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Text(
|
||||||
|
trainData.operator,
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
fontSize: isSmallScreen(context) ? 12 : 14,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainRoute extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainRoute({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
trainData.route.from,
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
Center(child: Text("-")),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
trainData.route.to,
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainDeparture extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainDeparture({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Text(
|
||||||
|
// "Plecare în ${dataPlecare.day.toString().padLeft(2, '0')}.${dataPlecare.month.toString().padLeft(2, '0')}.${dataPlecare.year.toString().padLeft(4, '0')}",
|
||||||
|
"Plecare în ${trainData.date}",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
fontWeight: FontWeight.w200,
|
||||||
|
fontSize: isSmallScreen(context) ? 14 : 16,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainLastInfo extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainLastInfo({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (trainData.status == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Card(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Text(
|
||||||
|
"Ultima informație",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 20 : 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
trainData.status!.station,
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 16 : 18,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
stateToString(trainData.status!.state),
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 16 : 18,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Row(
|
||||||
|
children: <Widget>[
|
||||||
|
// FutureDisplay<DateTime>(
|
||||||
|
// future: trainData.lastInfo.dateAndTime,
|
||||||
|
// builder: (context, dt) {
|
||||||
|
// return Text(
|
||||||
|
// "Raportat în ${dt.day.toString().padLeft(2, '0')}.${dt.month.toString().padLeft(2, '0')}.${dt.year.toString().padLeft(4, '0')}, la ${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}",
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final data = trainData.status!.delay;
|
||||||
|
if (data == 0) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data > 0) {
|
||||||
|
return Text(
|
||||||
|
"$data minute întârziere",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 14 : 16,
|
||||||
|
color: Colors.red.shade300,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Text(
|
||||||
|
"${-data} minute mai devreme",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 14 : 16,
|
||||||
|
color: Colors.green.shade300,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// class DisplayTrainNextStop extends StatelessWidget {
|
||||||
|
// final OnDemandTrainData trainData;
|
||||||
|
//
|
||||||
|
// DisplayTrainNextStop({@required this.trainData});
|
||||||
|
//
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// return FutureBuilder(
|
||||||
|
// future: trainData.nextStop.stationName,
|
||||||
|
// builder: (context, snapshot) {
|
||||||
|
// if (!snapshot.hasData) return Container(height: 0,);
|
||||||
|
//
|
||||||
|
// return Card(
|
||||||
|
// child: Center(
|
||||||
|
// child: Padding(
|
||||||
|
// padding: const EdgeInsets.all(2),
|
||||||
|
// child: Column(
|
||||||
|
// mainAxisSize: MainAxisSize.min,
|
||||||
|
// children: <Widget>[
|
||||||
|
// Padding(
|
||||||
|
// padding: const EdgeInsets.all(4),
|
||||||
|
// child: Text(
|
||||||
|
// "Următoarea oprire",
|
||||||
|
// style: Theme.of(context).textTheme.bodyText2.copyWith(
|
||||||
|
// fontSize: isSmallScreen(context) ? 18 : 20,
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// FutureDisplay(
|
||||||
|
// future: trainData.nextStop.stationName,
|
||||||
|
// builder: (context, station) {
|
||||||
|
// return Padding(
|
||||||
|
// padding: const EdgeInsets.fromLTRB(4, 0, 4, 0),
|
||||||
|
// child: Text(
|
||||||
|
// station,
|
||||||
|
// style: Theme.of(context).textTheme.bodyText2.copyWith(
|
||||||
|
// fontSize: isSmallScreen(context) ? 16 : 18,
|
||||||
|
// fontWeight: FontWeight.w500,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// FutureDisplay<DateTime>(
|
||||||
|
// future: trainData.nextStop.arrival,
|
||||||
|
// builder: (context, arrival) {
|
||||||
|
// const months = ["ian", "feb", "mar", "apr", "mai", "iun", "iul", "aug", "sep", "oct", "noi", "dec"];
|
||||||
|
//
|
||||||
|
// return Column(
|
||||||
|
// mainAxisSize: MainAxisSize.min,
|
||||||
|
// children: <Widget>[
|
||||||
|
// Text(
|
||||||
|
// "în ${arrival.day} ${months[arrival.month - 1]} ${arrival.year}",
|
||||||
|
// style: Theme.of(context).textTheme.bodyText2.copyWith(
|
||||||
|
// fontSize: isSmallScreen(context) ? 12 : 14,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// Text(
|
||||||
|
// "la ${arrival.hour.toString().padLeft(2, '0')}:${arrival.minute.toString().padLeft(2, '0')}",
|
||||||
|
// style: Theme.of(context).textTheme.bodyText2.copyWith(
|
||||||
|
// fontSize: isSmallScreen(context) ? 12 : 14,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// )
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
class DisplayTrainDestination extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainDestination({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final destination = trainData.stations.last;
|
||||||
|
|
||||||
|
return Card(
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
child: Text(
|
||||||
|
"Destinația",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 20 : 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(4, 0, 4, 0),
|
||||||
|
child: Text(
|
||||||
|
destination.name,
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 18 : 20,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final arrival = destination.arrival!.scheduleTime;
|
||||||
|
final delay = trainData.stations.last.arrival!.status?.delay ?? 0;
|
||||||
|
final parts = arrival.split(':');
|
||||||
|
final arrivalDT = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day, int.parse(parts[0]), int.parse(parts[1]));
|
||||||
|
final arrivalWithDelay = arrivalDT.add(Duration(minutes: delay));
|
||||||
|
final arrivalWithDelayString = '${arrivalWithDelay.hour}:${arrivalWithDelay.minute.toString().padLeft(2, "0")}';
|
||||||
|
// const months = ["ian", "feb", "mar", "apr", "mai", "iun", "iul", "aug", "sep", "oct", "noi", "dec"];
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
// Text(
|
||||||
|
// "în ${arrival.day} ${months[arrival.month - 1]} ${arrival.year}",
|
||||||
|
// style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
// fontSize: isSmallScreen(context) ? 12 : 14,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
Text.rich(
|
||||||
|
// "la ${arrival.hour.toString().padLeft(2, '0')}:${arrival.minute.toString().padLeft(2, '0')}",
|
||||||
|
TextSpan(
|
||||||
|
text: 'la',
|
||||||
|
children: [
|
||||||
|
TextSpan(text: ' '),
|
||||||
|
TextSpan(
|
||||||
|
text: '$arrival',
|
||||||
|
style: delay == 0 ? null : TextStyle(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (delay != 0) ...[
|
||||||
|
TextSpan(text: ' '),
|
||||||
|
TextSpan(
|
||||||
|
text: '$arrivalWithDelayString',
|
||||||
|
style: TextStyle(
|
||||||
|
color: delay > 0 ? Colors.red.shade300 : Colors.green.shade300,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
),
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 14 : 16,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayTrainRouteDistance extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainRouteDistance({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"Distanța rutei",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 20 : 22,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${trainData.stations.last.km} km",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 18 : 20,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// class DisplayTrainRouteDuration extends StatelessWidget {
|
||||||
|
// final TrainData trainData;
|
||||||
|
//
|
||||||
|
// DisplayTrainRouteDuration({required this.trainData});
|
||||||
|
//
|
||||||
|
// @override
|
||||||
|
// Widget build(BuildContext context) {
|
||||||
|
// return Card(
|
||||||
|
// child: Center(
|
||||||
|
// child: Padding(
|
||||||
|
// padding: const EdgeInsets.all(2),
|
||||||
|
// child: Column(
|
||||||
|
// mainAxisSize: MainAxisSize.min,
|
||||||
|
// children: <Widget>[
|
||||||
|
// Text(
|
||||||
|
// "Durata rutei",
|
||||||
|
// style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
// fontSize: isSmallScreen(context) ? 16 : 18,
|
||||||
|
// fontWeight: FontWeight.bold,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// ),
|
||||||
|
// FutureDisplay<Duration>(
|
||||||
|
// future: trainData.routeDuration,
|
||||||
|
// builder: (context, duration) {
|
||||||
|
// var durationString = StringBuffer();
|
||||||
|
//
|
||||||
|
// bool firstWritten = false;
|
||||||
|
//
|
||||||
|
// if (duration.inDays > 0) {
|
||||||
|
// firstWritten = true;
|
||||||
|
// if (duration.inDays == 1) durationString.write("1 zi");
|
||||||
|
// else durationString.write("${duration.inDays} zile");
|
||||||
|
// duration -= Duration(days: duration.inDays);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (duration.inHours > 0) {
|
||||||
|
// if (firstWritten) {
|
||||||
|
// durationString.write(", ");
|
||||||
|
// }
|
||||||
|
// firstWritten = true;
|
||||||
|
// if (duration.inHours == 1) durationString.write("1 oră");
|
||||||
|
// else durationString.write("${duration.inHours} ore");
|
||||||
|
// duration -= Duration(hours: duration.inHours);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (duration.inMinutes > 0) {
|
||||||
|
// if (firstWritten) {
|
||||||
|
// durationString.write(", ");
|
||||||
|
// }
|
||||||
|
// firstWritten = true;
|
||||||
|
// if (duration.inMinutes == 1) durationString.write("1 minut");
|
||||||
|
// else durationString.write("${duration.inMinutes} minute");
|
||||||
|
// duration -= Duration(minutes: duration.inMinutes);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return Text(
|
||||||
|
// durationString.toString(),
|
||||||
|
// style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
// fontSize: isSmallScreen(context) ? 14 : 16,
|
||||||
|
// ),
|
||||||
|
// textAlign: TextAlign.center,
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
class DisplayTrainStations extends StatelessWidget {
|
||||||
|
final TrainData trainData;
|
||||||
|
|
||||||
|
DisplayTrainStations({required this.trainData});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SliverList(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
return IndexedSemantics(
|
||||||
|
child: DisplayTrainStation(
|
||||||
|
station: trainData.stations[index],
|
||||||
|
),
|
||||||
|
index: index,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
childCount: trainData.stations.length,
|
||||||
|
addSemanticIndexes: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,476 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:info_tren/models/train_data.dart';
|
||||||
|
import 'package:info_tren/pages/train_info_page/view_train/train_info_material.dart' show isSmallScreen;
|
||||||
|
|
||||||
|
class DisplayTrainStation extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
DisplayTrainStation({required this.station});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Card(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(2),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: <Widget>[
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final delay = station.departure?.status?.delay ?? station.arrival?.status?.delay;
|
||||||
|
final real = station.departure?.status?.real ?? station.arrival?.status?.real;
|
||||||
|
|
||||||
|
final isDelayed = delay != null && delay > 0 && real == true;
|
||||||
|
final isOnTime = delay != null && delay <= 0 && real == true;
|
||||||
|
final isNotScheduled = false;
|
||||||
|
|
||||||
|
return KmBadge(
|
||||||
|
station: station,
|
||||||
|
isNotScheduled: isNotScheduled,
|
||||||
|
isDelayed: isDelayed,
|
||||||
|
isOnTime: isOnTime,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Title(
|
||||||
|
station: station,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Time(
|
||||||
|
station: station,
|
||||||
|
),
|
||||||
|
Delay(
|
||||||
|
station: station,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KmBadge extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
final bool isNotScheduled;
|
||||||
|
final bool isOnTime;
|
||||||
|
final bool isDelayed;
|
||||||
|
|
||||||
|
KmBadge({
|
||||||
|
required this.station,
|
||||||
|
this.isNotScheduled = false,
|
||||||
|
this.isOnTime = false,
|
||||||
|
this.isDelayed = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@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(
|
||||||
|
station.km.toString(),
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.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(
|
||||||
|
"km",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: 10,
|
||||||
|
color: MediaQuery.of(context).boldText ? Colors.white70 : foregroundColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Title extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
Title({
|
||||||
|
required this.station
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Text(
|
||||||
|
station.name,
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 18 : 22,
|
||||||
|
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w500 : FontWeight.w300,
|
||||||
|
// fontStyle: items[1] == "ONI" ? FontStyle.italic : FontStyle.normal,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Time extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
Time({
|
||||||
|
required this.station,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (station.arrival == null) {
|
||||||
|
// Plecare
|
||||||
|
return DepartureTime(
|
||||||
|
station: station,
|
||||||
|
firstStation: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (station.departure == null) {
|
||||||
|
// Sosire
|
||||||
|
return ArrivalTime(
|
||||||
|
station: station,
|
||||||
|
finalStation: true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"→",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 18 : 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(width: 2,),
|
||||||
|
ArrivalTime(station: station,),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
StopTime(station: station,),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
DepartureTime(station: station,),
|
||||||
|
Container(width: 2,),
|
||||||
|
Text(
|
||||||
|
"→",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 18 : 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArrivalTime extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
final bool finalStation;
|
||||||
|
|
||||||
|
ArrivalTime({
|
||||||
|
required this.station,
|
||||||
|
this.finalStation = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (station.arrival == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
if (finalStation) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"→",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: isSmallScreen(context) ? 18 : 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(width: 2,),
|
||||||
|
Text("sosire la "),
|
||||||
|
ArrivalTime(station: station,),
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final delay = station.arrival!.status?.delay ?? 0;
|
||||||
|
final time = station.arrival!.scheduleTime;
|
||||||
|
|
||||||
|
if (delay == 0) {
|
||||||
|
return Text("$time");
|
||||||
|
}
|
||||||
|
else if (delay > 0) {
|
||||||
|
final splits = time.split(":").map((s) => int.parse(s)).toList();
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
final oldDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
||||||
|
final newDate = oldDate.add(Duration(minutes: delay));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
color: Colors.red.shade300,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final splits = time.split(":").map((s) => int.parse(s)).toList();
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
final oldDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
||||||
|
final newDate = oldDate.add(Duration(minutes: delay));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
color: Colors.green.shade300,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StopTime extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
StopTime({
|
||||||
|
required this.station,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"staționează pentru",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
int stopsForInt = station.stoppingTime!;
|
||||||
|
if (stopsForInt == 1) {
|
||||||
|
return Text(
|
||||||
|
"1 minut",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (stopsForInt < 20) {
|
||||||
|
return Text(
|
||||||
|
"${station.stoppingTime} minute",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Text(
|
||||||
|
"${station.stoppingTime} de minute",
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DepartureTime extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
final bool firstStation;
|
||||||
|
|
||||||
|
DepartureTime({
|
||||||
|
required this.station,
|
||||||
|
this.firstStation = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (station.departure == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
if (firstStation) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Expanded(child: Container(),),
|
||||||
|
Text("plecare la "),
|
||||||
|
DepartureTime(station: station,),
|
||||||
|
Container(width: 2,),
|
||||||
|
Text(
|
||||||
|
"→",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
fontSize: 22,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final delay = station.departure!.status?.delay ?? 0;
|
||||||
|
final time = station.departure!.scheduleTime;
|
||||||
|
|
||||||
|
if (delay == 0) {
|
||||||
|
return Text("$time");
|
||||||
|
}
|
||||||
|
else if (delay > 0) {
|
||||||
|
final splits = time.split(":").map((s) => int.parse(s)).toList();
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
final oldDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
||||||
|
final newDate = oldDate.add(Duration(minutes: delay));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
color: Colors.red.shade300,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final splits = time.split(":").map((s) => int.parse(s)).toList();
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
final oldDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
||||||
|
final newDate = oldDate.add(Duration(minutes: delay));
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${newDate.hour.toString().padLeft(2, '0')}:${newDate.minute.toString().padLeft(2, '0')}",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
color: Colors.green.shade300,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Delay extends StatelessWidget {
|
||||||
|
final Station station;
|
||||||
|
|
||||||
|
Delay({
|
||||||
|
required this.station,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (station.arrival?.status == null && station.departure?.status == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
var delay = station.arrival?.status?.delay;
|
||||||
|
if (station.departure?.status?.real == true) {
|
||||||
|
delay = station.departure?.status?.delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delay == 0 || delay == null) return Container();
|
||||||
|
else if (delay > 0) {
|
||||||
|
return Text(
|
||||||
|
"$delay minute întârziere",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
color: Colors.red.shade300,
|
||||||
|
fontSize: 14,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (delay < 0) {
|
||||||
|
return Text(
|
||||||
|
"${-delay} minute mai devreme",
|
||||||
|
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||||
|
color: Colors.green.shade300,
|
||||||
|
fontSize: 14,
|
||||||
|
fontStyle: FontStyle.italic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,7 +40,7 @@ enum NotchStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
class StopListLine extends StatelessWidget {
|
class StopListLine extends StatelessWidget {
|
||||||
final StationEntry station;
|
final Station station;
|
||||||
final int width;
|
final int width;
|
||||||
StopListLine(this.station, {this.width = 32}) : assert(width.isEven);
|
StopListLine(this.station, {this.width = 32}) : assert(width.isEven);
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ class StopListLinePainter extends CustomPainter {
|
||||||
}
|
}
|
||||||
|
|
||||||
class StopOnLineDetails extends StatelessWidget {
|
class StopOnLineDetails extends StatelessWidget {
|
||||||
final StationEntry station;
|
final Station station;
|
||||||
StopOnLineDetails(this.station);
|
StopOnLineDetails(this.station);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -172,11 +172,11 @@ class StopOnLineDetails extends StatelessWidget {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (station.observations == "ONI")
|
// if (station.observations == "ONI")
|
||||||
Padding(
|
// Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(8.0, 0.0, 8.0, 0.5),
|
// padding: const EdgeInsets.fromLTRB(8.0, 0.0, 8.0, 0.5),
|
||||||
child: Text("oprire ne-itinerarică", style: Theme.of(context).textTheme.bodyText2.copyWith(color: Colors.red.shade700),),
|
// child: Text("oprire ne-itinerarică", style: Theme.of(context).textTheme.bodyText2.copyWith(color: Colors.red.shade700),),
|
||||||
),
|
// ),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(8.0, 0.5, 8.0, 8.0),
|
padding: const EdgeInsets.fromLTRB(8.0, 0.5, 8.0, 8.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -186,11 +186,12 @@ class StopOnLineDetails extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
StopOnLineTimeDetails(station),
|
StopOnLineTimeDetails(station),
|
||||||
if (station.real)
|
// TODO: Figure out how to display delay info
|
||||||
Padding(
|
// if (station.arrival != null && station.arrival.status != null || station.departure != null && station.departure.status != null)
|
||||||
padding: const EdgeInsets.all(2.0),
|
// Padding(
|
||||||
child: StopOnLineDelayDetails(station),
|
// padding: const EdgeInsets.all(2.0),
|
||||||
),
|
// child: StopOnLineDelayDetails(station),
|
||||||
|
// ),
|
||||||
Divider(
|
Divider(
|
||||||
height: 0,
|
height: 0,
|
||||||
),
|
),
|
||||||
|
@ -201,14 +202,14 @@ class StopOnLineDetails extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class StopOnLineTimeDetails extends StatelessWidget {
|
class StopOnLineTimeDetails extends StatelessWidget {
|
||||||
final StationEntry station;
|
final Station station;
|
||||||
StopOnLineTimeDetails(this.station);
|
StopOnLineTimeDetails(this.station);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
if (station.arrivalTime.isNotEmpty)
|
if (station.arrival != null)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(4.0),
|
padding: const EdgeInsets.all(4.0),
|
||||||
child: Align(
|
child: Align(
|
||||||
|
@ -221,14 +222,14 @@ class StopOnLineTimeDetails extends StatelessWidget {
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
station.arrivalTime,
|
station.arrival.scheduleTime,
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (station.waitTime.isNotEmpty)
|
if (station.stoppingTime != null)
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(4.0),
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
@ -242,7 +243,7 @@ class StopOnLineTimeDetails extends StatelessWidget {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"${station.waitTime} ${station.waitTime == "1" ? "minut" : "minute"}",
|
"${station.stoppingTime} ${station.stoppingTime == 1 ? "minut" : "minute"}",
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -252,7 +253,7 @@ class StopOnLineTimeDetails extends StatelessWidget {
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
Expanded(child: Container(),),
|
Expanded(child: Container(),),
|
||||||
if (station.departureTime.isNotEmpty)
|
if (station.departure != null)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(4.0),
|
padding: const EdgeInsets.all(4.0),
|
||||||
child: Align(
|
child: Align(
|
||||||
|
@ -265,7 +266,7 @@ class StopOnLineTimeDetails extends StatelessWidget {
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
station.departureTime,
|
station.departure.scheduleTime,
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -277,32 +278,32 @@ class StopOnLineTimeDetails extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StopOnLineDelayDetails extends StatelessWidget {
|
// class StopOnLineDelayDetails extends StatelessWidget {
|
||||||
final StationEntry station;
|
// final Station station;
|
||||||
StopOnLineDelayDetails(this.station);
|
// StopOnLineDelayDetails(this.station);
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Widget build(BuildContext context) {
|
// Widget build(BuildContext context) {
|
||||||
if (station.delay == 0) {
|
// if (station.delay == 0) {
|
||||||
return Text(
|
// return Text(
|
||||||
"Fără întârziere",
|
// "Fără întârziere",
|
||||||
style: Theme.of(context).textTheme.caption,
|
// style: Theme.of(context).textTheme.caption,
|
||||||
textAlign: TextAlign.center,
|
// textAlign: TextAlign.center,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
else if (station.delay < 0) {
|
// else if (station.delay < 0) {
|
||||||
return Text(
|
// return Text(
|
||||||
"${-(station.delay)} minute mai devreme",
|
// "${-(station.delay)} minute mai devreme",
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(color: Colors.green.shade700),
|
// style: Theme.of(context).textTheme.bodyText2.copyWith(color: Colors.green.shade700),
|
||||||
textAlign: TextAlign.center,
|
// textAlign: TextAlign.center,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
return Text(
|
// return Text(
|
||||||
"${station.delay} minute întârziere",
|
// "${station.delay} minute întârziere",
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(color: Colors.red.shade700),
|
// style: Theme.of(context).textTheme.bodyText2.copyWith(color: Colors.red.shade700),
|
||||||
textAlign: TextAlign.center,
|
// textAlign: TextAlign.center,
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:info_tren/stations_list.dart';
|
import 'package:info_tren/stations_list.dart.old';
|
||||||
|
|
||||||
import 'models/train_data.dart';
|
import 'models/train_data.dart';
|
||||||
|
|
||||||
|
@ -29,33 +29,30 @@ class TrainInfoDisplayData extends StatelessWidget {
|
||||||
padding: const EdgeInsets.all(4.0),
|
padding: const EdgeInsets.all(4.0),
|
||||||
child: TotalDetails(trainData),
|
child: TotalDetails(trainData),
|
||||||
),
|
),
|
||||||
if (trainData.destination.station.isNotEmpty)
|
CustomDivider(),
|
||||||
...[
|
Padding(
|
||||||
CustomDivider(),
|
padding: const EdgeInsets.all(4.0),
|
||||||
Padding(
|
child: Destination(trainData),
|
||||||
padding: const EdgeInsets.all(4.0),
|
),
|
||||||
child: Destination(trainData),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
CustomDivider(),
|
CustomDivider(),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(4.0),
|
padding: const EdgeInsets.all(4.0),
|
||||||
child: LastUpdate(trainData),
|
child: LastUpdate(trainData),
|
||||||
),
|
),
|
||||||
if (trainData.nextStop.station.isNotEmpty)
|
// if (trainData.nextStop.station.isNotEmpty)
|
||||||
...[
|
// ...[
|
||||||
CustomDivider(),
|
// CustomDivider(),
|
||||||
Padding(
|
// Padding(
|
||||||
padding: const EdgeInsets.all(4.0),
|
// padding: const EdgeInsets.all(4.0),
|
||||||
child: NextStop(trainData),
|
// child: NextStop(trainData),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
CustomDivider(),
|
CustomDivider(),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(4.0),
|
padding: const EdgeInsets.all(4.0),
|
||||||
child: TrainStatus(trainData),
|
child: TrainStatus(trainData),
|
||||||
),
|
),
|
||||||
Divider(color: Theme.of(context).accentColor,),
|
Divider(color: Theme.of(context).colorScheme.secondary,),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(4.0),
|
padding: const EdgeInsets.all(4.0),
|
||||||
child: StationsList(trainData),
|
child: StationsList(trainData),
|
||||||
|
@ -81,7 +78,7 @@ class TrainName extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Text(
|
return Text(
|
||||||
"${trainData.rang} ${trainData.trainNumber}",
|
"${trainData.rank} ${trainData.number}",
|
||||||
style: Theme.of(context).textTheme.headline3,
|
style: Theme.of(context).textTheme.headline3,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -98,20 +95,20 @@ class TrainRoute extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
"${trainData.route.split("-")[0]}",
|
trainData.route.from,
|
||||||
style: Theme.of(context).textTheme.bodyText1.copyWith(fontStyle: FontStyle.italic),
|
style: Theme.of(context).textTheme.bodyText1?.copyWith(fontStyle: FontStyle.italic),
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"-",
|
"-",
|
||||||
style: Theme.of(context).textTheme.bodyText1.copyWith(fontStyle: FontStyle.italic),
|
style: Theme.of(context).textTheme.bodyText1?.copyWith(fontStyle: FontStyle.italic),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
"${trainData.route.split("-")[1]}",
|
trainData.route.to,
|
||||||
style: Theme.of(context).textTheme.bodyText1.copyWith(fontStyle: FontStyle.italic),
|
style: Theme.of(context).textTheme.bodyText1?.copyWith(fontStyle: FontStyle.italic),
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -141,7 +138,7 @@ class TrainStatus extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Text(
|
return Text(
|
||||||
trainData.state,
|
trainData.status.toString(),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: Theme.of(context).textTheme.headline5,
|
style: Theme.of(context).textTheme.headline5,
|
||||||
);
|
);
|
||||||
|
@ -154,16 +151,16 @@ class Destination extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (trainData.destination.station.isEmpty) return Container();
|
final destinationStation = trainData.stations.last;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
"Destinația: ${trainData.destination.station}",
|
"Destinația: ${destinationStation.name}",
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"Sosește în ${trainData.destination.dateAndTime.split(" ")[0]} la ${trainData.destination.dateAndTime.split(" ")[1]}",
|
"Sosește la ${destinationStation.arrival!.scheduleTime}",
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -177,6 +174,9 @@ class LastUpdate extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
if (trainData.status == null) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
@ -188,62 +188,63 @@ class LastUpdate extends StatelessWidget {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(2.0),
|
padding: const EdgeInsets.all(2.0),
|
||||||
child: Text(trainData.lastInfo.station, textAlign: TextAlign.left,),
|
child: Text(trainData.status!.station, textAlign: TextAlign.left,),
|
||||||
),
|
),
|
||||||
Expanded(child: Container(),),
|
Expanded(child: Container(),),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(2.0),
|
padding: const EdgeInsets.all(2.0),
|
||||||
child: Text(trainData.lastInfo.event, textAlign: TextAlign.right,),
|
child: Text(trainData.status!.state.toString(), textAlign: TextAlign.right,),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(2.0),
|
padding: const EdgeInsets.all(2.0),
|
||||||
child: trainData.lastInfo.delay == 0
|
child: trainData.status!.delay == 0
|
||||||
? Text("Fără întârziere", style: Theme.of(context).textTheme.caption,)
|
? Text("Fără întârziere", style: Theme.of(context).textTheme.caption,)
|
||||||
: trainData.lastInfo.delay > 0
|
: trainData.status!.delay > 0
|
||||||
? Text("${trainData.lastInfo.delay} minute întârziere", style: Theme.of(context).textTheme.bodyText2.copyWith(color: Colors.red.shade700),)
|
? Text("${trainData.status!.delay} minute întârziere", style: Theme.of(context).textTheme.bodyText2?.copyWith(color: Colors.red.shade700),)
|
||||||
: Text("${-(trainData.lastInfo.delay)} minute mai devreme", style: Theme.of(context).textTheme.bodyText2.copyWith(color: Colors.green.shade700),)
|
: Text("${-(trainData.status!.delay)} minute mai devreme", style: Theme.of(context).textTheme.bodyText2?.copyWith(color: Colors.green.shade700),)
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(2.0),
|
|
||||||
child: Text("Raportat la ${trainData.lastInfo.dateAndTime}"),
|
|
||||||
),
|
),
|
||||||
|
// TODO: Implement status report time detection
|
||||||
|
// Padding(
|
||||||
|
// padding: const EdgeInsets.all(2.0),
|
||||||
|
// child: Text("Raportat la ${trainData.lastInfo.dateAndTime}"),
|
||||||
|
// ),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NextStop extends StatelessWidget {
|
// class NextStop extends StatelessWidget {
|
||||||
final TrainData trainData;
|
// final TrainData trainData;
|
||||||
NextStop(this.trainData);
|
// NextStop(this.trainData);
|
||||||
|
|
||||||
@override
|
// @override
|
||||||
Widget build(BuildContext context) {
|
// Widget build(BuildContext context) {
|
||||||
return Column(
|
// return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
// mainAxisSize: MainAxisSize.min,
|
||||||
children: <Widget>[
|
// children: <Widget>[
|
||||||
Padding(
|
// Padding(
|
||||||
padding: const EdgeInsets.all(2.0),
|
// padding: const EdgeInsets.all(2.0),
|
||||||
child: Text("Următoarea oprire", style: Theme.of(context).textTheme.headline5,),
|
// child: Text("Următoarea oprire", style: Theme.of(context).textTheme.headline5,),
|
||||||
),
|
// ),
|
||||||
Row(
|
// Row(
|
||||||
children: <Widget>[
|
// children: <Widget>[
|
||||||
Padding(
|
// Padding(
|
||||||
padding: const EdgeInsets.all(2.0),
|
// padding: const EdgeInsets.all(2.0),
|
||||||
child: Text(trainData.nextStop.station, textAlign: TextAlign.left,),
|
// child: Text(trainData.nextStop.station, textAlign: TextAlign.left,),
|
||||||
),
|
// ),
|
||||||
Expanded(child: Container(),),
|
// Expanded(child: Container(),),
|
||||||
Padding(
|
// Padding(
|
||||||
padding: const EdgeInsets.all(2.0),
|
// padding: const EdgeInsets.all(2.0),
|
||||||
child: Text(trainData.nextStop.dateAndTime, textAlign: TextAlign.right,),
|
// child: Text(trainData.nextStop.dateAndTime, textAlign: TextAlign.right,),
|
||||||
)
|
// )
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
class TotalDetails extends StatelessWidget {
|
class TotalDetails extends StatelessWidget {
|
||||||
final TrainData trainData;
|
final TrainData trainData;
|
||||||
|
@ -254,18 +255,18 @@ class TotalDetails extends StatelessWidget {
|
||||||
return Row(
|
return Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
trainData.distance,
|
'${trainData.stations.last.km} km',
|
||||||
style: Theme.of(context).textTheme.caption,
|
style: Theme.of(context).textTheme.caption,
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container()
|
child: Container()
|
||||||
),
|
),
|
||||||
Text(
|
// Text(
|
||||||
trainData.tripLength,
|
// trainData.tripLength,
|
||||||
style: Theme.of(context).textTheme.caption,
|
// style: Theme.of(context).textTheme.caption,
|
||||||
textAlign: TextAlign.right,
|
// textAlign: TextAlign.right,
|
||||||
)
|
// )
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
import 'dart:io' show Platform;
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
|
|
||||||
import 'package:info_tren/models/train_data.dart';
|
|
||||||
import 'package:info_tren/train_info_page/train_info_cupertino.dart';
|
|
||||||
import 'package:info_tren/train_info_page/train_info_material.dart';
|
|
||||||
|
|
||||||
mixin TrainInfoMixin {
|
|
||||||
String title;
|
|
||||||
bool showTrainData;
|
|
||||||
TrainLookupResult lookupResult;
|
|
||||||
bool requestedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
class TrainInfo extends StatelessWidget {
|
|
||||||
static String routeName = "/trainInfo/display";
|
|
||||||
|
|
||||||
final int trainNumber;
|
|
||||||
|
|
||||||
TrainInfo({@required this.trainNumber});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return TrainDataWebViewAdapter(
|
|
||||||
builder: (context) {
|
|
||||||
if (Platform.isAndroid) {
|
|
||||||
return TrainInfoMaterial(trainNumber: trainNumber,);
|
|
||||||
}
|
|
||||||
else if (Platform.isIOS) {
|
|
||||||
return TrainInfoCupertino(trainNumber: trainNumber,);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef FutureDisplayCallback<T>(BuildContext context, T data);
|
|
||||||
|
|
||||||
class FutureDisplay<T> extends StatelessWidget {
|
|
||||||
final Future<T> future;
|
|
||||||
final FutureDisplayCallback<T> builder;
|
|
||||||
|
|
||||||
FutureDisplay({Key key, @required this.future, @required this.builder}): super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureBuilder(
|
|
||||||
future: future,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasData) return builder(context, snapshot.data);
|
|
||||||
if (snapshot.hasError) throw snapshot.error;
|
|
||||||
if (snapshot.connectionState == ConnectionState.done) return Container();
|
|
||||||
|
|
||||||
Widget loadingWidget;
|
|
||||||
if (Platform.isAndroid) {
|
|
||||||
loadingWidget = CircularProgressIndicator();
|
|
||||||
}
|
|
||||||
else if (Platform.isIOS) {
|
|
||||||
loadingWidget = CupertinoActivityIndicator();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Center(
|
|
||||||
child: loadingWidget,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,506 +0,0 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:info_tren/models/train_data.dart';
|
|
||||||
import 'package:info_tren/train_info_page/train_info.dart';
|
|
||||||
import 'package:info_tren/train_info_page/train_info_constants.dart';
|
|
||||||
|
|
||||||
class DisplayTrainStation extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
|
|
||||||
DisplayTrainStation({@required this.station});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
children: <Widget>[
|
|
||||||
FutureDisplay(
|
|
||||||
future: Future.wait([
|
|
||||||
station.delay,
|
|
||||||
station.realOrEstimate,
|
|
||||||
station.observations,
|
|
||||||
]),
|
|
||||||
builder: (context, data) {
|
|
||||||
final isDelayed = (data[0] as int) > 0 && (data[1] as RealOrEstimate) == RealOrEstimate.real;
|
|
||||||
final isOnTime = (data[0] as int) <= 0 && (data[1] as RealOrEstimate) == RealOrEstimate.real;
|
|
||||||
final isNotScheduled = data[2] == "ONI";
|
|
||||||
|
|
||||||
return KmBadge(
|
|
||||||
station: station,
|
|
||||||
isNotScheduled: isNotScheduled,
|
|
||||||
isDelayed: isDelayed,
|
|
||||||
isOnTime: isOnTime,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Title(
|
|
||||||
station: station,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Time(
|
|
||||||
station: station,
|
|
||||||
),
|
|
||||||
Delay(
|
|
||||||
station: station,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KmBadge extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
final bool isNotScheduled;
|
|
||||||
final bool isOnTime;
|
|
||||||
final bool isDelayed;
|
|
||||||
|
|
||||||
KmBadge({
|
|
||||||
@required this.station,
|
|
||||||
this.isNotScheduled = false,
|
|
||||||
this.isOnTime = false,
|
|
||||||
this.isDelayed = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
Color foregroundColor = FOREGROUND_WHITE;
|
|
||||||
Color backgroundColor;
|
|
||||||
|
|
||||||
if (isNotScheduled) {
|
|
||||||
foregroundColor = Color.fromRGBO(225, 175, 30, 1);
|
|
||||||
backgroundColor = Color.fromRGBO(80, 40, 10, 1);
|
|
||||||
}
|
|
||||||
else if (isOnTime) {
|
|
||||||
foregroundColor = Color.fromRGBO(130, 175, 65, 1);
|
|
||||||
backgroundColor = Color.fromRGBO(40, 80, 10, 1);
|
|
||||||
}
|
|
||||||
else if (isDelayed) {
|
|
||||||
foregroundColor = Color.fromRGBO(225, 75, 30, 1);
|
|
||||||
backgroundColor = 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: FutureDisplay<int>(
|
|
||||||
future: station.km,
|
|
||||||
builder: (context, value) {
|
|
||||||
return Text(
|
|
||||||
value.toString(),
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w400 : FontWeight.w200,
|
|
||||||
color: MediaQuery.of(context).boldText ? FOREGROUND_WHITE : foregroundColor,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"km",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
fontSize: 10,
|
|
||||||
color: MediaQuery.of(context).boldText ? FOREGROUND_WHITE : foregroundColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Title extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
|
|
||||||
Title({
|
|
||||||
@required this.station
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<List<String>>(
|
|
||||||
future: Future.wait([
|
|
||||||
station.stationName,
|
|
||||||
station.observations
|
|
||||||
]),
|
|
||||||
builder: (context, items) {
|
|
||||||
return Text(
|
|
||||||
items[0],
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
fontSize: 22,
|
|
||||||
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w400 : FontWeight.w200,
|
|
||||||
fontStyle: items[1] == "ONI" ? FontStyle.italic : FontStyle.normal,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Time extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
|
|
||||||
Time({
|
|
||||||
@required this.station,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<List<String>>(
|
|
||||||
future: Future.wait([
|
|
||||||
station.arrivalTime,
|
|
||||||
station.stopsFor,
|
|
||||||
station.departureTime,
|
|
||||||
]),
|
|
||||||
builder: (context, items) {
|
|
||||||
if (items[0].isEmpty) {
|
|
||||||
// Plecare
|
|
||||||
return DepartureTime(
|
|
||||||
station: station,
|
|
||||||
firstStation: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items[2].isEmpty) {
|
|
||||||
// Sosire
|
|
||||||
return ArrivalTime(
|
|
||||||
station: station,
|
|
||||||
finalStation: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"→",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
fontSize: 22,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(width: 2,),
|
|
||||||
ArrivalTime(station: station,),
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
StopTime(station: station,),
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
DepartureTime(station: station,),
|
|
||||||
Container(width: 2,),
|
|
||||||
Text(
|
|
||||||
"→",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
fontSize: 22,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ArrivalTime extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
final bool finalStation;
|
|
||||||
|
|
||||||
ArrivalTime({
|
|
||||||
@required this.station,
|
|
||||||
this.finalStation = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<List<Object>>(
|
|
||||||
future: Future.wait([
|
|
||||||
station.arrivalTime,
|
|
||||||
station.delay,
|
|
||||||
]),
|
|
||||||
builder: (context, data) {
|
|
||||||
if (finalStation) {
|
|
||||||
return Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"→",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
fontSize: 22,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(width: 2,),
|
|
||||||
Text("sosire la "),
|
|
||||||
ArrivalTime(station: station,),
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (data[1] == 0) {
|
|
||||||
return Text("${data[0]}");
|
|
||||||
}
|
|
||||||
else if (data[1] as int > 0) {
|
|
||||||
final splits = (data[0] as String).split(":").map((s) => int.parse(s)).toList();
|
|
||||||
|
|
||||||
final now = DateTime.now();
|
|
||||||
final newDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
|
||||||
final oldDate = newDate.subtract(Duration(minutes: data[1] as int));
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"${data[0]}",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
color: CupertinoColors.destructiveRed,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final splits = (data[0] as String).split(":").map((s) => int.parse(s)).toList();
|
|
||||||
|
|
||||||
final now = DateTime.now();
|
|
||||||
final newDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
|
||||||
final oldDate = newDate.subtract(Duration(minutes: data[1] as int));
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"${data[0]}",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
color: CupertinoColors.activeGreen,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StopTime extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
|
|
||||||
StopTime({
|
|
||||||
@required this.station,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<String>(
|
|
||||||
future: station.stopsFor,
|
|
||||||
builder: (context, stopsFor) {
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"staționează pentru",
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
Builder(
|
|
||||||
builder: (context) {
|
|
||||||
int stopsForInt = int.parse(stopsFor);
|
|
||||||
if (stopsForInt == 1) {
|
|
||||||
return Text(
|
|
||||||
"1 minut",
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if (stopsForInt < 20) {
|
|
||||||
return Text(
|
|
||||||
"$stopsFor minute",
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Text(
|
|
||||||
"$stopsFor de minute",
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DepartureTime extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
final bool firstStation;
|
|
||||||
|
|
||||||
DepartureTime({
|
|
||||||
@required this.station,
|
|
||||||
this.firstStation = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<List<Object>>(
|
|
||||||
future: Future.wait([
|
|
||||||
station.departureTime,
|
|
||||||
station.delay,
|
|
||||||
]),
|
|
||||||
builder: (context, data) {
|
|
||||||
if (firstStation) {
|
|
||||||
return Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
Text("plecare la "),
|
|
||||||
DepartureTime(station: station,),
|
|
||||||
Container(width: 2,),
|
|
||||||
Text(
|
|
||||||
"→",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
fontSize: 22,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (data[1] == 0) {
|
|
||||||
return Text("${data[0]}");
|
|
||||||
}
|
|
||||||
else if (data[1] as int > 0) {
|
|
||||||
final splits = (data[0] as String).split(":").map((s) => int.parse(s)).toList();
|
|
||||||
|
|
||||||
final now = DateTime.now();
|
|
||||||
final newDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
|
||||||
final oldDate = newDate.subtract(Duration(minutes: data[1] as int));
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"${data[0]}",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
color: CupertinoColors.destructiveRed,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final splits = (data[0] as String).split(":").map((s) => int.parse(s)).toList();
|
|
||||||
|
|
||||||
final now = DateTime.now();
|
|
||||||
final newDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
|
||||||
final oldDate = newDate.subtract(Duration(minutes: data[1] as int));
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"${data[0]}",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
color: CupertinoColors.activeGreen,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Delay extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
|
|
||||||
Delay({
|
|
||||||
@required this.station,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<int>(
|
|
||||||
future: station.delay,
|
|
||||||
builder: (context, delay) {
|
|
||||||
if (delay == 0) return Container();
|
|
||||||
|
|
||||||
else if (delay > 0) {
|
|
||||||
return Text(
|
|
||||||
"$delay minute întârziere",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
color: CupertinoColors.destructiveRed,
|
|
||||||
fontSize: 12,
|
|
||||||
fontStyle: FontStyle.italic,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (delay < 0) {
|
|
||||||
return Text(
|
|
||||||
"${-delay} minute mai devreme",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(
|
|
||||||
color: CupertinoColors.activeGreen,
|
|
||||||
fontSize: 12,
|
|
||||||
fontStyle: FontStyle.italic,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Container();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,944 +0,0 @@
|
||||||
import 'package:info_tren/train_info_page/train_info_animation_helpers.dart';
|
|
||||||
import 'package:info_tren/train_info_page/train_info_material_DisplayTrainStation.dart';
|
|
||||||
import 'package:info_tren/utils/stream_list.dart';
|
|
||||||
|
|
||||||
import '../models/train_data.dart';
|
|
||||||
import './train_info.dart';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class TrainInfoMaterial extends StatefulWidget {
|
|
||||||
final int trainNumber;
|
|
||||||
|
|
||||||
TrainInfoMaterial({@required this.trainNumber});
|
|
||||||
|
|
||||||
@override
|
|
||||||
_TrainInfoMaterialState createState() => _TrainInfoMaterialState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TrainInfoMaterialState extends State<TrainInfoMaterial> with TrainInfoMixin {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
title = widget.trainNumber.toString();
|
|
||||||
showTrainData = false;
|
|
||||||
requestedData = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeDependencies() {
|
|
||||||
super.didChangeDependencies();
|
|
||||||
|
|
||||||
if (!requestedData) {
|
|
||||||
requestedData = true;
|
|
||||||
|
|
||||||
TrainDataWebViewAdapter.of(context).loadTrain(widget.trainNumber).then((value) {
|
|
||||||
setState(() {
|
|
||||||
lookupResult = value;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (lookupResult == TrainLookupResult.NOT_FOUND) {
|
|
||||||
Future.delayed(Duration(seconds: 5), () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (lookupResult == TrainLookupResult.FOUND) {
|
|
||||||
Future.delayed(Duration(seconds: 1, milliseconds: 500), () {
|
|
||||||
setState(() {
|
|
||||||
showTrainData = true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (!showTrainData) {
|
|
||||||
return _TrainInfoMaterialBefore(
|
|
||||||
title: title,
|
|
||||||
lookupResult: lookupResult,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return _TrainDataMaterialAfter(
|
|
||||||
title: title,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TrainInfoMaterialBefore extends StatefulWidget {
|
|
||||||
final String title;
|
|
||||||
final TrainLookupResult lookupResult;
|
|
||||||
|
|
||||||
_TrainInfoMaterialBefore({@required this.title, @required this.lookupResult});
|
|
||||||
|
|
||||||
@override
|
|
||||||
_TrainInfoMaterialBeforeState createState() => _TrainInfoMaterialBeforeState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TrainInfoMaterialBeforeState extends State<_TrainInfoMaterialBefore> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
centerTitle: true,
|
|
||||||
title: Text(widget.title ?? ""),
|
|
||||||
),
|
|
||||||
body: SafeArea(
|
|
||||||
bottom: false,
|
|
||||||
child: StreamBuilder<ProgressReport>(
|
|
||||||
stream: TrainDataWebViewAdapter.of(context).progressStream,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
switch (snapshot.connectionState) {
|
|
||||||
case ConnectionState.none:
|
|
||||||
return Container();
|
|
||||||
case ConnectionState.waiting:
|
|
||||||
return Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
CircularProgressIndicator(),
|
|
||||||
Text(
|
|
||||||
"Conectare...",
|
|
||||||
style: Theme.of(context).textTheme.headline6,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
case ConnectionState.active:
|
|
||||||
break;
|
|
||||||
case ConnectionState.done:
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
ProgressReportDisplayEntry(
|
|
||||||
key: ValueKey(1),
|
|
||||||
completed: 1 <= snapshot.data.current,
|
|
||||||
waitingText: "Se crează WebView",
|
|
||||||
completedText: "WebView a fost creat",
|
|
||||||
),
|
|
||||||
ProgressReportDisplayEntry(
|
|
||||||
key: ValueKey(2),
|
|
||||||
completed: 2 <= snapshot.data.current,
|
|
||||||
waitingText: "Se încarcă pagina Informatica Feroviară",
|
|
||||||
completedText: "Pagina Informatica Feroviară a fost încărcată",
|
|
||||||
),
|
|
||||||
ProgressReportDisplayEntry(
|
|
||||||
key: ValueKey(3),
|
|
||||||
completed: 3 <= snapshot.data.current,
|
|
||||||
waitingText: "Se încarcă informațiile despre tren",
|
|
||||||
completedText: "Informațiile despre tren au fost încărcate",
|
|
||||||
),
|
|
||||||
if (widget.lookupResult != null)
|
|
||||||
...[
|
|
||||||
Container(height: 20,),
|
|
||||||
SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: AnimatedBackground(
|
|
||||||
animationDuration: Duration(milliseconds: 250),
|
|
||||||
initialColor: Theme.of(context).scaffoldBackgroundColor,
|
|
||||||
backgroundColor:
|
|
||||||
widget.lookupResult == TrainLookupResult.FOUND
|
|
||||||
? Colors.green
|
|
||||||
: Colors.red,
|
|
||||||
child: Center(
|
|
||||||
child: Row(
|
|
||||||
children: <Widget>[
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
if (widget.lookupResult == TrainLookupResult.FOUND)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(8, 8, 0, 8),
|
|
||||||
child: Center(
|
|
||||||
child: CircularProgressIndicator(
|
|
||||||
strokeWidth: 2,
|
|
||||||
valueColor: AlwaysStoppedAnimation(Colors.greenAccent),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Text(
|
|
||||||
widget.lookupResult == TrainLookupResult.FOUND
|
|
||||||
? "Trenul a fost găsit"
|
|
||||||
: widget.lookupResult == TrainLookupResult.NOT_FOUND
|
|
||||||
? "Trenul nu a fost găsit"
|
|
||||||
: "A apărut o eroare în căutarea trenului",
|
|
||||||
style: Theme.of(context).textTheme.headline6,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isSmallScreen(BuildContext context) => MediaQuery.of(context).size.height <= 425;
|
|
||||||
|
|
||||||
class _TrainDataMaterialAfter extends StatefulWidget {
|
|
||||||
final String title;
|
|
||||||
|
|
||||||
_TrainDataMaterialAfter({@required this.title});
|
|
||||||
|
|
||||||
@override
|
|
||||||
_TrainDataMaterialAfterState createState() => _TrainDataMaterialAfterState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TrainDataMaterialAfterState extends State<_TrainDataMaterialAfter> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureBuilder<OnDemandTrainData>(
|
|
||||||
future: TrainDataWebViewAdapter.of(context).trainData(onInvalidation: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
}),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (!snapshot.hasData) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
centerTitle: true,
|
|
||||||
title: Text(widget.title ?? ""),
|
|
||||||
),
|
|
||||||
body: SafeArea(
|
|
||||||
child: Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
appBar: isSmallScreen(context) ? null : AppBar(
|
|
||||||
centerTitle: true,
|
|
||||||
title: FutureBuilder<List<String>>(
|
|
||||||
future: Future.wait([
|
|
||||||
snapshot.data.rang,
|
|
||||||
snapshot.data.trainNumber
|
|
||||||
]),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasData) {
|
|
||||||
return Text("Informații despre ${snapshot.data[0]} ${snapshot.data[1]}");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Text(widget.title ?? "");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: Column(
|
|
||||||
children: <Widget>[
|
|
||||||
if (isSmallScreen(context))
|
|
||||||
FutureBuilder<List<String>>(
|
|
||||||
future: Future.wait([
|
|
||||||
snapshot.data.rang,
|
|
||||||
snapshot.data.trainNumber,
|
|
||||||
]),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
var title = "INFO TREN";
|
|
||||||
if (snapshot.hasData) title = "INFO TREN ─ ${snapshot.data[0]} ${snapshot.data[1]}";
|
|
||||||
|
|
||||||
return SlimAppBar(
|
|
||||||
title: title,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: SafeArea(
|
|
||||||
bottom: false,
|
|
||||||
child: CustomScrollView(
|
|
||||||
slivers: <Widget>[
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: DisplayTrainID(trainData: snapshot.data,),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: DisplayTrainOperator(trainData: snapshot.data,),
|
|
||||||
),
|
|
||||||
SliverPadding(
|
|
||||||
padding: const EdgeInsets.only(left: 2, right: 2),
|
|
||||||
sliver: SliverToBoxAdapter(
|
|
||||||
child: DisplayTrainRoute(trainData: snapshot.data,),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: DisplayTrainDeparture(trainData: snapshot.data,),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Divider(
|
|
||||||
color: Colors.white70,
|
|
||||||
height: isSmallScreen(context) ? 8 : 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: DisplayTrainLastInfo(trainData: snapshot.data,),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: IntrinsicHeight(
|
|
||||||
child: Row(
|
|
||||||
children: <Widget>[
|
|
||||||
Expanded(child: DisplayTrainNextStop(trainData: snapshot.data,)),
|
|
||||||
Expanded(child: DisplayTrainDestination(trainData: snapshot.data,)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: IntrinsicHeight(
|
|
||||||
child: Row(
|
|
||||||
children: <Widget>[
|
|
||||||
Expanded(child: DisplayTrainRouteDuration(trainData: snapshot.data,)),
|
|
||||||
Expanded(child: DisplayTrainRouteDistance(trainData: snapshot.data,)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Divider(
|
|
||||||
color: Colors.white70,
|
|
||||||
height: isSmallScreen(context) ? 8 : 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
DisplayTrainStations(
|
|
||||||
trainData: snapshot.data,
|
|
||||||
pageLoadFuture: TrainDataWebViewAdapter.of(context).nextLoadFuture,
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Container(
|
|
||||||
height: MediaQuery.of(context).viewPadding.bottom,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisplayTrainID extends StatelessWidget {
|
|
||||||
final OnDemandTrainData trainData;
|
|
||||||
|
|
||||||
DisplayTrainID({@required this.trainData});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<List<String>>(
|
|
||||||
future: Future.wait([
|
|
||||||
trainData.rang,
|
|
||||||
trainData.trainNumber,
|
|
||||||
]),
|
|
||||||
builder: (context, list) {
|
|
||||||
return Text(
|
|
||||||
"${list[0]} ${list[1]}",
|
|
||||||
style: (isSmallScreen(context)
|
|
||||||
? Theme.of(context).textTheme.headline4
|
|
||||||
: Theme.of(context).textTheme.headline3).copyWith(
|
|
||||||
color: Theme.of(context).textTheme.bodyText2.color,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisplayTrainOperator extends StatelessWidget {
|
|
||||||
final OnDemandTrainData trainData;
|
|
||||||
|
|
||||||
DisplayTrainOperator({@required this.trainData});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<String>(
|
|
||||||
future: trainData.operator,
|
|
||||||
builder: (context, op) {
|
|
||||||
return Text(
|
|
||||||
op,
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontStyle: FontStyle.italic,
|
|
||||||
fontSize: isSmallScreen(context) ? 12 : 14,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisplayTrainRoute extends StatelessWidget {
|
|
||||||
final OnDemandTrainData trainData;
|
|
||||||
|
|
||||||
DisplayTrainRoute({@required this.trainData});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay(
|
|
||||||
future: Future.wait([trainData.route.from, trainData.route.to]),
|
|
||||||
builder: (context, routePieces) {
|
|
||||||
return Row(
|
|
||||||
children: <Widget>[
|
|
||||||
Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
child: Text(
|
|
||||||
routePieces[0],
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
Center(child: Text("-")),
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
child: Text(
|
|
||||||
routePieces[1],
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.right,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisplayTrainDeparture extends StatelessWidget {
|
|
||||||
final OnDemandTrainData trainData;
|
|
||||||
|
|
||||||
DisplayTrainDeparture({@required this.trainData});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.all(2),
|
|
||||||
child: FutureDisplay<DateTime>(
|
|
||||||
future: trainData.departureDate,
|
|
||||||
builder: (context, dataPlecare) {
|
|
||||||
return Text(
|
|
||||||
"Plecare în ${dataPlecare.day.toString().padLeft(2, '0')}.${dataPlecare.month.toString().padLeft(2, '0')}.${dataPlecare.year.toString().padLeft(4, '0')}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontStyle: FontStyle.italic,
|
|
||||||
fontWeight: FontWeight.w200,
|
|
||||||
fontSize: isSmallScreen(context) ? 12 : 14,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisplayTrainLastInfo extends StatelessWidget {
|
|
||||||
final OnDemandTrainData trainData;
|
|
||||||
|
|
||||||
DisplayTrainLastInfo({@required this.trainData});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Card(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(2),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(2),
|
|
||||||
child: Text(
|
|
||||||
"Ultima informație",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 18 : 20,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: <Widget>[
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
child: FutureDisplay(
|
|
||||||
future: trainData.lastInfo.station,
|
|
||||||
builder: (context, station) {
|
|
||||||
return Text(
|
|
||||||
station,
|
|
||||||
style: Theme.of(context).textTheme.bodyText2,
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
child: FutureDisplay(
|
|
||||||
future: trainData.lastInfo.event,
|
|
||||||
builder: (context, event) {
|
|
||||||
return Text(
|
|
||||||
event,
|
|
||||||
style: Theme.of(context).textTheme.bodyText2,
|
|
||||||
textAlign: TextAlign.right,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(2),
|
|
||||||
child: Row(
|
|
||||||
children: <Widget>[
|
|
||||||
FutureDisplay<DateTime>(
|
|
||||||
future: trainData.lastInfo.dateAndTime,
|
|
||||||
builder: (context, dt) {
|
|
||||||
return Text(
|
|
||||||
"Raportat în ${dt.day.toString().padLeft(2, '0')}.${dt.month.toString().padLeft(2, '0')}.${dt.year.toString().padLeft(4, '0')}, la ${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}",
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
FutureBuilder(
|
|
||||||
initialData: 0,
|
|
||||||
future: trainData.lastInfo.delay,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.data == 0) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snapshot.data > 0) {
|
|
||||||
return Text(
|
|
||||||
"${snapshot.data} minute întârziere",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: 14,
|
|
||||||
color: Color.fromRGBO(200, 30, 15, 1),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Text(
|
|
||||||
"${-snapshot.data} minute mai devreme",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Color.fromRGBO(15, 200, 15, 1),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisplayTrainNextStop extends StatelessWidget {
|
|
||||||
final OnDemandTrainData trainData;
|
|
||||||
|
|
||||||
DisplayTrainNextStop({@required this.trainData});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureBuilder(
|
|
||||||
future: trainData.nextStop.stationName,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (!snapshot.hasData) return Container(height: 0,);
|
|
||||||
|
|
||||||
return Card(
|
|
||||||
child: Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(2),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
child: Text(
|
|
||||||
"Următoarea oprire",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 18 : 20,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
FutureDisplay(
|
|
||||||
future: trainData.nextStop.stationName,
|
|
||||||
builder: (context, station) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(4, 0, 4, 0),
|
|
||||||
child: Text(
|
|
||||||
station,
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 16 : 18,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
FutureDisplay<DateTime>(
|
|
||||||
future: trainData.nextStop.arrival,
|
|
||||||
builder: (context, arrival) {
|
|
||||||
const months = ["ian", "feb", "mar", "apr", "mai", "iun", "iul", "aug", "sep", "oct", "noi", "dec"];
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"în ${arrival.day} ${months[arrival.month - 1]} ${arrival.year}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 12 : 14,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"la ${arrival.hour.toString().padLeft(2, '0')}:${arrival.minute.toString().padLeft(2, '0')}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 12 : 14,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisplayTrainDestination extends StatelessWidget {
|
|
||||||
final OnDemandTrainData trainData;
|
|
||||||
|
|
||||||
DisplayTrainDestination({@required this.trainData});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureBuilder(
|
|
||||||
future: trainData.destination.stationName,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (!snapshot.hasData) return Container(height: 0,);
|
|
||||||
|
|
||||||
return Card(
|
|
||||||
child: Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(2),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
child: Text(
|
|
||||||
"Destinația",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 18 : 20,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
FutureDisplay(
|
|
||||||
future: trainData.destination.stationName,
|
|
||||||
builder: (context, station) {
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(4, 0, 4, 0),
|
|
||||||
child: Text(
|
|
||||||
station,
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 16 : 18,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
FutureDisplay<DateTime>(
|
|
||||||
future: trainData.destination.arrival,
|
|
||||||
builder: (context, arrival) {
|
|
||||||
const months = ["ian", "feb", "mar", "apr", "mai", "iun", "iul", "aug", "sep", "oct", "noi", "dec"];
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"în ${arrival.day} ${months[arrival.month - 1]} ${arrival.year}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 12 : 14,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"la ${arrival.hour.toString().padLeft(2, '0')}:${arrival.minute.toString().padLeft(2, '0')}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 12 : 14,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisplayTrainRouteDistance extends StatelessWidget {
|
|
||||||
final OnDemandTrainData trainData;
|
|
||||||
|
|
||||||
DisplayTrainRouteDistance({@required this.trainData});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Card(
|
|
||||||
child: Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(2),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"Distanța rutei",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 16 : 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
FutureDisplay(
|
|
||||||
future: trainData.routeDistance,
|
|
||||||
builder: (context, distance) {
|
|
||||||
return Text(
|
|
||||||
"$distance km",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 14 : 16,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisplayTrainRouteDuration extends StatelessWidget {
|
|
||||||
final OnDemandTrainData trainData;
|
|
||||||
|
|
||||||
DisplayTrainRouteDuration({@required this.trainData});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Card(
|
|
||||||
child: Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(2),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"Durata rutei",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 16 : 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
FutureDisplay<Duration>(
|
|
||||||
future: trainData.routeDuration,
|
|
||||||
builder: (context, duration) {
|
|
||||||
var durationString = StringBuffer();
|
|
||||||
|
|
||||||
bool firstWritten = false;
|
|
||||||
|
|
||||||
if (duration.inDays > 0) {
|
|
||||||
firstWritten = true;
|
|
||||||
if (duration.inDays == 1) durationString.write("1 zi");
|
|
||||||
else durationString.write("${duration.inDays} zile");
|
|
||||||
duration -= Duration(days: duration.inDays);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (duration.inHours > 0) {
|
|
||||||
if (firstWritten) {
|
|
||||||
durationString.write(", ");
|
|
||||||
}
|
|
||||||
firstWritten = true;
|
|
||||||
if (duration.inHours == 1) durationString.write("1 oră");
|
|
||||||
else durationString.write("${duration.inHours} ore");
|
|
||||||
duration -= Duration(hours: duration.inHours);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (duration.inMinutes > 0) {
|
|
||||||
if (firstWritten) {
|
|
||||||
durationString.write(", ");
|
|
||||||
}
|
|
||||||
firstWritten = true;
|
|
||||||
if (duration.inMinutes == 1) durationString.write("1 minut");
|
|
||||||
else durationString.write("${duration.inMinutes} minute");
|
|
||||||
duration -= Duration(minutes: duration.inMinutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Text(
|
|
||||||
durationString.toString(),
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 14 : 16,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisplayTrainStations extends StatelessWidget {
|
|
||||||
final OnDemandTrainData trainData;
|
|
||||||
final Future pageLoadFuture;
|
|
||||||
|
|
||||||
DisplayTrainStations({@required this.trainData, @required this.pageLoadFuture});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return StreamBuilder<List<OnDemandStation>>(
|
|
||||||
stream: listifyStream(trainData.stations(pageLoadFuture: pageLoadFuture)),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (!snapshot.hasData) {
|
|
||||||
return SliverToBoxAdapter(
|
|
||||||
child: Container(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SliverList(
|
|
||||||
delegate: SliverChildBuilderDelegate(
|
|
||||||
(context, index) {
|
|
||||||
return IndexedSemantics(
|
|
||||||
child: DisplayTrainStation(
|
|
||||||
station: snapshot.data[index],
|
|
||||||
),
|
|
||||||
index: index,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
childCount: snapshot.data.length,
|
|
||||||
addSemanticIndexes: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SlimAppBar extends StatelessWidget {
|
|
||||||
final String title;
|
|
||||||
final double size;
|
|
||||||
// final Function onBackTap;
|
|
||||||
|
|
||||||
SlimAppBar({
|
|
||||||
@required this.title,
|
|
||||||
this.size = 24,
|
|
||||||
// this.onBackTap,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
height: size,
|
|
||||||
child: Container(
|
|
||||||
color:
|
|
||||||
Theme.of(context).appBarTheme?.color ??
|
|
||||||
Theme.of(context).primaryColor,
|
|
||||||
child: InkWell(
|
|
||||||
onTap: (ModalRoute.of(context)?.canPop ?? false)
|
|
||||||
? () => Navigator.of(context).pop()
|
|
||||||
: null,
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: <Widget>[
|
|
||||||
Container(
|
|
||||||
height: size,
|
|
||||||
width: size,
|
|
||||||
child: (ModalRoute.of(context)?.canPop ?? false)
|
|
||||||
? BackButtonIcon()
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Center(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(2),
|
|
||||||
child: Text(
|
|
||||||
title,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style:
|
|
||||||
Theme.of(context).appBarTheme.textTheme?.caption?.copyWith(color: Theme.of(context).appBarTheme.textTheme?.bodyText2?.color) ??
|
|
||||||
Theme.of(context).textTheme.caption.copyWith(color: Theme.of(context).textTheme.bodyText2.color),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
height: size,
|
|
||||||
width: size,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,509 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:info_tren/models/train_data.dart';
|
|
||||||
import 'package:info_tren/train_info_page/train_info.dart';
|
|
||||||
import 'package:info_tren/train_info_page/train_info_material.dart' show isSmallScreen;
|
|
||||||
|
|
||||||
class DisplayTrainStation extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
|
|
||||||
DisplayTrainStation({@required this.station});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Card(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(2),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Row(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
children: <Widget>[
|
|
||||||
FutureDisplay(
|
|
||||||
future: Future.wait([
|
|
||||||
station.delay,
|
|
||||||
station.realOrEstimate,
|
|
||||||
station.observations,
|
|
||||||
]),
|
|
||||||
builder: (context, data) {
|
|
||||||
final isDelayed = (data[0] as int) > 0 && (data[1] as RealOrEstimate) == RealOrEstimate.real;
|
|
||||||
final isOnTime = (data[0] as int) <= 0 && (data[1] as RealOrEstimate) == RealOrEstimate.real;
|
|
||||||
final isNotScheduled = data[2] == "ONI";
|
|
||||||
|
|
||||||
return KmBadge(
|
|
||||||
station: station,
|
|
||||||
isNotScheduled: isNotScheduled,
|
|
||||||
isDelayed: isDelayed,
|
|
||||||
isOnTime: isOnTime,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Title(
|
|
||||||
station: station,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Time(
|
|
||||||
station: station,
|
|
||||||
),
|
|
||||||
Delay(
|
|
||||||
station: station,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class KmBadge extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
final bool isNotScheduled;
|
|
||||||
final bool isOnTime;
|
|
||||||
final bool isDelayed;
|
|
||||||
|
|
||||||
KmBadge({
|
|
||||||
@required this.station,
|
|
||||||
this.isNotScheduled = false,
|
|
||||||
this.isOnTime = false,
|
|
||||||
this.isDelayed = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
@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: FutureDisplay<int>(
|
|
||||||
future: station.km,
|
|
||||||
builder: (context, value) {
|
|
||||||
return Text(
|
|
||||||
value.toString(),
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 14 : 18,
|
|
||||||
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w400 : FontWeight.w200,
|
|
||||||
color: MediaQuery.of(context).boldText ? Colors.white70 : foregroundColor,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"km",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: 10,
|
|
||||||
color: MediaQuery.of(context).boldText ? Colors.white70 : foregroundColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Title extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
|
|
||||||
Title({
|
|
||||||
@required this.station
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<List<String>>(
|
|
||||||
future: Future.wait([
|
|
||||||
station.stationName,
|
|
||||||
station.observations
|
|
||||||
]),
|
|
||||||
builder: (context, items) {
|
|
||||||
return Text(
|
|
||||||
items[0],
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 18 : 22,
|
|
||||||
fontWeight: MediaQuery.of(context).boldText ? FontWeight.w400 : FontWeight.w200,
|
|
||||||
fontStyle: items[1] == "ONI" ? FontStyle.italic : FontStyle.normal,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Time extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
|
|
||||||
Time({
|
|
||||||
@required this.station,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<List<String>>(
|
|
||||||
future: Future.wait([
|
|
||||||
station.arrivalTime,
|
|
||||||
station.stopsFor,
|
|
||||||
station.departureTime,
|
|
||||||
]),
|
|
||||||
builder: (context, items) {
|
|
||||||
if (items[0].isEmpty) {
|
|
||||||
// Plecare
|
|
||||||
return DepartureTime(
|
|
||||||
station: station,
|
|
||||||
firstStation: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (items[2].isEmpty) {
|
|
||||||
// Sosire
|
|
||||||
return ArrivalTime(
|
|
||||||
station: station,
|
|
||||||
finalStation: true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"→",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 18 : 22,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(width: 2,),
|
|
||||||
ArrivalTime(station: station,),
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
StopTime(station: station,),
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
DepartureTime(station: station,),
|
|
||||||
Container(width: 2,),
|
|
||||||
Text(
|
|
||||||
"→",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 18 : 22,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ArrivalTime extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
final bool finalStation;
|
|
||||||
|
|
||||||
ArrivalTime({
|
|
||||||
@required this.station,
|
|
||||||
this.finalStation = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<List<Object>>(
|
|
||||||
future: Future.wait([
|
|
||||||
station.arrivalTime,
|
|
||||||
station.delay,
|
|
||||||
]),
|
|
||||||
builder: (context, data) {
|
|
||||||
if (finalStation) {
|
|
||||||
return Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"→",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: isSmallScreen(context) ? 18 : 22,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(width: 2,),
|
|
||||||
Text("sosire la "),
|
|
||||||
ArrivalTime(station: station,),
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (data[1] == 0) {
|
|
||||||
return Text("${data[0]}");
|
|
||||||
}
|
|
||||||
else if (data[1] as int > 0) {
|
|
||||||
final splits = (data[0] as String).split(":").map((s) => int.parse(s)).toList();
|
|
||||||
|
|
||||||
final now = DateTime.now();
|
|
||||||
final newDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
|
||||||
final oldDate = newDate.subtract(Duration(minutes: data[1] as int));
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"${data[0]}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
color: Colors.red.shade300,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final splits = (data[0] as String).split(":").map((s) => int.parse(s)).toList();
|
|
||||||
|
|
||||||
final now = DateTime.now();
|
|
||||||
final newDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
|
||||||
final oldDate = newDate.subtract(Duration(minutes: data[1] as int));
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"${data[0]}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
color: Colors.green.shade300,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StopTime extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
|
|
||||||
StopTime({
|
|
||||||
@required this.station,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<String>(
|
|
||||||
future: station.stopsFor,
|
|
||||||
builder: (context, stopsFor) {
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"staționează pentru",
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
Builder(
|
|
||||||
builder: (context) {
|
|
||||||
int stopsForInt = int.parse(stopsFor);
|
|
||||||
if (stopsForInt == 1) {
|
|
||||||
return Text(
|
|
||||||
"1 minut",
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if (stopsForInt < 20) {
|
|
||||||
return Text(
|
|
||||||
"$stopsFor minute",
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Text(
|
|
||||||
"$stopsFor de minute",
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DepartureTime extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
final bool firstStation;
|
|
||||||
|
|
||||||
DepartureTime({
|
|
||||||
@required this.station,
|
|
||||||
this.firstStation = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<List<Object>>(
|
|
||||||
future: Future.wait([
|
|
||||||
station.departureTime,
|
|
||||||
station.delay,
|
|
||||||
]),
|
|
||||||
builder: (context, data) {
|
|
||||||
if (firstStation) {
|
|
||||||
return Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Expanded(child: Container(),),
|
|
||||||
Text("plecare la "),
|
|
||||||
DepartureTime(station: station,),
|
|
||||||
Container(width: 2,),
|
|
||||||
Text(
|
|
||||||
"→",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
fontSize: 22,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (data[1] == 0) {
|
|
||||||
return Text("${data[0]}");
|
|
||||||
}
|
|
||||||
else if (data[1] as int > 0) {
|
|
||||||
final splits = (data[0] as String).split(":").map((s) => int.parse(s)).toList();
|
|
||||||
|
|
||||||
final now = DateTime.now();
|
|
||||||
final newDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
|
||||||
final oldDate = newDate.subtract(Duration(minutes: data[1] as int));
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"${data[0]}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
color: Colors.red.shade300,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final splits = (data[0] as String).split(":").map((s) => int.parse(s)).toList();
|
|
||||||
|
|
||||||
final now = DateTime.now();
|
|
||||||
final newDate = DateTime(now.year, now.month, now.day, splits[0], splits[1]);
|
|
||||||
final oldDate = newDate.subtract(Duration(minutes: data[1] as int));
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"${oldDate.hour.toString().padLeft(2, '0')}:${oldDate.minute.toString().padLeft(2, '0')}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
decoration: TextDecoration.lineThrough,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"${data[0]}",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
color: Colors.green.shade300,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class Delay extends StatelessWidget {
|
|
||||||
final OnDemandStation station;
|
|
||||||
|
|
||||||
Delay({
|
|
||||||
@required this.station,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return FutureDisplay<int>(
|
|
||||||
future: station.delay,
|
|
||||||
builder: (context, delay) {
|
|
||||||
if (delay == 0) return Container();
|
|
||||||
|
|
||||||
else if (delay > 0) {
|
|
||||||
return Text(
|
|
||||||
"$delay minute întârziere",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
color: Colors.red.shade300,
|
|
||||||
fontSize: 12,
|
|
||||||
fontStyle: FontStyle.italic,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (delay < 0) {
|
|
||||||
return Text(
|
|
||||||
"${-delay} minute mai devreme",
|
|
||||||
style: Theme.of(context).textTheme.bodyText2.copyWith(
|
|
||||||
color: Colors.green.shade300,
|
|
||||||
fontSize: 12,
|
|
||||||
fontStyle: FontStyle.italic,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Container();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,385 +0,0 @@
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io' show Platform;
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:info_tren/train_info_page/train_info.dart';
|
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
import 'package:tuple/tuple.dart';
|
|
||||||
|
|
||||||
part 'train_info_prompt.g.dart';
|
|
||||||
|
|
||||||
typedef TrainSelectedCallback(int trainNumber);
|
|
||||||
|
|
||||||
mixin TrainInfoPromptCommon {
|
|
||||||
static String routeName = "/trainInfo/chooseTrain";
|
|
||||||
|
|
||||||
onTrainSelected(BuildContext context, int selection) {
|
|
||||||
Navigator.of(context).pushNamed(TrainInfo.routeName, arguments: selection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mixin TrainInfoPromptListHandling {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget getOperatorsListView(BuildContext context, {String currentInput = "", @required TrainSelectedCallback onTrainSelected}) {
|
|
||||||
var sliversTuple = operators.map(
|
|
||||||
(op) => Tuple2(
|
|
||||||
getFilteredLines(op, currentInput),
|
|
||||||
getOperatorSliver(context, op, currentInput, onTrainSelected)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.where((tuple) => tuple.item1.isNotEmpty).toList();
|
|
||||||
if (currentInput.isNotEmpty) sliversTuple.sort((a, b) {
|
|
||||||
final aTrain = a.item1.first;
|
|
||||||
final bTrain = b.item1.first;
|
|
||||||
|
|
||||||
final inputAsRegExp = RegExp(currentInput);
|
|
||||||
|
|
||||||
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) => tuple.item2).toList();
|
|
||||||
|
|
||||||
return CustomScrollView(
|
|
||||||
slivers: <Widget>[
|
|
||||||
...slivers,
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: getUseCurrentInputWidget(currentInput, onTrainSelected),
|
|
||||||
),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Container(
|
|
||||||
height: MediaQuery.of(context).viewPadding.bottom,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget getUseCurrentInputWidget(String currentInput, TrainSelectedCallback onTrainSelected) {
|
|
||||||
if (currentInput.isEmpty) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (int.tryParse(currentInput) == null) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
if (Platform.isAndroid)
|
|
||||||
ListTile(
|
|
||||||
title: Text("Caută trenul cu numărul $currentInput"),
|
|
||||||
onTap: () {
|
|
||||||
onTrainSelected(int.parse(currentInput));
|
|
||||||
},
|
|
||||||
)
|
|
||||||
else if (Platform.isIOS)
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
onTrainSelected(int.parse(currentInput));
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: <Widget>[
|
|
||||||
Text("Caută trenul cu numărul $currentInput")
|
|
||||||
],
|
|
||||||
)
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Divider(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget getOperatorSliver(BuildContext context, TrainOperatorLines _operator, String currentInput, TrainSelectedCallback onTrainSelected) {
|
|
||||||
final filteredLines = getFilteredLines(_operator, currentInput);
|
|
||||||
|
|
||||||
if (filteredLines.isEmpty) {
|
|
||||||
return SliverToBoxAdapter(child: Container(),);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SliverPrototypeExtentList(
|
|
||||||
prototypeItem: Column(
|
|
||||||
children: <Widget>[
|
|
||||||
getLineListItem(
|
|
||||||
context,
|
|
||||||
op: TrainOperatorLines(),
|
|
||||||
line: _TrainOperatorTrainDescription()
|
|
||||||
),
|
|
||||||
Divider(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
delegate: SliverChildBuilderDelegate(
|
|
||||||
(context, index) {
|
|
||||||
return Column(
|
|
||||||
children: <Widget>[
|
|
||||||
getLineListItem(
|
|
||||||
context,
|
|
||||||
op: _operator,
|
|
||||||
line: filteredLines[index],
|
|
||||||
onTrainSelected: onTrainSelected
|
|
||||||
),
|
|
||||||
Divider(),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
childCount: filteredLines.length,
|
|
||||||
addSemanticIndexes: true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget getLineListItem(BuildContext context, {TrainOperatorLines op, _TrainOperatorTrainDescription line, TrainSelectedCallback onTrainSelected}) {
|
|
||||||
if (Platform.isAndroid) {
|
|
||||||
return ListTile(
|
|
||||||
dense: true,
|
|
||||||
title: Text("${line.rang ?? ""} ${line.number ?? ""}"),
|
|
||||||
subtitle: Text(op.operator ?? ""),
|
|
||||||
onTap: () {
|
|
||||||
onTrainSelected(line.internalNumber);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else if (Platform.isIOS) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
onTrainSelected(line.internalNumber);
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
|
|
||||||
child: SizedBox(
|
|
||||||
width: double.infinity,
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
op.operator ?? "",
|
|
||||||
style: CupertinoTheme.of(context).textTheme.textStyle.copyWith(fontSize: 10, fontWeight: FontWeight.w200),
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
"${line.rang ?? ""} ${line.number ?? ""}",
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TrainInfoPromptMaterial extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
_TrainInfoPromptMaterialState createState() => _TrainInfoPromptMaterialState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TrainInfoPromptMaterialState extends State<TrainInfoPromptMaterial> with TrainInfoPromptCommon, TrainInfoPromptListHandling {
|
|
||||||
TextEditingController trainNoController = TextEditingController();
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
loadOperators(context).then((_) {
|
|
||||||
setState(() {});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text("Informații despre tren"),
|
|
||||||
centerTitle: true,
|
|
||||||
),
|
|
||||||
body: SafeArea(
|
|
||||||
bottom: false,
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
children: <Widget>[
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
child: TextField(
|
|
||||||
controller: trainNoController,
|
|
||||||
autofocus: true,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
labelText: "Numărul trenului",
|
|
||||||
),
|
|
||||||
inputFormatters: [
|
|
||||||
FilteringTextInputFormatter.digitsOnly,
|
|
||||||
],
|
|
||||||
textInputAction: TextInputAction.search,
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
onChanged: (_) {
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: getOperatorsListView(context, currentInput: trainNoController.text, onTrainSelected: (number) {
|
|
||||||
onTrainSelected(context, number);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TrainInfoPromptCupertino extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
_TrainInfoPromptCupertinoState createState() => _TrainInfoPromptCupertinoState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TrainInfoPromptCupertinoState extends State<TrainInfoPromptCupertino> with TrainInfoPromptCommon, TrainInfoPromptListHandling {
|
|
||||||
TextEditingController trainNoController = TextEditingController();
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
|
|
||||||
loadOperators(context).then((_) {
|
|
||||||
setState(() {});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return CupertinoPageScaffold(
|
|
||||||
navigationBar: CupertinoNavigationBar(
|
|
||||||
middle: Text("Informații despre tren"),
|
|
||||||
),
|
|
||||||
child: SafeArea(
|
|
||||||
bottom: false,
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
children: <Widget>[
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(4),
|
|
||||||
child: CupertinoTextField(
|
|
||||||
controller: trainNoController,
|
|
||||||
autofocus: true,
|
|
||||||
placeholder: "Numărul trenului",
|
|
||||||
textInputAction: TextInputAction.search,
|
|
||||||
keyboardType: TextInputType.number,
|
|
||||||
onChanged: (_) {
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
inputFormatters: [
|
|
||||||
FilteringTextInputFormatter.digitsOnly,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: getOperatorsListView(
|
|
||||||
context,
|
|
||||||
currentInput: trainNoController.text, onTrainSelected: (number) {
|
|
||||||
onTrainSelected(context, number);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@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({
|
|
||||||
this.operator,
|
|
||||||
this.shortName = "",
|
|
||||||
this.version,
|
|
||||||
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
|
|
||||||
});
|
|
||||||
|
|
||||||
factory _TrainOperatorTrainDescription.fromJson(Map<String, dynamic> json) => _$_TrainOperatorTrainDescriptionFromJson(json);
|
|
||||||
Map<String, dynamic> toJson() => _$_TrainOperatorTrainDescriptionToJson(this);
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'train_info_prompt.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// JsonSerializableGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
TrainOperatorLines _$TrainOperatorLinesFromJson(Map<String, dynamic> json) {
|
|
||||||
return TrainOperatorLines(
|
|
||||||
operator: json['operator'] as String,
|
|
||||||
shortName: json['short_name'] as String,
|
|
||||||
version: json['versiune'] as String,
|
|
||||||
trains: (json['trenuri'] as List)
|
|
||||||
?.map((e) => e == null
|
|
||||||
? null
|
|
||||||
: _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) {
|
|
||||||
return _TrainOperatorTrainDescription(
|
|
||||||
number: json['numar'] as String,
|
|
||||||
rang: json['rang'] as String,
|
|
||||||
internalNumber: json['numar_intern'] as int);
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, dynamic> _$_TrainOperatorTrainDescriptionToJson(
|
|
||||||
_TrainOperatorTrainDescription instance) =>
|
|
||||||
<String, dynamic>{
|
|
||||||
'rang': instance.rang,
|
|
||||||
'numar': instance.number,
|
|
||||||
'numar_intern': instance.internalNumber
|
|
||||||
};
|
|
12
lib/utils/default_ui_design.dart
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:info_tren/models/ui_design.dart';
|
||||||
|
|
||||||
|
UiDesign get defaultUiDesign {
|
||||||
|
if (Platform.isIOS) {
|
||||||
|
return UiDesign.CUPERTINO;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return UiDesign.MATERIAL;
|
||||||
|
}
|
||||||
|
}
|
12
lib/utils/state_to_string.dart
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import 'package:info_tren/models/train_data.dart';
|
||||||
|
|
||||||
|
String stateToString(State state) {
|
||||||
|
switch(state) {
|
||||||
|
case State.PASSING:
|
||||||
|
return 'trecere fără oprire';
|
||||||
|
case State.ARRIVAL:
|
||||||
|
return 'sosire';
|
||||||
|
case State.DEPARTURE:
|
||||||
|
return 'plecare';
|
||||||
|
}
|
||||||
|
}
|
12
lib/utils/string.dart
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
extension TakeWhile on String {
|
||||||
|
String takeWhile(Function charValidator) {
|
||||||
|
StringBuffer output = StringBuffer();
|
||||||
|
|
||||||
|
for (final char in this.codeUnits) {
|
||||||
|
if (charValidator(char)) output.writeCharCode(char);
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,34 +0,0 @@
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io' show Platform;
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
|
||||||
|
|
||||||
/// Evaluates a JavaScript function on the given WebView.
|
|
||||||
///
|
|
||||||
/// The JavaScript function must return a String.
|
|
||||||
///
|
|
||||||
/// On Android, the `String` resulted from the evaluation
|
|
||||||
/// is JSON parsed. On iOS, the `String` is returned as is.
|
|
||||||
///
|
|
||||||
/// Other platforms are not supported. The returned value
|
|
||||||
/// in this case will be `null`.
|
|
||||||
Future<String> wInvoke({
|
|
||||||
@required WebViewController webViewController,
|
|
||||||
@required String jsFunctionContent,
|
|
||||||
bool isFunctionAlready = false
|
|
||||||
}) async {
|
|
||||||
final actualJS = isFunctionAlready ?
|
|
||||||
jsFunctionContent :
|
|
||||||
"""
|
|
||||||
(() => {
|
|
||||||
$jsFunctionContent
|
|
||||||
})()
|
|
||||||
""";
|
|
||||||
|
|
||||||
final res = await webViewController.evaluateJavascript(actualJS);
|
|
||||||
|
|
||||||
if (Platform.isAndroid) return JsonDecoder().convert(res) as String;
|
|
||||||
else if (Platform.isIOS) return res;
|
|
||||||
else return null;
|
|
||||||
}
|
|
196
pubspec.lock
|
@ -1,20 +1,27 @@
|
||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
_fe_analyzer_shared:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: _fe_analyzer_shared
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "24.0.0"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.36.4"
|
version: "2.1.0"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: args
|
name: args
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.2"
|
version: "2.2.0"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -22,69 +29,62 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.1"
|
version: "2.6.1"
|
||||||
boolean_selector:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: boolean_selector
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.0"
|
|
||||||
build:
|
build:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build
|
name: build
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.5"
|
version: "2.1.0"
|
||||||
build_config:
|
build_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_config
|
name: build_config
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.0"
|
version: "1.0.0"
|
||||||
build_daemon:
|
build_daemon:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_daemon
|
name: build_daemon
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "3.0.0"
|
||||||
build_resolvers:
|
build_resolvers:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_resolvers
|
name: build_resolvers
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.6"
|
version: "2.0.4"
|
||||||
build_runner:
|
build_runner:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.6.1"
|
version: "2.1.1"
|
||||||
build_runner_core:
|
build_runner_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_runner_core
|
name: build_runner_core
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.6"
|
version: "7.1.0"
|
||||||
built_collection:
|
built_collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_collection
|
name: built_collection
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.2"
|
version: "5.1.0"
|
||||||
built_value:
|
built_value:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_value
|
name: built_value
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.7.0"
|
version: "8.1.2"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -99,20 +99,27 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
clock:
|
checked_yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: clock
|
name: checked_yaml
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "2.0.1"
|
||||||
|
cli_util:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cli_util
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.3"
|
||||||
code_builder:
|
code_builder:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: code_builder
|
name: code_builder
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.0"
|
version: "4.1.0"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -126,21 +133,14 @@ packages:
|
||||||
name: convert
|
name: convert
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "3.0.1"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: crypto
|
name: crypto
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.6"
|
version: "3.0.1"
|
||||||
csslib:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: csslib
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.16.1"
|
|
||||||
cupertino_icons:
|
cupertino_icons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -154,122 +154,110 @@ packages:
|
||||||
name: dart_style
|
name: dart_style
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.9"
|
version: "2.0.3"
|
||||||
fake_async:
|
file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: fake_async
|
name: file
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "6.1.2"
|
||||||
fixnum:
|
fixnum:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: fixnum
|
name: fixnum
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.10.9"
|
version: "1.0.0"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
flutter_test:
|
flutter_redux:
|
||||||
dependency: "direct dev"
|
dependency: "direct main"
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
front_end:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
description:
|
||||||
name: front_end
|
name: flutter_redux
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.19"
|
version: "0.8.2"
|
||||||
|
frontend_server_client:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: frontend_server_client
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: glob
|
name: glob
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.7"
|
version: "2.0.1"
|
||||||
graphs:
|
graphs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: graphs
|
name: graphs
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0"
|
version: "2.0.0"
|
||||||
html:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: html
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.14.0+2"
|
|
||||||
http:
|
http:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.0+2"
|
version: "0.13.3"
|
||||||
http_multi_server:
|
http_multi_server:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http_multi_server
|
name: http_multi_server
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "3.0.1"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http_parser
|
name: http_parser
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.3"
|
version: "4.0.0"
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: io
|
name: io
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.3"
|
version: "1.0.3"
|
||||||
js:
|
js:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: js
|
name: js
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.1+1"
|
version: "0.6.3"
|
||||||
json_annotation:
|
json_annotation:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: json_annotation
|
name: json_annotation
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.0"
|
version: "4.1.0"
|
||||||
json_serializable:
|
json_serializable:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: json_serializable
|
name: json_serializable
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "5.0.0"
|
||||||
kernel:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: kernel
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.3.19"
|
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: logging
|
name: logging
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.11.3+2"
|
version: "1.0.1"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -283,28 +271,21 @@ packages:
|
||||||
name: meta
|
name: meta
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.7.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: mime
|
name: mime
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.9.6+3"
|
version: "1.0.0"
|
||||||
package_config:
|
package_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: package_config
|
name: package_config
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "2.0.0"
|
||||||
package_resolver:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: package_resolver
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.10"
|
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -318,35 +299,42 @@ packages:
|
||||||
name: pedantic
|
name: pedantic
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.7.0"
|
version: "1.11.1"
|
||||||
pool:
|
pool:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pool
|
name: pool
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.5.0"
|
||||||
pub_semver:
|
pub_semver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pub_semver
|
name: pub_semver
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.2"
|
version: "2.0.0"
|
||||||
pubspec_parse:
|
pubspec_parse:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pubspec_parse
|
name: pubspec_parse
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.4"
|
version: "1.0.0"
|
||||||
quiver:
|
quiver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: quiver
|
name: quiver
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.3"
|
version: "3.0.1"
|
||||||
|
redux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: redux
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.0"
|
||||||
rxdart:
|
rxdart:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -360,14 +348,14 @@ packages:
|
||||||
name: shelf
|
name: shelf
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.5"
|
version: "1.2.0"
|
||||||
shelf_web_socket:
|
shelf_web_socket:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shelf_web_socket
|
name: shelf_web_socket
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.3"
|
version: "1.0.1"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -379,7 +367,14 @@ packages:
|
||||||
name: source_gen
|
name: source_gen
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.9.4+2"
|
version: "1.1.0"
|
||||||
|
source_helper:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_helper
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -407,7 +402,7 @@ packages:
|
||||||
name: stream_transform
|
name: stream_transform
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.19"
|
version: "2.0.0"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -422,27 +417,20 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
test_api:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: test_api
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.3.0"
|
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: timing
|
name: timing
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.1+1"
|
version: "1.0.0"
|
||||||
tuple:
|
tuple:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: tuple
|
name: tuple
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "2.0.0"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -463,28 +451,20 @@ packages:
|
||||||
name: watcher
|
name: watcher
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.9.7+12"
|
version: "1.0.0"
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web_socket_channel
|
name: web_socket_channel
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.14"
|
version: "2.1.0"
|
||||||
webview_flutter:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: webview_flutter
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.3.11+2"
|
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: yaml
|
name: yaml
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.16"
|
version: "3.1.0"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.12.0 <3.0.0"
|
dart: ">=2.12.0 <3.0.0"
|
||||||
flutter: ">=1.5.0"
|
|
||||||
|
|
31
pubspec.yaml
|
@ -1,5 +1,5 @@
|
||||||
name: info_tren
|
name: info_tren
|
||||||
description: O aplicație de vizualizare a datelor puse la dispoziție de Informatica Feroviară.xe
|
description: O aplicație de vizualizare a datelor puse la dispoziție de Informatica Feroviară.
|
||||||
|
|
||||||
# The following defines the version and build number for your application.
|
# The following defines the version and build number for your application.
|
||||||
# A version number is three numbers separated by dots, like 1.2.43
|
# A version number is three numbers separated by dots, like 1.2.43
|
||||||
|
@ -14,7 +14,7 @@ description: O aplicație de vizualizare a datelor puse la dispoziție de Inform
|
||||||
version: 2.0.6
|
version: 2.0.6
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.3.0 <3.0.0"
|
sdk: ">=2.12.0 <3.0.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
|
@ -23,18 +23,17 @@ dependencies:
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
# cupertino_icons: ^0.1.2
|
# cupertino_icons: ^0.1.2
|
||||||
json_annotation: ^2.0.0
|
|
||||||
rxdart: ^0.22.0
|
rxdart: ^0.22.0
|
||||||
http: ^0.12.0
|
http: ^0.13.0
|
||||||
webview_flutter: ^0.3.0
|
|
||||||
cupertino_icons: ^0.1.2
|
cupertino_icons: ^0.1.2
|
||||||
tuple: ^1.0.2
|
tuple: ^2.0.0
|
||||||
|
flutter_redux: ^0.8.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
# flutter_test:
|
||||||
sdk: flutter
|
# sdk: flutter
|
||||||
build_runner: ^1.0.0
|
build_runner: ^2.1.0
|
||||||
json_serializable: ^3.0.0
|
json_serializable: ^5.0.0
|
||||||
|
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
|
@ -64,7 +63,17 @@ flutter:
|
||||||
# "family" key with the font family name, and a "fonts" key with a
|
# "family" key with the font family name, and a "fonts" key with a
|
||||||
# list giving the asset and other descriptors for the font. For
|
# list giving the asset and other descriptors for the font. For
|
||||||
# example:
|
# example:
|
||||||
# fonts:
|
fonts:
|
||||||
|
- family: Atkinson Hyperlegible
|
||||||
|
fonts:
|
||||||
|
- asset: fonts/ah/ah-Regular.ttf
|
||||||
|
- asset: fonts/ah/ah-Italic.ttf
|
||||||
|
style: italic
|
||||||
|
- asset: fonts/ah/ah-Bold.ttf
|
||||||
|
weight: 700
|
||||||
|
- asset: fonts/ah/ah-BoldItalic.ttf
|
||||||
|
weight: 700
|
||||||
|
style: italic
|
||||||
# - family: Schyler
|
# - family: Schyler
|
||||||
# fonts:
|
# fonts:
|
||||||
# - asset: fonts/Schyler-Regular.ttf
|
# - asset: fonts/Schyler-Regular.ttf
|
||||||
|
|
BIN
web/favicon.png
Normal file
After Width: | Height: | Size: 917 B |
BIN
web/icons/Icon-192.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
web/icons/Icon-512.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
BIN
web/icons/Icon-maskable-192.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
BIN
web/icons/Icon-maskable-512.png
Normal file
After Width: | Height: | Size: 20 KiB |
101
web/index.html
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<!--
|
||||||
|
If you are serving your web app in a path other than the root, change the
|
||||||
|
href value below to reflect the base path you are serving from.
|
||||||
|
|
||||||
|
The path provided below has to start and end with a slash "/" in order for
|
||||||
|
it to work correctly.
|
||||||
|
|
||||||
|
For more details:
|
||||||
|
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
|
||||||
|
|
||||||
|
This is a placeholder for base href that will be replaced by the value of
|
||||||
|
the `--base-href` argument provided to `flutter build`.
|
||||||
|
-->
|
||||||
|
<base href="$FLUTTER_BASE_HREF">
|
||||||
|
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||||
|
<meta name="description" content="A new Flutter project.">
|
||||||
|
|
||||||
|
<!-- iOS meta tags & icons -->
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
|
<meta name="apple-mobile-web-app-title" content="info_tren">
|
||||||
|
<link rel="apple-touch-icon" href="icons/Icon-192.png">
|
||||||
|
|
||||||
|
<title>info_tren</title>
|
||||||
|
<link rel="manifest" href="manifest.json">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- This script installs service_worker.js to provide PWA functionality to
|
||||||
|
application. For more information, see:
|
||||||
|
https://developers.google.com/web/fundamentals/primers/service-workers -->
|
||||||
|
<script>
|
||||||
|
var serviceWorkerVersion = null;
|
||||||
|
var scriptLoaded = false;
|
||||||
|
function loadMainDartJs() {
|
||||||
|
if (scriptLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scriptLoaded = true;
|
||||||
|
var scriptTag = document.createElement('script');
|
||||||
|
scriptTag.src = 'main.dart.js';
|
||||||
|
scriptTag.type = 'application/javascript';
|
||||||
|
document.body.append(scriptTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
// Service workers are supported. Use them.
|
||||||
|
window.addEventListener('load', function () {
|
||||||
|
// Wait for registration to finish before dropping the <script> tag.
|
||||||
|
// Otherwise, the browser will load the script multiple times,
|
||||||
|
// potentially different versions.
|
||||||
|
var serviceWorkerUrl = 'flutter_service_worker.js?v=' + serviceWorkerVersion;
|
||||||
|
navigator.serviceWorker.register(serviceWorkerUrl)
|
||||||
|
.then((reg) => {
|
||||||
|
function waitForActivation(serviceWorker) {
|
||||||
|
serviceWorker.addEventListener('statechange', () => {
|
||||||
|
if (serviceWorker.state == 'activated') {
|
||||||
|
console.log('Installed new service worker.');
|
||||||
|
loadMainDartJs();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!reg.active && (reg.installing || reg.waiting)) {
|
||||||
|
// No active web worker and we have installed or are installing
|
||||||
|
// one for the first time. Simply wait for it to activate.
|
||||||
|
waitForActivation(reg.installing || reg.waiting);
|
||||||
|
} else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
|
||||||
|
// When the app updates the serviceWorkerVersion changes, so we
|
||||||
|
// need to ask the service worker to update.
|
||||||
|
console.log('New service worker available.');
|
||||||
|
reg.update();
|
||||||
|
waitForActivation(reg.installing);
|
||||||
|
} else {
|
||||||
|
// Existing service worker is still good.
|
||||||
|
console.log('Loading app from service worker.');
|
||||||
|
loadMainDartJs();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// If service worker doesn't succeed in a reasonable amount of time,
|
||||||
|
// fallback to plaint <script> tag.
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!scriptLoaded) {
|
||||||
|
console.warn(
|
||||||
|
'Failed to load app from service worker. Falling back to plain <script> tag.',
|
||||||
|
);
|
||||||
|
loadMainDartJs();
|
||||||
|
}
|
||||||
|
}, 4000);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Service workers not supported. Just drop the <script> tag.
|
||||||
|
loadMainDartJs();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
35
web/manifest.json
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"name": "info_tren",
|
||||||
|
"short_name": "info_tren",
|
||||||
|
"start_url": ".",
|
||||||
|
"display": "standalone",
|
||||||
|
"background_color": "#0175C2",
|
||||||
|
"theme_color": "#0175C2",
|
||||||
|
"description": "A new Flutter project.",
|
||||||
|
"orientation": "portrait-primary",
|
||||||
|
"prefer_related_applications": false,
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-maskable-192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "icons/Icon-maskable-512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png",
|
||||||
|
"purpose": "maskable"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|