diff --git a/.gitignore b/.gitignore index 6550ed7..05f6f99 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +websockets_from_scratch/ + # Created by https://www.toptal.com/developers/gitignore/api/dart,flutter,androidstudio # Edit at https://www.toptal.com/developers/gitignore?templates=dart,flutter,androidstudio diff --git a/.idea/caches/deviceStreaming.xml b/.idea/caches/deviceStreaming.xml new file mode 100644 index 0000000..61a0a4a --- /dev/null +++ b/.idea/caches/deviceStreaming.xml @@ -0,0 +1,679 @@ + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml new file mode 100644 index 0000000..f1e215f --- /dev/null +++ b/.idea/libraries/Dart_SDK.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml new file mode 100644 index 0000000..b0f6971 --- /dev/null +++ b/.idea/libraries/Flutter_Plugins.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/KotlinJavaRuntime.xml b/.idea/libraries/KotlinJavaRuntime.xml new file mode 100644 index 0000000..2b96ac4 --- /dev/null +++ b/.idea/libraries/KotlinJavaRuntime.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8f3fc05 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.idea/runConfigurations/main_dart.xml b/.idea/runConfigurations/app_main_dart.xml similarity index 51% rename from .idea/runConfigurations/main_dart.xml rename to .idea/runConfigurations/app_main_dart.xml index 9d4cd1e..05640dc 100644 --- a/.idea/runConfigurations/main_dart.xml +++ b/.idea/runConfigurations/app_main_dart.xml @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/.idea/runConfigurations/server_main_dart.xml b/.idea/runConfigurations/server_main_dart.xml new file mode 100644 index 0000000..d51a979 --- /dev/null +++ b/.idea/runConfigurations/server_main_dart.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..7ddfc9e --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 7ac450a..0ff0f8e 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,3 @@ # dispatch -A **mock** ambulance dispatch app, built with Flutter. - -**This software is a work in progress and will only be for training. It MUST NOT be used for any real emergency services operations.** - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +A Flutter app to mock up dispatching emergency ambulances to incidents. **This must not be used for real ambulance operations under any circumstances**. diff --git a/android/dispatch_android.iml b/android/dispatch_android.iml new file mode 100644 index 0000000..f00ee02 --- /dev/null +++ b/android/dispatch_android.iml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..6550ed7 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,227 @@ +# Created by https://www.toptal.com/developers/gitignore/api/dart,flutter,androidstudio +# Edit at https://www.toptal.com/developers/gitignore?templates=dart,flutter,androidstudio + +### Dart ### +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +build/ +# If you're building an application, you may want to check-in your pubspec.lock +pubspec.lock + +# Directory created by dartdoc +# If you don't generate documentation locally you can remove this line. +doc/api/ + +# dotenv environment variables file +.env* + +# Avoid committing generated Javascript files: +*.dart.js +*.info.json # Produced by the --dump-info flag. +*.js # When generated by dart2js. Don't specify *.js if your + # project includes source files written in JavaScript. +*.js_ +*.js.deps +*.js.map + +.flutter-plugins +.flutter-plugins-dependencies + +### Dart Patch ### +# dotenv environment variables file +.env + +### Flutter ### +# Flutter/Dart/Pub related +**/doc/api/ +.fvm/flutter_sdk +.pub-cache/ +.pub/ +coverage/ +lib/generated_plugin_registrant.dart +# For library packages, don’t commit the pubspec.lock file. +# Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies. +# See https://dart.dev/guides/libraries/private-files#pubspeclock +#pubspec.lock + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/key.properties +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/.last_build_id +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages + +### AndroidStudio ### +# Covers files to be ignored for android development using Android Studio. + +# Built application files +*.apk +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ + +# Gradle files +.gradle +.gradle/ + +# Signing files +.signing/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio +/*/build/ +/*/local.properties +/*/out +/*/*/build +/*/*/production +captures/ +.navigation/ +*.ipr +*~ +*.swp + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Android Patch +gen-external-apklibs + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# NDK +obj/ + +# IntelliJ IDEA +*.iml +*.iws +/out/ + +# User-specific configurations +.idea/caches/ +.idea/libraries/ +.idea/shelf/ +.idea/workspace.xml +.idea/tasks.xml +.idea/.name +.idea/compiler.xml +.idea/copyright/profiles_settings.xml +.idea/encodings.xml +.idea/misc.xml +.idea/modules.xml +.idea/scopes/scope_settings.xml +.idea/dictionaries +.idea/vcs.xml +.idea/jsLibraryMappings.xml +.idea/datasources.xml +.idea/dataSources.ids +.idea/sqlDataSources.xml +.idea/dynamic.xml +.idea/uiDesigner.xml +.idea/assetWizardSettings.xml +.idea/gradle.xml +.idea/jarRepositories.xml +.idea/navEditor.xml + +# Legacy Eclipse project files +.classpath +.project +.cproject +.settings/ + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.war +*.ear + +# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml) +hs_err_pid* + +## Plugin-specific files: + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Mongo Explorer plugin +.idea/mongoSettings.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### AndroidStudio Patch ### + +!/gradle/wrapper/gradle-wrapper.jar + +# End of https://www.toptal.com/developers/gitignore/api/dart,flutter,androidstudio \ No newline at end of file diff --git a/.metadata b/app/.metadata similarity index 100% rename from .metadata rename to app/.metadata diff --git a/app/README.md b/app/README.md new file mode 100644 index 0000000..7ac450a --- /dev/null +++ b/app/README.md @@ -0,0 +1,18 @@ +# dispatch + +A **mock** ambulance dispatch app, built with Flutter. + +**This software is a work in progress and will only be for training. It MUST NOT be used for any real emergency services operations.** + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/analysis_options.yaml b/app/analysis_options.yaml similarity index 100% rename from analysis_options.yaml rename to app/analysis_options.yaml diff --git a/android/.gitignore b/app/android/.gitignore similarity index 100% rename from android/.gitignore rename to app/android/.gitignore diff --git a/android/app/build.gradle.kts b/app/android/app/build.gradle.kts similarity index 100% rename from android/app/build.gradle.kts rename to app/android/app/build.gradle.kts diff --git a/android/app/src/debug/AndroidManifest.xml b/app/android/app/src/debug/AndroidManifest.xml similarity index 100% rename from android/app/src/debug/AndroidManifest.xml rename to app/android/app/src/debug/AndroidManifest.xml diff --git a/android/app/src/main/AndroidManifest.xml b/app/android/app/src/main/AndroidManifest.xml similarity index 100% rename from android/app/src/main/AndroidManifest.xml rename to app/android/app/src/main/AndroidManifest.xml diff --git a/android/app/src/main/kotlin/com/example/dispatch/MainActivity.kt b/app/android/app/src/main/kotlin/com/example/dispatch/MainActivity.kt similarity index 100% rename from android/app/src/main/kotlin/com/example/dispatch/MainActivity.kt rename to app/android/app/src/main/kotlin/com/example/dispatch/MainActivity.kt diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/app/android/app/src/main/res/drawable-v21/launch_background.xml similarity index 100% rename from android/app/src/main/res/drawable-v21/launch_background.xml rename to app/android/app/src/main/res/drawable-v21/launch_background.xml diff --git a/android/app/src/main/res/drawable/launch_background.xml b/app/android/app/src/main/res/drawable/launch_background.xml similarity index 100% rename from android/app/src/main/res/drawable/launch_background.xml rename to app/android/app/src/main/res/drawable/launch_background.xml diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-hdpi/ic_launcher.png rename to app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-mdpi/ic_launcher.png rename to app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/android/app/src/main/res/values-night/styles.xml b/app/android/app/src/main/res/values-night/styles.xml similarity index 100% rename from android/app/src/main/res/values-night/styles.xml rename to app/android/app/src/main/res/values-night/styles.xml diff --git a/android/app/src/main/res/values/styles.xml b/app/android/app/src/main/res/values/styles.xml similarity index 100% rename from android/app/src/main/res/values/styles.xml rename to app/android/app/src/main/res/values/styles.xml diff --git a/android/app/src/profile/AndroidManifest.xml b/app/android/app/src/profile/AndroidManifest.xml similarity index 100% rename from android/app/src/profile/AndroidManifest.xml rename to app/android/app/src/profile/AndroidManifest.xml diff --git a/android/build.gradle.kts b/app/android/build.gradle.kts similarity index 100% rename from android/build.gradle.kts rename to app/android/build.gradle.kts diff --git a/android/gradle.properties b/app/android/gradle.properties similarity index 100% rename from android/gradle.properties rename to app/android/gradle.properties diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/app/android/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from android/gradle/wrapper/gradle-wrapper.properties rename to app/android/gradle/wrapper/gradle-wrapper.properties diff --git a/android/settings.gradle.kts b/app/android/settings.gradle.kts similarity index 100% rename from android/settings.gradle.kts rename to app/android/settings.gradle.kts diff --git a/assets/images/dca.jpg b/app/assets/images/dca.jpg similarity index 100% rename from assets/images/dca.jpg rename to app/assets/images/dca.jpg diff --git a/assets/images/dca.png b/app/assets/images/dca.png similarity index 100% rename from assets/images/dca.png rename to app/assets/images/dca.png diff --git a/assets/images/hems-car.jpg b/app/assets/images/hems-car.jpg similarity index 100% rename from assets/images/hems-car.jpg rename to app/assets/images/hems-car.jpg diff --git a/assets/images/hems-car.png b/app/assets/images/hems-car.png similarity index 100% rename from assets/images/hems-car.png rename to app/assets/images/hems-car.png diff --git a/assets/images/rrv.png b/app/assets/images/rrv.png similarity index 100% rename from assets/images/rrv.png rename to app/assets/images/rrv.png diff --git a/assets/images/tvaa.jpg b/app/assets/images/tvaa.jpg similarity index 100% rename from assets/images/tvaa.jpg rename to app/assets/images/tvaa.jpg diff --git a/ios/.gitignore b/app/ios/.gitignore similarity index 100% rename from ios/.gitignore rename to app/ios/.gitignore diff --git a/ios/Flutter/AppFrameworkInfo.plist b/app/ios/Flutter/AppFrameworkInfo.plist similarity index 100% rename from ios/Flutter/AppFrameworkInfo.plist rename to app/ios/Flutter/AppFrameworkInfo.plist diff --git a/ios/Flutter/Debug.xcconfig b/app/ios/Flutter/Debug.xcconfig similarity index 100% rename from ios/Flutter/Debug.xcconfig rename to app/ios/Flutter/Debug.xcconfig diff --git a/ios/Flutter/Release.xcconfig b/app/ios/Flutter/Release.xcconfig similarity index 100% rename from ios/Flutter/Release.xcconfig rename to app/ios/Flutter/Release.xcconfig diff --git a/ios/Runner.xcodeproj/project.pbxproj b/app/ios/Runner.xcodeproj/project.pbxproj similarity index 100% rename from ios/Runner.xcodeproj/project.pbxproj rename to app/ios/Runner.xcodeproj/project.pbxproj diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/app/ios/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from ios/Runner.xcworkspace/contents.xcworkspacedata rename to app/ios/Runner.xcworkspace/contents.xcworkspacedata diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/ios/Runner/AppDelegate.swift b/app/ios/Runner/AppDelegate.swift similarity index 100% rename from ios/Runner/AppDelegate.swift rename to app/ios/Runner/AppDelegate.swift diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png rename to app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json similarity index 100% rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json rename to app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png similarity index 100% rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png rename to app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png similarity index 100% rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png rename to app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png similarity index 100% rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png rename to app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md similarity index 100% rename from ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md rename to app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/app/ios/Runner/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from ios/Runner/Base.lproj/LaunchScreen.storyboard rename to app/ios/Runner/Base.lproj/LaunchScreen.storyboard diff --git a/ios/Runner/Base.lproj/Main.storyboard b/app/ios/Runner/Base.lproj/Main.storyboard similarity index 100% rename from ios/Runner/Base.lproj/Main.storyboard rename to app/ios/Runner/Base.lproj/Main.storyboard diff --git a/ios/Runner/Info.plist b/app/ios/Runner/Info.plist similarity index 100% rename from ios/Runner/Info.plist rename to app/ios/Runner/Info.plist diff --git a/ios/Runner/Runner-Bridging-Header.h b/app/ios/Runner/Runner-Bridging-Header.h similarity index 100% rename from ios/Runner/Runner-Bridging-Header.h rename to app/ios/Runner/Runner-Bridging-Header.h diff --git a/ios/RunnerTests/RunnerTests.swift b/app/ios/RunnerTests/RunnerTests.swift similarity index 100% rename from ios/RunnerTests/RunnerTests.swift rename to app/ios/RunnerTests/RunnerTests.swift diff --git a/lib/api/.gitignore b/app/lib/api/.gitignore similarity index 100% rename from lib/api/.gitignore rename to app/lib/api/.gitignore diff --git a/lib/api/env.dart b/app/lib/api/env.dart similarity index 100% rename from lib/api/env.dart rename to app/lib/api/env.dart diff --git a/lib/api/maps/geocoding.dart b/app/lib/api/maps/geocoding.dart similarity index 100% rename from lib/api/maps/geocoding.dart rename to app/lib/api/maps/geocoding.dart diff --git a/lib/config/dependencies.dart b/app/lib/config/dependencies.dart similarity index 100% rename from lib/config/dependencies.dart rename to app/lib/config/dependencies.dart diff --git a/lib/data/repositories/auth/auth_repository.dart b/app/lib/data/repositories/auth/auth_repository.dart similarity index 100% rename from lib/data/repositories/auth/auth_repository.dart rename to app/lib/data/repositories/auth/auth_repository.dart diff --git a/lib/data/repositories/auth/auth_repository_dev.dart b/app/lib/data/repositories/auth/auth_repository_dev.dart similarity index 100% rename from lib/data/repositories/auth/auth_repository_dev.dart rename to app/lib/data/repositories/auth/auth_repository_dev.dart diff --git a/lib/data/repositories/event/event_repository.dart b/app/lib/data/repositories/event/event_repository.dart similarity index 81% rename from lib/data/repositories/event/event_repository.dart rename to app/lib/data/repositories/event/event_repository.dart index 03f88c4..6f2bcd2 100644 --- a/lib/data/repositories/event/event_repository.dart +++ b/app/lib/data/repositories/event/event_repository.dart @@ -1,4 +1,4 @@ -import '../../../domain/models/event.dart'; +import '../../../domain/models/event/event.dart'; import '../../../utils/result.dart'; /// Data source for events. diff --git a/lib/data/repositories/event/event_repository_local.dart b/app/lib/data/repositories/event/event_repository_local.dart similarity index 96% rename from lib/data/repositories/event/event_repository_local.dart rename to app/lib/data/repositories/event/event_repository_local.dart index f595ef3..530bb9f 100644 --- a/lib/data/repositories/event/event_repository_local.dart +++ b/app/lib/data/repositories/event/event_repository_local.dart @@ -1,4 +1,4 @@ -import '../../../domain/models/event.dart'; +import '../../../domain/models/event/event.dart'; import '../../../domain/models/status.dart'; import '../../../utils/result.dart'; import '../../services/local_data_service.dart'; diff --git a/lib/data/repositories/unit/unit_repository.dart b/app/lib/data/repositories/unit/unit_repository.dart similarity index 100% rename from lib/data/repositories/unit/unit_repository.dart rename to app/lib/data/repositories/unit/unit_repository.dart diff --git a/app/lib/data/services/api/api_client.dart b/app/lib/data/services/api/api_client.dart new file mode 100644 index 0000000..babdf31 --- /dev/null +++ b/app/lib/data/services/api/api_client.dart @@ -0,0 +1,26 @@ +import 'package:web_socket_channel/web_socket_channel.dart'; + +class ApiClient { + ApiClient({required this.host, required this.port}); + + WebSocketChannel? _channel; + + WebSocketChannel? get channel => _channel; + + Uri get _channelUri => Uri(scheme: 'ws', host: host, port: port); + + WebSocketChannel connect() { + _channel = WebSocketChannel.connect(_channelUri); + return channel!; + } + + final String host; + + final int port; + + Stream get stream => channel!.stream; + + void get requestEvents => channel!.sink.add('events'); + + void get requestUnits => channel!.sink.add('units'); +} diff --git a/app/lib/data/services/local_data_service.dart b/app/lib/data/services/local_data_service.dart new file mode 100644 index 0000000..942725c --- /dev/null +++ b/app/lib/data/services/local_data_service.dart @@ -0,0 +1,129 @@ +// Copyright 2024 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:latlng/latlng.dart'; + +import '../../domain/models/event/event.dart'; +import '../../domain/models/noc.dart'; +import '../../domain/models/unit/unit.dart'; +import '../../domain/models/user/user.dart'; + +class LocalDataService { + LocalDataService() : _events = _defaultEvents, _units = _defaultUnits; + + final List _events; + + List get events => _events; + + final List _units; + + List get units => _units; + + User get user { + return const User( + name: 'Sofie', + esr: 12353248763, + // For demo purposes we use a local asset + picture: 'assets/user.jpg', + ); + } +} + +/// A default list of units. +final List _defaultUnits = [ + Unit( + callsign: 'NA136', + location: LatLng( + Angle.degree(51.607539604000266), + Angle.degree(-1.237806756282358), + ), + ), + Unit( + callsign: 'NA402', + location: LatLng(Angle.degree(51.605), Angle.degree(-1.238)), + ), + Unit( + callsign: 'NA283', + location: LatLng( + Angle.degree(51.616072911907786), + Angle.degree(-1.2536017723108663), + ), + ), + Unit( + callsign: 'NA072', + location: LatLng( + Angle.degree(51.8296012219854), + Angle.degree(-1.3134667111590494), + ), + ), + Unit( + callsign: 'NF159', + location: LatLng( + Angle.degree(51.62832936052779), + Angle.degree(-1.1854888181805424), + ), + vehicleType: VehicleType.communityFirstResponder, + ), + Unit( + callsign: 'NR154', + location: LatLng( + Angle.degree(51.66706110914126), + Angle.degree(-1.3082872829130447), + ), + vehicleType: VehicleType.criticalCareCar, + ), + Unit( + callsign: 'NT431', + location: LatLng( + Angle.degree(51.397809576171085), + Angle.degree(-1.3230646597735394), + ), + vehicleType: VehicleType.rrv, + ), + Unit( + callsign: '0024', + location: LatLng( + Angle.degree(51.61832936052779), + Angle.degree(-1.0854888181805424), + ), + vehicleType: VehicleType.helicopter, + ), +]; + +/// A default list of events. +final List _defaultEvents = [ + Event.preAlert(id: 423124, address: 'Sainsbury\'s Kidlington'), + Event.preAlert(id: 423125, address: '47 Hamble Drive Abingdon'), + Event.withNOC( + id: 423129, + address: 'Carfax Tower, Oxford', + noc: Cat2NOC.c2Stabbing(), + )..assignedUnits = [_defaultUnits[2]], + Event.withNOC( + id: 423126, + address: '25 Old Union Way, Thame', + noc: Cat4NOC.medicalMinor(), + )..assignedUnits = [_defaultUnits[1]], + Event.withNOC( + id: 423127, + address: '6 The Greenway, Oxfordshire', + noc: Cat1NOC.c1ArrestPeriArrest(), + ) + ..assignedUnits = [ + _defaultUnits[0], + _defaultUnits[4], + _defaultUnits[6], + _defaultUnits[7], + ], + Event.withNOC( + id: 423128, + address: 'Thatcham Station', + noc: Cat4NOC.mentalHealth(), + )..assignedUnits = [_defaultUnits[5]], + Event.withNOC( + id: 423130, + address: 'Next, Westgate Shopping Centre, Oxford', + noc: Cat3NOC.fallInjuriesUnknown(), + )..assignedUnits = [_defaultUnits[3]], +]; diff --git a/app/lib/domain/models/event/category.dart b/app/lib/domain/models/event/category.dart new file mode 100644 index 0000000..189ea08 --- /dev/null +++ b/app/lib/domain/models/event/category.dart @@ -0,0 +1,30 @@ +import '../status.dart'; + +/// The category assigned to an [Event]. +enum Category { + one('1'), + two('2'), + three('3'), + four('4'), + none('0'); + + const Category(this.number); + + List get nocs => switch (this) { + Category.one => catOneNOCs, + Category.two => catTwoNOCs, + Category.three => catThreeNOCs, + Category.four => catFourNOCs, + Category.none => List.empty(), + }; + + final String number; + + String toJson() => name; + + @override + String toString() => switch (this) { + Category.none => '', + _ => 'C$number', + }; +} diff --git a/app/lib/domain/models/event/category_colour.dart b/app/lib/domain/models/event/category_colour.dart new file mode 100644 index 0000000..f8de8de --- /dev/null +++ b/app/lib/domain/models/event/category_colour.dart @@ -0,0 +1,12 @@ +import 'package:dispatch/domain/models/event/category.dart'; +import 'package:flutter/material.dart'; + +extension CategoryColour on Category { + Color get colour => switch (this) { + Category.one => Colors.purple, + Category.two => Colors.red, + Category.three => Colors.yellow, + Category.four => Colors.green, + Category.none => Colors.grey, + }; +} diff --git a/lib/domain/models/event.dart b/app/lib/domain/models/event/event.dart similarity index 60% rename from lib/domain/models/event.dart rename to app/lib/domain/models/event/event.dart index 282b69e..e1575e3 100644 --- a/lib/domain/models/event.dart +++ b/app/lib/domain/models/event/event.dart @@ -1,24 +1,22 @@ -import 'dart:collection'; - -import 'package:flutter/material.dart'; +// import 'package:flutter/material.dart'; // import 'package:flutter_google_maps_webservices/geocoding.dart'; // import 'package:google_maps_flutter/google_maps_flutter.dart'; // import '../../../api/maps/geocoding.dart'; // import '../../map.dart'; -import 'status.dart'; -import 'unit/unit.dart'; +// import 'package:flutter/foundation.dart'; +import 'package:latlng/latlng.dart'; + +import '../status.dart'; +import '../unit/unit.dart'; +import 'category.dart'; /// An emergency event that the ambulance service has become aware of. class Event { - Event._({ - required this.id, - required this.address, - required this.status, - required this.category, - }) { - if (status == Status.preAlert()) { + Event._({required this.id, required this.address, required this.status}) + : category = status.category { + if (status == EventStatus.preAlert()) { assert(category == Category.none); } @@ -28,12 +26,15 @@ class Event { } Event.preAlert({required int id, required String address}) - : this._( - id: id, - address: address, - status: Status.preAlert(), - category: Category.none, - ); + : this._(id: id, address: address, status: EventStatus.preAlert()); + + factory Event.fromJson(Map json) { + return switch (json) { + {'id': int id, 'address': String address, 'status': EventStatus status} => + Event._(id: id, address: address, status: status), + _ => throw const FormatException('Failed to load album.'), + }; + } factory Event.withNOC({ required int id, @@ -130,7 +131,7 @@ class Event { void addNOC(NOC noc) { if (_noc == null) { _noc = noc; - status = Status.nhs999(noc.category); + status = EventStatus.nhs999(noc.category); category = noc.category; } else { throw Exception( @@ -160,21 +161,11 @@ class Event { Category category; - // // TODO vary the icon based on the category of event. - // /// Path to the image used as this [Event]'s icon. - // String? get _iconAsset => null; - /// A unique numerical identifier. final int id; - // /// Latitude. - // double get lat => location.lat; - // - // /// Longitude. - // double get lng => location.lng; - // - // /// The latitude and longitude of the emergency. - // late Location location; + /// The latitude and longitude of the emergency. + late LatLng location; // /// Returns the latitude and longitude of a given street [address]. // Future _locationFromAddress() async { @@ -185,91 +176,24 @@ class Event { // return location; // } - // /// Gets a [Marker] for showing this [Event] on a map. - // Marker get mapMarker { - // final String id = this.id.toString(); - // - // return Marker( - // markerId: MarkerId(id), - // position: LatLng(lat, lng), - // icon: - // (_iconAsset != null) - // ? markerIcon(_iconAsset!) - // : BitmapDescriptor.defaultMarker, - // infoWindow: InfoWindow( - // title: 'Event $id (cat ${category.number})', - // snippet: address, - // ), - // ); - // } - /// Nature of Call. NOC? _noc; /// Nature of Call. NOC? get noc => _noc; - Status status; -} - -/// Storage for all the events that units will respond to. -class EventListModel extends ChangeNotifier { - EventListModel({required List events}) { - _events.addAll(events); - } + EventStatus status; - EventListModel.blank(); - - /// Internal, private state of the event list. - final List _events = []; - - /// An unmodifiable view of the events in the event list. - UnmodifiableListView get events => UnmodifiableListView(_events); - - /// The current total number of events. - int get numEvents => _events.length; - - /// Adds [event] to event list. This and [removeAll] are the only ways to - /// modify the event list from the outside. - void add(Event event) { - _events.add(event); - // This call tells the widgets that are listening to this model to rebuild. - notifyListeners(); - } - - /// Removes all events from the event list. - void removeAll() { - _events.clear(); - // This call tells the widgets that are listening to this model to rebuild. - notifyListeners(); - } -} - -/// The category assigned to an [Event]. -enum Category { - one('1', Colors.purple), - two('2', Colors.red), - three('3', Colors.yellow), - four('4', Colors.green), - none('0', Colors.grey); - - const Category(this.number, this.colour); - - final Color colour; - - List get nocs => switch (this) { - Category.one => catOneNOCs, - Category.two => catTwoNOCs, - Category.three => catThreeNOCs, - Category.four => catFourNOCs, - Category.none => List.empty(), + Map toJson() => { + 'id': id, + 'category': category.toJson(), + 'noc': noc, + 'address': address, + 'assignedUnits': List.from( + assignedUnits.map((Unit assignedUnit) => assignedUnit.callsign), + ), }; - final String number; - @override - String toString() => switch (this) { - Category.none => '', - _ => 'C$number', - }; + String toString() => 'Event $id'; } diff --git a/app/lib/domain/models/event/event_list_model.dart b/app/lib/domain/models/event/event_list_model.dart new file mode 100644 index 0000000..088efe1 --- /dev/null +++ b/app/lib/domain/models/event/event_list_model.dart @@ -0,0 +1,38 @@ +import 'dart:collection'; + +import 'package:flutter/foundation.dart'; + +import 'event.dart'; + +/// Storage for all the events that units will respond to. +class EventListModel extends ChangeNotifier { + EventListModel({required List events}) { + _events.addAll(events); + } + + EventListModel.blank(); + + /// Internal, private state of the event list. + final List _events = []; + + /// An unmodifiable view of the events in the event list. + UnmodifiableListView get events => UnmodifiableListView(_events); + + /// The current total number of events. + int get numEvents => _events.length; + + /// Adds [event] to event list. This and [removeAll] are the only ways to + /// modify the event list from the outside. + void add(Event event) { + _events.add(event); + // This call tells the widgets that are listening to this model to rebuild. + notifyListeners(); + } + + /// Removes all events from the event list. + void removeAll() { + _events.clear(); + // This call tells the widgets that are listening to this model to rebuild. + notifyListeners(); + } +} diff --git a/app/lib/domain/models/event/event_map_marker.dart b/app/lib/domain/models/event/event_map_marker.dart new file mode 100644 index 0000000..6654f97 --- /dev/null +++ b/app/lib/domain/models/event/event_map_marker.dart @@ -0,0 +1,34 @@ +import 'package:google_maps_flutter/google_maps_flutter.dart'; + +import '../../../map.dart'; +import 'event.dart'; + +extension EventMapMarker on Event { + // TODO vary the icon based on the category of event. + /// Path to the image used as this [Event]'s icon. + String? get _iconAsset => + throw UnimplementedError('Event._iconAsset is not yet implemented.'); + + /// Latitude. + double get lat => location.latitude.degrees; + + /// Longitude. + double get lng => location.longitude.degrees; + + /// Gets a [Marker] for showing this [Event] on a map. + Marker get mapMarker { + final String id = this.id.toString(); + + return Marker( + markerId: MarkerId(id), + position: LatLng(lat, lng), + icon: (_iconAsset != null) + ? markerIcon(_iconAsset!) + : BitmapDescriptor.defaultMarker, + infoWindow: InfoWindow( + title: 'Event $id (cat ${category.number})', + snippet: address, + ), + ); + } +} diff --git a/lib/domain/models/noc.dart b/app/lib/domain/models/noc.dart similarity index 95% rename from lib/domain/models/noc.dart rename to app/lib/domain/models/noc.dart index 2b1e453..2ee1e49 100644 --- a/lib/domain/models/noc.dart +++ b/app/lib/domain/models/noc.dart @@ -1,8 +1,9 @@ -import 'event.dart'; +import 'event/category.dart'; import 'status.dart'; final class Cat1NOC extends NOC { - const Cat1NOC._({required description}) : super(Category.one, description); + const Cat1NOC._({required String description}) + : super(Category.one, description); const Cat1NOC.c1ArrestPeriArrest() : this._(description: 'C1 Arrest/Peri Arrest'); @@ -28,7 +29,8 @@ final class Cat1NOC extends NOC { } final class Cat2NOC extends NOC { - const Cat2NOC._({required description}) : super(Category.two, description); + const Cat2NOC._({required String description}) + : super(Category.two, description); const Cat2NOC.allergicReaction() : this._(description: 'Allergic Reaction'); const Cat2NOC.bleedingSpecify() @@ -72,7 +74,8 @@ final class Cat2NOC extends NOC { } final class Cat3NOC extends NOC { - const Cat3NOC._({required description}) : super(Category.three, description); + const Cat3NOC._({required String description}) + : super(Category.three, description); const Cat3NOC.abdominalFlankPain() : this._(description: 'Abdominal/Flank Pain'); @@ -95,7 +98,8 @@ final class Cat3NOC extends NOC { } final class Cat4NOC extends NOC { - const Cat4NOC._({required description}) : super(Category.four, description); + const Cat4NOC._({required String description}) + : super(Category.four, description); const Cat4NOC.animalInsectsBitesOrStingsMinor() : this._(description: 'Animal/Insects Bites or Stings (minor)'); diff --git a/lib/domain/models/status.dart b/app/lib/domain/models/status.dart similarity index 91% rename from lib/domain/models/status.dart rename to app/lib/domain/models/status.dart index 91cd3e4..884874e 100644 --- a/lib/domain/models/status.dart +++ b/app/lib/domain/models/status.dart @@ -1,20 +1,23 @@ -import 'event.dart'; +import 'event/category.dart'; -interface class Status { - const Status(this.category, this.description); +interface class EventStatus { + const EventStatus(this.category, this.description); - /// Creates an emergency ambulance [Status]. - const factory Status.nhs999(Category category) = PathwaysDisposition._nhs999; + /// Creates an emergency ambulance [EventStatus]. + const factory EventStatus.nhs999(Category category) = + PathwaysDisposition._nhs999; - const Status.preAlert() : category = null, description = _preAlert; + const EventStatus.preAlert() + : category = Category.none, + description = _preAlert; @override bool operator ==(Object other) => - other is Status && + other is EventStatus && (other.category == category) && (other.description == description); - final Category? category; + final Category category; final String description; @@ -27,7 +30,7 @@ interface class Status { String toString() => description; } -base class PathwaysDisposition extends Status { +base class PathwaysDisposition extends EventStatus { const PathwaysDisposition._(super.category, super.description); const PathwaysDisposition._nhs999(Category category) @@ -35,7 +38,7 @@ base class PathwaysDisposition extends Status { } /// Nature of Call. -abstract class NOC extends Status { +abstract class NOC extends EventStatus { const NOC(super.category, super.description) : specify = false; const NOC.withSpecify(super.category, super.description) : specify = true; @@ -44,9 +47,6 @@ abstract class NOC extends Status { // /// The extra details provided in response to a "Specify..." prompt. // final String detail; - @override - Category get category => super.category!; - final bool specify; static List get cat1 => catOneNOCs; @@ -57,6 +57,8 @@ abstract class NOC extends Status { static List get cat4 => catFourNOCs; + String toJson() => toString(); + @override String toString() { final String catNumber = category.number; @@ -66,7 +68,8 @@ abstract class NOC extends Status { } final class Cat1NOC extends NOC { - const Cat1NOC._({required description}) : super(Category.one, description); + const Cat1NOC._({required String description}) + : super(Category.one, description); const Cat1NOC.c1ArrestPeriArrest() : this._(description: 'C1 Arrest/Peri Arrest'); @@ -92,7 +95,8 @@ final class Cat1NOC extends NOC { } final class Cat2NOC extends NOC { - const Cat2NOC._({required description}) : super(Category.two, description); + const Cat2NOC._({required String description}) + : super(Category.two, description); const Cat2NOC.allergicReaction() : this._(description: 'Allergic Reaction'); const Cat2NOC.bleedingSpecify() @@ -136,7 +140,8 @@ final class Cat2NOC extends NOC { } final class Cat3NOC extends NOC { - const Cat3NOC._({required description}) : super(Category.three, description); + const Cat3NOC._({required String description}) + : super(Category.three, description); const Cat3NOC.abdominalFlankPain() : this._(description: 'Abdominal/Flank Pain'); @@ -159,7 +164,8 @@ final class Cat3NOC extends NOC { } final class Cat4NOC extends NOC { - const Cat4NOC._({required description}) : super(Category.four, description); + const Cat4NOC._({required String description}) + : super(Category.four, description); const Cat4NOC.animalInsectsBitesOrStingsMinor() : this._(description: 'Animal/Insects Bites or Stings (minor)'); diff --git a/app/lib/domain/models/unit/unit.dart b/app/lib/domain/models/unit/unit.dart new file mode 100644 index 0000000..de5cbb2 --- /dev/null +++ b/app/lib/domain/models/unit/unit.dart @@ -0,0 +1,40 @@ +import 'package:latlng/latlng.dart'; + +/// An ambulance vehicle, air ambulance or other resource. +class Unit { + Unit({ + required this.callsign, + required this.location, + this.vehicleType = VehicleType.dca, + }); + + /// A unique identifier for this resource. + final String callsign; + + /// The current latitude and longitude of this unit. + LatLng location; + + Map toJson() => { + 'callsign': callsign, + 'vehicleType': vehicleType.toString(), + 'location': [location.latitude.degrees, location.longitude.degrees], + }; + + @override + String toString() => callsign; + + /// The type of vehicle that this is. + final VehicleType vehicleType; +} + +enum VehicleType { + dca('Double-Crewed Ambulance'), + rrv('Rapid Response Vehicle'), + helicopter('Air Ambulance Helicopter'), + criticalCareCar('Critical Care Car'), + communityFirstResponder('Community First Responder'); + + const VehicleType(this.name); + + final String name; +} diff --git a/lib/domain/models/unit/unit.dart b/app/lib/domain/models/unit/unit_map_marker.dart similarity index 50% rename from lib/domain/models/unit/unit.dart rename to app/lib/domain/models/unit/unit_map_marker.dart index d3a185a..8c66e18 100644 --- a/lib/domain/models/unit/unit.dart +++ b/app/lib/domain/models/unit/unit_map_marker.dart @@ -1,51 +1,27 @@ +import 'package:dispatch/domain/models/unit/unit.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import '../../../map.dart'; -/// An ambulance vehicle, air ambulance or other resource. -class Unit { - Unit({ - required this.callsign, - required this.location, - this.vehicleType = VehicleType.dca, - }); - - /// A unique identifier for this resource. - final String callsign; - +extension UnitMapMarker on Unit { /// Path to the image used as this [Event]'s icon. String get _iconAsset => switch (vehicleType) { VehicleType.dca => 'assets/images/dca.png', VehicleType.rrv => 'assets/images/rrv.png', VehicleType.helicopter => 'assets/images/tvaa.jpg', VehicleType.criticalCareCar => 'assets/images/hems-car.png', + // FIXME: give the CFR a unique image. + VehicleType.communityFirstResponder => 'assets/images/rrv.png', }; - /// The current latitude and longitude of this unit. - LatLng location; - /// Gets a [Marker] for showing this [Unit] on a map. Marker get mapMarker => Marker( markerId: MarkerId(callsign), - position: LatLng(location.latitude, location.longitude), + position: LatLng(location.latitude.degrees, location.longitude.degrees), icon: markerIcon(_iconAsset), infoWindow: InfoWindow( title: '$callsign (${vehicleType.name})', snippet: location.toString(), ), ); - - /// The type of vehicle that this is. - final VehicleType vehicleType; -} - -enum VehicleType { - dca('Double-Crewed Ambulance'), - rrv('Rapid Response Vehicle'), - helicopter('Air Ambulance Helicopter'), - criticalCareCar('Critical Care Car'); - - const VehicleType(this.name); - - final String name; } diff --git a/app/lib/domain/models/unit/unit_status.dart b/app/lib/domain/models/unit/unit_status.dart new file mode 100644 index 0000000..714510e --- /dev/null +++ b/app/lib/domain/models/unit/unit_status.dart @@ -0,0 +1,101 @@ +/// @docImport 'unit.dart'; +library; + +import 'package:flutter/material.dart'; + +/// Possible statuses for a [Unit] to show its current activity. +enum UnitStatus { + pd('PD', 'Pre-Duty'), + ab('AB', 'Available Base'), + ds('DS', 'Dispatched to Standby'), + av('AV', 'Available - Voice'), + af('AF', 'Available - Foot'), + am('AM', 'Available - MDT'), + ra('RA', 'Available - Returning'), + sb('SB', 'Available - Standby'), + ms('MS', 'Mobile - Standby'), + dp('DP', 'Dispatched'), + mo('MO', 'Mobile'), + as('AS', 'At Scene'), + ls('LS', 'Left Scene'), + ah('AH', 'At Hospital'), + ho('HO', 'Handover'), + vc('VC', 'Vehicle Clear'), + rt('RT', 'Request Transport'), + nt('NT', 'No Transport Required'), + rv('RV', 'At Scene - RV Point'), + wp('WP', 'With Patient'), + ak('AK', 'Acknowledgement'), + os('OS', 'Out of Service'); + + const UnitStatus(this.abbreviation, this.name); + + final String abbreviation; + + final String name; + + /// Gets the colour to display in the [Unit]'s row of the unit screen. + Color get backgroundColour => switch (this) { + UnitStatus.pd => Colors.grey, + + UnitStatus.ab => Colors.orange, + + UnitStatus.ds || + UnitStatus.av || + UnitStatus.af || + UnitStatus.am || + UnitStatus.sb || + UnitStatus.ms => Colors.lightGreenAccent, + + UnitStatus.ra => Colors.green.shade900, + + UnitStatus.dp || + UnitStatus.as || + UnitStatus.ls || + UnitStatus.ah || + UnitStatus.ho || + UnitStatus.nt || + UnitStatus.rv || + UnitStatus.wp || + UnitStatus.ak => Colors.red, + + UnitStatus.mo => Colors.pinkAccent, + + UnitStatus.vc => Colors.lightBlueAccent.shade200, + + UnitStatus.rt => Colors.red.shade900, + + UnitStatus.os => Colors.black, + }; + + /// White text = Are doing, Grey text = Awaiting, Black text = Have actioned. + Color get fontColour => switch (this) { + /// White: Are doing + UnitStatus.pd || + UnitStatus.ds || + UnitStatus.av || + UnitStatus.af || + UnitStatus.am || + UnitStatus.ra || + UnitStatus.ms || + UnitStatus.mo || + UnitStatus.rt || + UnitStatus.os => Colors.white, + + /// Grey: Awaiting + UnitStatus.ds || UnitStatus.dp => Colors.grey, + + /// Black: Have actioned + UnitStatus.ab || + UnitStatus.sb || + UnitStatus.as || + UnitStatus.ls || + UnitStatus.ah || + UnitStatus.ho || + UnitStatus.vc || + UnitStatus.nt || + UnitStatus.rv || + UnitStatus.wp || + UnitStatus.ak => Colors.black, + }; +} diff --git a/lib/domain/models/user/user.dart b/app/lib/domain/models/user/user.dart similarity index 100% rename from lib/domain/models/user/user.dart rename to app/lib/domain/models/user/user.dart diff --git a/lib/main.dart b/app/lib/main.dart similarity index 94% rename from lib/main.dart rename to app/lib/main.dart index 5a72d7e..438b7f2 100644 --- a/lib/main.dart +++ b/app/lib/main.dart @@ -3,10 +3,7 @@ import 'package:provider/provider.dart'; import 'api/env.dart'; import 'config/dependencies.dart'; -// import 'data/services/local_data_service.dart'; -import 'domain/models/event.dart'; -// import 'domain/models/unit.dart'; -// import 'map.dart'; +import 'domain/models/event/event_list_model.dart'; import 'routing/router.dart'; void main() async { diff --git a/lib/map.dart b/app/lib/map.dart similarity index 93% rename from lib/map.dart rename to app/lib/map.dart index 8f459ba..145dec4 100644 --- a/lib/map.dart +++ b/app/lib/map.dart @@ -1,8 +1,10 @@ import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'domain/models/event.dart'; +import 'domain/models/event/event.dart'; +// import 'domain/models/event/event_map_marker.dart'; import 'domain/models/unit/unit.dart'; +import 'domain/models/unit/unit_map_marker.dart'; /// A page that displays a Google Maps map. class MapPage extends StatefulWidget { @@ -39,7 +41,7 @@ class _MapPageState extends State { bool showUnits = true; Set get _markers => { - // FIXME fix event markers + // // FIXME fix _iconAsset for event markers // ...(showEvents) ? widget.events.map((Event event) => event.mapMarker) : {}, ...(showUnits) ? widget.units.map((Unit unit) => unit.mapMarker) : {}, }; diff --git a/lib/routing/router.dart b/app/lib/routing/router.dart similarity index 79% rename from lib/routing/router.dart rename to app/lib/routing/router.dart index 3f07f8e..80a830d 100644 --- a/lib/routing/router.dart +++ b/app/lib/routing/router.dart @@ -2,13 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; +import 'package:web_socket_channel/web_socket_channel.dart'; import '../data/repositories/auth/auth_repository.dart'; -import '../ui/home/view_models/home_viewmodel.dart'; -import '../ui/home/widgets/home_screen.dart'; +import '../data/services/api/api_client.dart'; +// import '../ui/home/view_models/home_viewmodel.dart'; +// import '../ui/home/widgets/home_screen.dart'; import 'routes.dart'; /// Top go_router entry point. @@ -34,8 +36,34 @@ GoRouter router(AuthRepository authRepository) => GoRouter( GoRoute( path: Routes.home, builder: (context, state) { - final viewModel = HomeViewModel(eventRepository: context.read()); - return HomeScreen(viewModel: viewModel); + // TODO move this StreamBuilder test to a new Widget and revert to the Home widget. + ApiClient client = ApiClient(host: 'localhost', port: 8080); + WebSocketChannel channel = client.connect(); + // client.requestUnits; + client.requestEvents; + + return Scaffold( + appBar: AppBar(title: Text('StreamBuilder test')), + body: Center( + child: StreamBuilder( + stream: channel.stream, + builder: (context, snapshot) => + switch (snapshot.connectionState) { + ConnectionState.none => Text('None'), + ConnectionState.waiting => CircularProgressIndicator(), + ConnectionState.active => Text( + 'Active\n\n' + '${snapshot.data}', + textAlign: TextAlign.center, + ), + ConnectionState.done => Text('Done'), + }, + ), + ), + ); + + // final viewModel = HomeViewModel(eventRepository: context.read()); + // return HomeScreen(viewModel: viewModel); }, routes: [ GoRoute( diff --git a/lib/routing/routes.dart b/app/lib/routing/routes.dart similarity index 100% rename from lib/routing/routes.dart rename to app/lib/routing/routes.dart diff --git a/lib/ui/home/view_models/.gitkeep b/app/lib/ui/home/view_models/.gitkeep similarity index 100% rename from lib/ui/home/view_models/.gitkeep rename to app/lib/ui/home/view_models/.gitkeep diff --git a/lib/ui/home/view_models/home_viewmodel.dart b/app/lib/ui/home/view_models/home_viewmodel.dart similarity index 96% rename from lib/ui/home/view_models/home_viewmodel.dart rename to app/lib/ui/home/view_models/home_viewmodel.dart index c6f151e..de0dcac 100644 --- a/lib/ui/home/view_models/home_viewmodel.dart +++ b/app/lib/ui/home/view_models/home_viewmodel.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import '../../../data/repositories/event/event_repository.dart'; -import '../../../domain/models/event.dart'; +import '../../../domain/models/event/category_colour.dart'; +import '../../../domain/models/event/event.dart'; import '../../../utils/result.dart'; class HomeViewModel extends ChangeNotifier { diff --git a/lib/ui/home/widgets/home_screen.dart b/app/lib/ui/home/widgets/home_screen.dart similarity index 100% rename from lib/ui/home/widgets/home_screen.dart rename to app/lib/ui/home/widgets/home_screen.dart diff --git a/lib/utils/result.dart b/app/lib/utils/result.dart similarity index 100% rename from lib/utils/result.dart rename to app/lib/utils/result.dart diff --git a/linux/.gitignore b/app/linux/.gitignore similarity index 100% rename from linux/.gitignore rename to app/linux/.gitignore diff --git a/linux/CMakeLists.txt b/app/linux/CMakeLists.txt similarity index 100% rename from linux/CMakeLists.txt rename to app/linux/CMakeLists.txt diff --git a/linux/flutter/CMakeLists.txt b/app/linux/flutter/CMakeLists.txt similarity index 100% rename from linux/flutter/CMakeLists.txt rename to app/linux/flutter/CMakeLists.txt diff --git a/app/linux/flutter/generated_plugin_registrant.cc b/app/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..e71a16d --- /dev/null +++ b/app/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,11 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + + +void fl_register_plugins(FlPluginRegistry* registry) { +} diff --git a/app/linux/flutter/generated_plugin_registrant.h b/app/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/app/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/app/linux/flutter/generated_plugins.cmake b/app/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..2e1de87 --- /dev/null +++ b/app/linux/flutter/generated_plugins.cmake @@ -0,0 +1,23 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/linux/runner/CMakeLists.txt b/app/linux/runner/CMakeLists.txt similarity index 100% rename from linux/runner/CMakeLists.txt rename to app/linux/runner/CMakeLists.txt diff --git a/linux/runner/main.cc b/app/linux/runner/main.cc similarity index 100% rename from linux/runner/main.cc rename to app/linux/runner/main.cc diff --git a/linux/runner/my_application.cc b/app/linux/runner/my_application.cc similarity index 100% rename from linux/runner/my_application.cc rename to app/linux/runner/my_application.cc diff --git a/linux/runner/my_application.h b/app/linux/runner/my_application.h similarity index 100% rename from linux/runner/my_application.h rename to app/linux/runner/my_application.h diff --git a/macos/.gitignore b/app/macos/.gitignore similarity index 100% rename from macos/.gitignore rename to app/macos/.gitignore diff --git a/macos/Flutter/Flutter-Debug.xcconfig b/app/macos/Flutter/Flutter-Debug.xcconfig similarity index 100% rename from macos/Flutter/Flutter-Debug.xcconfig rename to app/macos/Flutter/Flutter-Debug.xcconfig diff --git a/macos/Flutter/Flutter-Release.xcconfig b/app/macos/Flutter/Flutter-Release.xcconfig similarity index 100% rename from macos/Flutter/Flutter-Release.xcconfig rename to app/macos/Flutter/Flutter-Release.xcconfig diff --git a/app/macos/Flutter/GeneratedPluginRegistrant.swift b/app/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000..cccf817 --- /dev/null +++ b/app/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,10 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { +} diff --git a/macos/Runner.xcodeproj/project.pbxproj b/app/macos/Runner.xcodeproj/project.pbxproj similarity index 100% rename from macos/Runner.xcodeproj/project.pbxproj rename to app/macos/Runner.xcodeproj/project.pbxproj diff --git a/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme similarity index 100% rename from macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme rename to app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme diff --git a/macos/Runner.xcworkspace/contents.xcworkspacedata b/app/macos/Runner.xcworkspace/contents.xcworkspacedata similarity index 100% rename from macos/Runner.xcworkspace/contents.xcworkspacedata rename to app/macos/Runner.xcworkspace/contents.xcworkspacedata diff --git a/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/macos/Runner/AppDelegate.swift b/app/macos/Runner/AppDelegate.swift similarity index 100% rename from macos/Runner/AppDelegate.swift rename to app/macos/Runner/AppDelegate.swift diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png diff --git a/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png similarity index 100% rename from macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png rename to app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png diff --git a/macos/Runner/Base.lproj/MainMenu.xib b/app/macos/Runner/Base.lproj/MainMenu.xib similarity index 100% rename from macos/Runner/Base.lproj/MainMenu.xib rename to app/macos/Runner/Base.lproj/MainMenu.xib diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/app/macos/Runner/Configs/AppInfo.xcconfig similarity index 100% rename from macos/Runner/Configs/AppInfo.xcconfig rename to app/macos/Runner/Configs/AppInfo.xcconfig diff --git a/macos/Runner/Configs/Debug.xcconfig b/app/macos/Runner/Configs/Debug.xcconfig similarity index 100% rename from macos/Runner/Configs/Debug.xcconfig rename to app/macos/Runner/Configs/Debug.xcconfig diff --git a/macos/Runner/Configs/Release.xcconfig b/app/macos/Runner/Configs/Release.xcconfig similarity index 100% rename from macos/Runner/Configs/Release.xcconfig rename to app/macos/Runner/Configs/Release.xcconfig diff --git a/macos/Runner/Configs/Warnings.xcconfig b/app/macos/Runner/Configs/Warnings.xcconfig similarity index 100% rename from macos/Runner/Configs/Warnings.xcconfig rename to app/macos/Runner/Configs/Warnings.xcconfig diff --git a/macos/Runner/DebugProfile.entitlements b/app/macos/Runner/DebugProfile.entitlements similarity index 100% rename from macos/Runner/DebugProfile.entitlements rename to app/macos/Runner/DebugProfile.entitlements diff --git a/macos/Runner/Info.plist b/app/macos/Runner/Info.plist similarity index 100% rename from macos/Runner/Info.plist rename to app/macos/Runner/Info.plist diff --git a/macos/Runner/MainFlutterWindow.swift b/app/macos/Runner/MainFlutterWindow.swift similarity index 100% rename from macos/Runner/MainFlutterWindow.swift rename to app/macos/Runner/MainFlutterWindow.swift diff --git a/macos/Runner/Release.entitlements b/app/macos/Runner/Release.entitlements similarity index 100% rename from macos/Runner/Release.entitlements rename to app/macos/Runner/Release.entitlements diff --git a/macos/RunnerTests/RunnerTests.swift b/app/macos/RunnerTests/RunnerTests.swift similarity index 100% rename from macos/RunnerTests/RunnerTests.swift rename to app/macos/RunnerTests/RunnerTests.swift diff --git a/app/pubspec.yaml b/app/pubspec.yaml new file mode 100644 index 0000000..63a71ce --- /dev/null +++ b/app/pubspec.yaml @@ -0,0 +1,101 @@ +name: dispatch +description: "A Flutter app to simulate ambulance dispatching." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 0.1.0+1 + +resolution: workspace +environment: + sdk: ^3.8.0 + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.8 + + google_maps_flutter: ^2.12.1 + flutter_google_maps_webservices: ^1.1.1 + provider: ^6.1.5 + gap: ^3.0.1 + go_router: ^17.0.1 + latlng: ^2.0.7 + web_socket_channel: ^3.0.3 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^6.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + assets: + - assets/images/ + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/to/resolution-aware-images + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/to/asset-from-package + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have 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 + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/to/font-from-package diff --git a/test/widget_test.dart b/app/test/widget_test.dart similarity index 100% rename from test/widget_test.dart rename to app/test/widget_test.dart diff --git a/web/favicon.png b/app/web/favicon.png similarity index 100% rename from web/favicon.png rename to app/web/favicon.png diff --git a/web/icons/Icon-192.png b/app/web/icons/Icon-192.png similarity index 100% rename from web/icons/Icon-192.png rename to app/web/icons/Icon-192.png diff --git a/web/icons/Icon-512.png b/app/web/icons/Icon-512.png similarity index 100% rename from web/icons/Icon-512.png rename to app/web/icons/Icon-512.png diff --git a/web/icons/Icon-maskable-192.png b/app/web/icons/Icon-maskable-192.png similarity index 100% rename from web/icons/Icon-maskable-192.png rename to app/web/icons/Icon-maskable-192.png diff --git a/web/icons/Icon-maskable-512.png b/app/web/icons/Icon-maskable-512.png similarity index 100% rename from web/icons/Icon-maskable-512.png rename to app/web/icons/Icon-maskable-512.png diff --git a/web/index.html b/app/web/index.html similarity index 100% rename from web/index.html rename to app/web/index.html diff --git a/web/manifest.json b/app/web/manifest.json similarity index 100% rename from web/manifest.json rename to app/web/manifest.json diff --git a/windows/.gitignore b/app/windows/.gitignore similarity index 100% rename from windows/.gitignore rename to app/windows/.gitignore diff --git a/windows/CMakeLists.txt b/app/windows/CMakeLists.txt similarity index 100% rename from windows/CMakeLists.txt rename to app/windows/CMakeLists.txt diff --git a/windows/flutter/CMakeLists.txt b/app/windows/flutter/CMakeLists.txt similarity index 100% rename from windows/flutter/CMakeLists.txt rename to app/windows/flutter/CMakeLists.txt diff --git a/windows/flutter/generated_plugin_registrant.cc b/app/windows/flutter/generated_plugin_registrant.cc similarity index 100% rename from windows/flutter/generated_plugin_registrant.cc rename to app/windows/flutter/generated_plugin_registrant.cc diff --git a/windows/flutter/generated_plugin_registrant.h b/app/windows/flutter/generated_plugin_registrant.h similarity index 100% rename from windows/flutter/generated_plugin_registrant.h rename to app/windows/flutter/generated_plugin_registrant.h diff --git a/windows/flutter/generated_plugins.cmake b/app/windows/flutter/generated_plugins.cmake similarity index 100% rename from windows/flutter/generated_plugins.cmake rename to app/windows/flutter/generated_plugins.cmake diff --git a/windows/runner/CMakeLists.txt b/app/windows/runner/CMakeLists.txt similarity index 100% rename from windows/runner/CMakeLists.txt rename to app/windows/runner/CMakeLists.txt diff --git a/windows/runner/Runner.rc b/app/windows/runner/Runner.rc similarity index 100% rename from windows/runner/Runner.rc rename to app/windows/runner/Runner.rc diff --git a/windows/runner/flutter_window.cpp b/app/windows/runner/flutter_window.cpp similarity index 100% rename from windows/runner/flutter_window.cpp rename to app/windows/runner/flutter_window.cpp diff --git a/windows/runner/flutter_window.h b/app/windows/runner/flutter_window.h similarity index 100% rename from windows/runner/flutter_window.h rename to app/windows/runner/flutter_window.h diff --git a/windows/runner/main.cpp b/app/windows/runner/main.cpp similarity index 100% rename from windows/runner/main.cpp rename to app/windows/runner/main.cpp diff --git a/windows/runner/resource.h b/app/windows/runner/resource.h similarity index 100% rename from windows/runner/resource.h rename to app/windows/runner/resource.h diff --git a/windows/runner/resources/app_icon.ico b/app/windows/runner/resources/app_icon.ico similarity index 100% rename from windows/runner/resources/app_icon.ico rename to app/windows/runner/resources/app_icon.ico diff --git a/windows/runner/runner.exe.manifest b/app/windows/runner/runner.exe.manifest similarity index 100% rename from windows/runner/runner.exe.manifest rename to app/windows/runner/runner.exe.manifest diff --git a/windows/runner/utils.cpp b/app/windows/runner/utils.cpp similarity index 100% rename from windows/runner/utils.cpp rename to app/windows/runner/utils.cpp diff --git a/windows/runner/utils.h b/app/windows/runner/utils.h similarity index 100% rename from windows/runner/utils.h rename to app/windows/runner/utils.h diff --git a/windows/runner/win32_window.cpp b/app/windows/runner/win32_window.cpp similarity index 100% rename from windows/runner/win32_window.cpp rename to app/windows/runner/win32_window.cpp diff --git a/windows/runner/win32_window.h b/app/windows/runner/win32_window.h similarity index 100% rename from windows/runner/win32_window.h rename to app/windows/runner/win32_window.h diff --git a/dispatch.iml b/dispatch.iml new file mode 100644 index 0000000..05abede --- /dev/null +++ b/dispatch.iml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ios/Flutter/ephemeral/flutter_lldb_helper.py b/ios/Flutter/ephemeral/flutter_lldb_helper.py new file mode 100644 index 0000000..a88caf9 --- /dev/null +++ b/ios/Flutter/ephemeral/flutter_lldb_helper.py @@ -0,0 +1,32 @@ +# +# Generated file, do not edit. +# + +import lldb + +def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict): + """Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages.""" + base = frame.register["x0"].GetValueAsAddress() + page_len = frame.register["x1"].GetValueAsUnsigned() + + # Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the + # first page to see if handled it correctly. This makes diagnosing + # misconfiguration (e.g. missing breakpoint) easier. + data = bytearray(page_len) + data[0:8] = b'IHELPED!' + + error = lldb.SBError() + frame.GetThread().GetProcess().WriteMemory(base, data, error) + if not error.Success(): + print(f'Failed to write into {base}[+{page_len}]', error) + return + +def __lldb_init_module(debugger: lldb.SBDebugger, _): + target = debugger.GetDummyTarget() + # Caveat: must use BreakpointCreateByRegEx here and not + # BreakpointCreateByName. For some reasons callback function does not + # get carried over from dummy target for the later. + bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$") + bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__)) + bp.SetAutoContinue(True) + print("-- LLDB integration loaded --") diff --git a/ios/Flutter/ephemeral/flutter_lldbinit b/ios/Flutter/ephemeral/flutter_lldbinit new file mode 100644 index 0000000..e3ba6fb --- /dev/null +++ b/ios/Flutter/ephemeral/flutter_lldbinit @@ -0,0 +1,5 @@ +# +# Generated file, do not edit. +# + +command script import --relative-to-command-file flutter_lldb_helper.py diff --git a/lib/data/services/local_data_service.dart b/lib/data/services/local_data_service.dart deleted file mode 100644 index 137ae5a..0000000 --- a/lib/data/services/local_data_service.dart +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2024 The Flutter team. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:google_maps_flutter/google_maps_flutter.dart'; - -import '../../domain/models/event.dart'; -import '../../domain/models/noc.dart'; -import '../../domain/models/unit/unit.dart'; -import '../../domain/models/user/user.dart'; - -class LocalDataService { - List get events => _defaultEvents; - - List get units => _defaultUnits; - - User get user { - return const User( - name: 'Sofie', - esr: 12353248763, - // For demo purposes we use a local asset - picture: 'assets/user.jpg', - ); - } -} - -/// A default list of units. -final List _defaultUnits = [ - Unit( - callsign: 'NA136', - location: LatLng(51.607539604000266, -1.237806756282358), - ), - Unit( - callsign: 'NA283', - location: LatLng(51.616072911907786, -1.2536017723108663), - ), - Unit( - callsign: 'NA072', - location: LatLng(51.8296012219854, -1.3134667111590494), - ), - Unit( - callsign: 'NT431', - location: LatLng(51.397809576171085, -1.3230646597735394), - vehicleType: VehicleType.rrv, - ), - Unit( - callsign: 'NR154', - location: LatLng(51.66706110914126, -1.3082872829130447), - vehicleType: VehicleType.criticalCareCar, - ), - Unit( - callsign: 'NH58', - location: LatLng(51.61832936052779, -1.0854888181805424), - vehicleType: VehicleType.helicopter, - ), -]; - -/// A default list of events. -final List _defaultEvents = [ - Event.preAlert(id: 423124, address: 'Sainsbury\'s Kidlington'), - Event.preAlert(id: 423125, address: '47 Hamble Drive Abingdon'), - Event.withNOC( - id: 423129, - address: 'Carfax Tower, Oxford', - noc: Cat2NOC.c2Stabbing(), - ), - Event.withNOC( - id: 423126, - address: '25 Old Union Way, Thame', - noc: Cat4NOC.medicalMinor(), - ), - Event.withNOC( - id: 423127, - address: '6 The Greenway, Oxfordshire', - noc: Cat1NOC.c1ArrestPeriArrest(), - ), - Event.withNOC( - id: 423128, - address: 'Thatcham Station', - noc: Cat4NOC.mentalHealth(), - ), - Event.withNOC( - id: 423130, - address: 'Next, Westgate Shopping Centre, Oxford', - noc: Cat3NOC.fallInjuriesUnknown(), - ), -]; diff --git a/lib/domain/models/unit/unit_status.dart b/lib/domain/models/unit/unit_status.dart deleted file mode 100644 index c56a14d..0000000 --- a/lib/domain/models/unit/unit_status.dart +++ /dev/null @@ -1,24 +0,0 @@ -/// @docImport 'unit.dart'; -library; - -/// Possible statuses for a [Unit] to show its current activity. -enum UnitStatus { - ab('AB', 'Available Base'), - ra('RA', 'Returning Available'), - dp('DP', 'Dispatched'), - mo('MO', 'Mobile'), - as('AS', 'At Scene'), - wp('WP', 'With Patient'), - ls('LS', 'Left Scene'), - ah('AH', 'At Hospital'), - ho('HO', 'Handover'), - vc('VC', 'Vehicle Clear'), - os('OS', 'Out of Service'), - pd('PD', 'Pre-Duty'); - - const UnitStatus(this.abbreviation, this.name); - - final String abbreviation; - - final String name; -} diff --git a/macos/Flutter/ephemeral/Flutter-Generated.xcconfig b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig new file mode 100644 index 0000000..e4b4683 --- /dev/null +++ b/macos/Flutter/ephemeral/Flutter-Generated.xcconfig @@ -0,0 +1,11 @@ +// This is a generated file; do not edit or check into version control. +FLUTTER_ROOT=C:\Users\weasd\Documents\flutter +FLUTTER_APPLICATION_PATH=C:\Users\weasd\dev\non-OH\dispatch +COCOAPODS_PARALLEL_CODE_SIGN=true +FLUTTER_BUILD_DIR=build +FLUTTER_BUILD_NAME=1.0.0 +FLUTTER_BUILD_NUMBER=1 +DART_OBFUSCATION=false +TRACK_WIDGET_CREATION=true +TREE_SHAKE_ICONS=false +PACKAGE_CONFIG=.dart_tool/package_config.json diff --git a/macos/Flutter/ephemeral/flutter_export_environment.sh b/macos/Flutter/ephemeral/flutter_export_environment.sh new file mode 100644 index 0000000..5ff6c81 --- /dev/null +++ b/macos/Flutter/ephemeral/flutter_export_environment.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=C:\Users\weasd\Documents\flutter" +export "FLUTTER_APPLICATION_PATH=C:\Users\weasd\dev\non-OH\dispatch" +export "COCOAPODS_PARALLEL_CODE_SIGN=true" +export "FLUTTER_BUILD_DIR=build" +export "FLUTTER_BUILD_NAME=1.0.0" +export "FLUTTER_BUILD_NUMBER=1" +export "DART_OBFUSCATION=false" +export "TRACK_WIDGET_CREATION=true" +export "TREE_SHAKE_ICONS=false" +export "PACKAGE_CONFIG=.dart_tool/package_config.json" diff --git a/pubspec.yaml b/pubspec.yaml index 6527efe..80461b2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,97 +1,19 @@ -name: dispatch -description: "A new Flutter project." -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +name: dispatch_suite +description: The dispatch app and server. +version: 0.1.0 +# repository: https://github.com/weasdown/dispatch +publish_to: none -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -# In Windows, build-name is used as the major, minor, and patch parts -# of the product and file versions while build-number is used as the build suffix. -version: 1.0.0+1 +workspace: + - app + - server environment: - sdk: ^3.7.2 + sdk: ^3.8.0 -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.8 - google_maps_flutter: ^2.12.1 - flutter_google_maps_webservices: ^1.1.1 - provider: ^6.1.5 - go_router: ^15.1.1 - gap: ^3.0.1 +# Add regular dependencies here. + # path: ^1.8.0 dev_dependencies: - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^5.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - assets: - - assets/images/ - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/to/resolution-aware-images - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/to/asset-from-package - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have 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 - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/to/font-from-package + lints: ^6.0.0 + test: ^1.24.0 diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/server/CHANGELOG.md b/server/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/server/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/server/README.md b/server/README.md new file mode 100644 index 0000000..8831761 --- /dev/null +++ b/server/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/server/analysis_options.yaml b/server/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/server/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/server/example/server_example.dart b/server/example/server_example.dart new file mode 100644 index 0000000..1c1fdcd --- /dev/null +++ b/server/example/server_example.dart @@ -0,0 +1,6 @@ +import 'package:server/server.dart'; + +void main() { + WebSocketServer server = WebSocketServer.run(); + print(server); +} diff --git a/server/lib/main.dart b/server/lib/main.dart new file mode 100644 index 0000000..82e0a9d --- /dev/null +++ b/server/lib/main.dart @@ -0,0 +1,5 @@ +import 'package:server/server.dart'; + +void main() { + WebSocketServer.run(); +} diff --git a/server/lib/server.dart b/server/lib/server.dart new file mode 100644 index 0000000..fe7236c --- /dev/null +++ b/server/lib/server.dart @@ -0,0 +1,6 @@ +/// Support for doing something awesome. +/// +/// More dartdocs go here. +library; + +export 'src/web_socket_server.dart'; diff --git a/server/lib/src/web_socket_server.dart b/server/lib/src/web_socket_server.dart new file mode 100644 index 0000000..c5a760d --- /dev/null +++ b/server/lib/src/web_socket_server.dart @@ -0,0 +1,100 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:dispatch/data/services/local_data_service.dart'; +import 'package:dispatch/domain/models/event/event.dart'; +import 'package:dispatch/domain/models/unit/unit.dart'; +import 'package:dispatch/utils/result.dart'; +import 'package:shelf/shelf.dart' show Handler; +import 'package:shelf/shelf_io.dart' as shelf_io; +import 'package:shelf_web_socket/shelf_web_socket.dart'; + +/// A server that provides a WebSocket connection. +class WebSocketServer { + WebSocketServer._({String? host, int? port}) + : host = host ?? _defaultHost, + _port = port ?? _defaultPort, + _localDataService = LocalDataService() { + _events = _localDataService.events; + _units = _localDataService.units; + } + + /// Creates a server without immediately running it. + WebSocketServer.pending({String? host, int? port}) + : this._(host: host, port: port); + + /// Creates a server and immediately runs it. + factory WebSocketServer.run({String? host, int? port}) => + WebSocketServer._(host: host, port: port).._serve(); + + /// Adds an item to its respective list. + Future> add(T item) => switch (T) { + Unit _ => Future(() => Result.ok(_units.add(item as Unit))), + Event _ => Future(() => Result.ok(_events.add(item as Event))), + _ => throw TypeError(), + }; + + Handler get coreHandler => webSocketHandler((webSocket, _) { + webSocket.stream.listen((message) async { + print('Received message: $message'); + + final String key; + final List response; + + switch (message) { + case 'units': + response = _units; + key = message; + case 'events': + response = _events; + key = message; + case _: + response = message; + key = 'error'; + } + + // Send the response back to the sender. + Map messageToReply = {key: response}; + String messageJSON = json.encode(messageToReply); + webSocket.sink.add(messageJSON); + print('Replied with: $messageJSON'); + }); + }); + + static const String _defaultHost = 'localhost'; + + static const int _defaultPort = 8080; + + List _events = []; + + final String host; + + LocalDataService _localDataService; + + // @Deprecated('messageFromJSON is pending removal.') + static Map messageFromJSON(String message) { + try { + return jsonDecode(message); + } on FormatException { + throw ArgumentError('message is not a valid JSON.'); + } + } + + final int _port; + + // FIXME refactor so server is higher-level than dart:io's HttpServer. Currently crashes when run on web because HttpServer isn't supported on web. + Future _serve() async => + shelf_io.serve(coreHandler, host, _port).then((HttpServer server) { + print( + 'Serving at ws://${server.address.host}:${server.port}\n' + '\t- Current units: $_units\n' + '\t- Current events: $_events\n', + ); + return server; + }); + + List _units = []; + + /// Gets all the [Unit]s currently connected to (but not necessarily logged in to) this server. + Result> get units => Result.ok(_units); +} diff --git a/server/pubspec.yaml b/server/pubspec.yaml new file mode 100644 index 0000000..ec8ce39 --- /dev/null +++ b/server/pubspec.yaml @@ -0,0 +1,21 @@ +name: server +description: A starting point for Dart libraries or applications. +version: 1.0.0 +# repository: https://github.com/my_org/my_repo + +resolution: workspace +environment: + sdk: ^3.8.0 + +# Add regular dependencies here. +dependencies: + dispatch: ^0.1.0+1 + google_maps_flutter: ^2.12.2 + latlng: ^2.0.7 + shelf: ^1.4.2 + shelf_web_socket: ^3.0.0 + # path: ^1.8.0 + +dev_dependencies: + lints: ^6.0.0 + test: ^1.24.0 diff --git a/server/test/server_test.dart b/server/test/server_test.dart new file mode 100644 index 0000000..dc8d0f1 --- /dev/null +++ b/server/test/server_test.dart @@ -0,0 +1,15 @@ +import 'package:server/server.dart'; +import 'package:test/test.dart'; + +void main() { + group('A group of tests', () { + setUp(() { + // Additional setup goes here. + }); + + test('First Test', () { + WebSocketServer server = WebSocketServer.run(); + print(server); + }); + }); +}